blob: 72659d68ab604771e2b7c545ee3a94fc6198d911 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#ifndef _MSC_VER
40#include <sys/stat.h>
41#endif
42
43// needed for GNU/LINUX glibc otherwise pread/pwrite wont work
44
45#ifndef _XOPEN_SOURCE
46#define _XOPEN_SOURCE 600
47#endif
48
49/*
50 * on old glibc's, this has to be
51 * defined explicitly
52 */
53#ifndef _XOPEN_SOURCE_EXTENDED
54#define _XOPEN_SOURCE_EXTENDED
55#endif
56
57#include <ucommon-config.h>
58#include "commoncpp/missing.h"
59
60// broken BSD; XOPEN should not imply _POSIX_C_SOURCE,
61// _POSIX_C_SOURCE should not stop __BSD_VISIBLE
62
63#define u_int unsigned int
64#define u_short unsigned short
65#define u_long unsigned long
66#define u_char unsigned char
67
68#include <fcntl.h>
69
70#ifdef HAVE_SYS_PARAM_H
71#include <sys/param.h>
72#endif
73
74#ifdef HAVE_SYS_FILE_H
75#include <sys/file.h>
76#endif
77
78#ifdef HAVE_SYS_LOCKF_H
79#include <sys/lockf.h>
80#endif
81
82#include <commoncpp/config.h>
83#include <commoncpp/export.h>
84#include <commoncpp/exception.h>
85#include <commoncpp/thread.h>
86#include <commoncpp/process.h>
87#include <commoncpp/file.h>
88
89#ifdef __BORLANDC__
90#include <stdio.h>
91#include <stdlib.h>
92#else
93#include <cstdio>
94#include <cstdlib>
95#endif
96
97#include <sys/stat.h>
98#include <cerrno>
99
100#ifndef _MSWINDOWS_
101
102#ifdef COMMON_AIX_FIXES
103#undef LOCK_EX
104#undef LOCK_SH
105#endif
106
107#ifdef MACOSX
108#define MISSING_LOCKF
109#endif
110
111#ifndef F_LOCK
112#define MISSING_LOCKF
113
114enum {
115 F_ULOCK = 1,
116 F_LOCK,
117 F_TLOCK,
118 F_TEST
119};
120
121#endif
122
123#endif // ndef WIN32
124
125#if defined(_OSF_SOURCE) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 1
126#undef LOCK_EX
127#undef LOCK_SH
128#endif
129
130#if 0
131/*
132 * not used anymore ? (hen)
133 */
134static const char *clearfile(const char *pathname)
135{
136 remove(pathname);
137 return pathname;
138}
139
140static const char *clearfifo(const char *pathname, int mode)
141{
142 remove(pathname);
143 mkfifo(pathname, mode);
144 return pathname;
145}
146#endif
147
148NAMESPACE_COMMONCPP
149
150RandomFile::RandomFile(const char *name) : Mutex()
151{
152#ifdef _MSWINDOWS_
153 fd = INVALID_HANDLE_VALUE;
154 // immediate is not defined on Win32
155#else
156 fd = -1;
157 flags.immediate = false;
158#endif
159 flags.thrown = flags.initial = flags.temp = false;
160 flags.count = 0;
161 pathname = NULL;
162}
163
164RandomFile::RandomFile(const RandomFile &rf) : Mutex()
165{
166 // first, `dup'-licate the file descriptor/handle
167#ifdef _MSWINDOWS_
168 HANDLE pidHandle = GetCurrentProcess();
169 HANDLE dupHandle;
170
171 if(rf.fd != INVALID_HANDLE_VALUE) {
172 if(!DuplicateHandle(pidHandle, rf.fd, pidHandle, &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
173 fd = INVALID_HANDLE_VALUE;
174 else
175 fd = dupHandle;
176 }
177 else
178 fd = INVALID_HANDLE_VALUE;
179
180#else
181 if(rf.fd > -1)
182 fd = dup(rf.fd);
183 else
184 fd = -1;
185
186#endif
187
188 flags = rf.flags;
189 flags.count = 0;
190
191 if(rf.pathname)
192 pathname = newString(rf.pathname);
193 else
194 pathname = NULL;
195}
196
197RandomFile::~RandomFile()
198{
199 final();
200}
201
202File::Error RandomFile::restart(void)
203{
204 return errOpenFailed;
205}
206
207File::Attr RandomFile::initialize(void)
208{
209 return attrPublic;
210}
211
212void RandomFile::final(void)
213{
214#ifdef _MSWINDOWS_
215 if(fd != INVALID_HANDLE_VALUE) {
216 CloseHandle(fd);
217 if(flags.temp && pathname)
218 DeleteFile(pathname);
219 }
220
221#else
222 if(fd > -1) {
223 close(fd);
224 if(flags.temp && pathname)
225 remove(pathname);
226 }
227#endif
228
229 if(pathname) {
230 delString(pathname);
231 pathname = NULL;
232 }
233
234#ifdef _MSWINDOWS_
235 fd = INVALID_HANDLE_VALUE;
236#else
237 fd = -1;
238#endif
239 flags.count = 0;
240 flags.initial = false;
241}
242
243RandomFile::Error RandomFile::error(Error id, char *str)
244{
245 errstr = str;
246 errid = id;
247 if(!flags.thrown) {
248 flags.thrown = true;
249#ifdef CCXX_EXCEPTIONS
250 if(Thread::getException() == Thread::throwObject)
251 throw(this);
252#ifdef COMMON_STD_EXCEPTION
253 else if(Thread::getException() == Thread::throwException) {
254 if(!str)
255 str = (char *)"";
256 throw FileException(str);
257 }
258#endif
259#endif
260 }
261 return id;
262}
263
264bool RandomFile::initial(void)
265{
266 bool init;
267
268#ifdef _MSWINDOWS_
269 if(fd == INVALID_HANDLE_VALUE)
270#else
271 if(fd < 0)
272#endif
273 return false;
274
275 enterMutex();
276 init = flags.initial;
277 flags.initial = false;
278
279 if(!init) {
280 leaveMutex();
281 return false;
282 }
283
284#ifdef _MSWINDOWS_
285 Attr access = initialize();
286 if(access == attrInvalid) {
287 CloseHandle(fd);
288 if(pathname)
289 DeleteFile(pathname);
290 fd = INVALID_HANDLE_VALUE;
291 leaveMutex();
292 error(errInitFailed);
293 return false;
294 }
295
296#else
297 int mode = (int)initialize();
298 if(!mode) {
299 close(fd);
300 fd = -1;
301 if(pathname)
302 remove(pathname);
303 leaveMutex();
304 error(errInitFailed);
305 return false;
306 }
307 fchmod(fd, mode);
308#endif
309
310 leaveMutex();
311 return init;
312}
313
314#ifndef _MSWINDOWS_
315RandomFile::Error RandomFile::setCompletion(Complete mode)
316{
317 long flag = fcntl(fd, F_GETFL);
318
319 if(fd < 0)
320 return errNotOpened;
321
322 flags.immediate = false;
323#ifdef O_SYNC
324 flag &= ~(O_SYNC | O_NONBLOCK);
325#else
326 flag &= ~O_NONBLOCK;
327#endif
328 switch(mode) {
329 case completionImmediate:
330#ifdef O_SYNC
331 flag |= O_SYNC;
332#endif
333 flags.immediate = true;
334 break;
335
336 case completionDelayed:
337 flag |= O_NONBLOCK;
338
339 //completionDeferred: ? (hen)
340 case completionDeferred:
341 break;
342 }
343 fcntl(fd, F_SETFL, flag);
344 return errSuccess;
345}
346#endif
347
348off_t RandomFile::getCapacity(void)
349{
350 off_t eof, pos = 0;
351#ifdef _MSWINDOWS_
352 if(!fd)
353#else
354 if(fd < 0)
355#endif
356 return 0;
357
358 enterMutex();
359#ifdef _MSWINDOWS_
360 pos = SetFilePointer(fd, 0l, NULL, FILE_CURRENT);
361 eof = SetFilePointer(fd, 0l, NULL, FILE_END);
362 SetFilePointer(fd, pos, NULL, FILE_BEGIN);
363#else
364 lseek(fd, pos, SEEK_SET);
365 pos = lseek(fd, 0l, SEEK_CUR);
366 eof = lseek(fd, 0l, SEEK_END);
367#endif
368 leaveMutex();
369 return eof;
370}
371
372bool RandomFile::operator!(void)
373{
374#ifdef _MSWINDOWS_
375 return fd == INVALID_HANDLE_VALUE;
376#else
377 if(fd < 0)
378 return true;
379
380 return false;
381#endif
382}
383
384SharedFile::SharedFile(const char *path) :
385RandomFile(path)
386{
387 fcb.address = NULL;
388 fcb.len = 0;
389 fcb.pos = 0;
390 open(path);
391}
392
393SharedFile::SharedFile(const SharedFile &sh) :
394RandomFile(sh)
395{
396}
397
398SharedFile::~SharedFile()
399{
400 final();
401}
402
403SharedFile::Error SharedFile::open(const char *path)
404{
405#ifdef _MSWINDOWS_
406 if(fd != INVALID_HANDLE_VALUE)
407#else
408 if(fd > -1)
409#endif
410 final();
411
412 if(path != pathname) {
413 if(pathname)
414 delString(pathname);
415 pathname = newString(path);
416 }
417
418 flags.initial = false;
419
420#ifdef _MSWINDOWS_
421 fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
422 if(fd == INVALID_HANDLE_VALUE) {
423 flags.initial = true;
424 fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
425 }
426 if(fd == INVALID_HANDLE_VALUE)
427 return errOpenFailed;
428
429 return errSuccess;
430
431#else
432 fd = ::open(pathname, O_RDWR);
433 if(fd < 0) {
434 flags.initial = true;
435 fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC,
436 (int)attrPrivate);
437 }
438 if(fd < 0)
439 return error(errOpenFailed);
440
441#ifdef LOCK_SH
442 if(::flock(fd, LOCK_SH | LOCK_NB)) {
443 close(fd);
444 fd = -1;
445 return error(errOpenInUse);
446 }
447#endif
448 return errSuccess;
449#endif // WIN32
450}
451
452SharedFile::Error SharedFile::fetch(caddr_t address, ccxx_size_t len, off_t pos)
453{
454#ifdef _MSWINDOWS_
455 if(fd == INVALID_HANDLE_VALUE)
456#else
457 if(fd < 0)
458#endif
459 return errNotOpened;
460
461 enterMutex();
462 if(address)
463 fcb.address = address;
464
465 if(len)
466 fcb.len = len;
467
468 if(pos != -1)
469 fcb.pos = pos;
470
471#ifdef _MSWINDOWS_
472 OVERLAPPED over;
473 SetFilePointer(fd, fcb.pos, NULL, FILE_BEGIN);
474 over.hEvent = 0;
475 over.Offset = fcb.pos;
476 over.OffsetHigh = 0;
477 LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, fcb.len, 0, &over);
478 DWORD count;
479 if(!ReadFile(fd, fcb.address, fcb.len, &count, NULL)) {
480 leaveMutex();
481 return errReadFailure;
482 }
483 leaveMutex();
484 if(count < fcb.len)
485 return errReadIncomplete;
486
487 return errSuccess;
488
489#else
490 lseek(fd, fcb.pos, SEEK_SET);
491 if(lockf(fd, F_LOCK, fcb.len)) {
492 leaveMutex();
493 return errLockFailure;
494 }
495
496 int io = ::read(fd, fcb.address, fcb.len);
497 leaveMutex();
498
499 if((size_t) io == fcb.len)
500 return errSuccess;
501
502 if(io > -1)
503 return errReadIncomplete;
504
505 switch(errno) {
506 case EINTR:
507 return errReadInterrupted;
508 default:
509 return errReadFailure;
510 }
511#endif
512}
513
514#ifndef _MSWINDOWS_
515SharedFile::Error SharedFile::clear(ccxx_size_t len, off_t pos)
516{
517 if(fd < 0)
518 return errNotOpened;
519
520 enterMutex();
521 if(len)
522 fcb.len = len;
523
524 if(pos != -1)
525 fcb.pos = pos;
526
527 lseek(fd, fcb.pos, SEEK_SET);
528 if(lockf(fd, F_ULOCK, fcb.len)) {
529 leaveMutex();
530 return errLockFailure;
531 }
532 leaveMutex();
533 return errSuccess;
534}
535#endif // ndef WIN32
536
537SharedFile::Error SharedFile::update(caddr_t address, ccxx_size_t len, off_t pos)
538{
539#ifdef _MSWINDOWS_
540 if(fd == INVALID_HANDLE_VALUE)
541#else
542 if(fd < 0)
543#endif
544 return errNotOpened;
545
546 enterMutex();
547 if(address)
548 fcb.address = address;
549
550 if(len)
551 fcb.len = len;
552
553 if(pos != -1)
554 fcb.pos = pos;
555
556#ifdef _MSWINDOWS_
557 OVERLAPPED over;
558 SetFilePointer(fd, fcb.pos, NULL, FILE_BEGIN);
559 over.hEvent = 0;
560 over.Offset = pos;
561 over.OffsetHigh = 0;
562 DWORD count;
563 if(!WriteFile(fd, fcb.address, fcb.len, &count, NULL)) {
564 SetFilePointer(fd, fcb.pos, NULL, FILE_CURRENT);
565 UnlockFileEx(fd, 0, len, 0, &over);
566 leaveMutex();
567 return errWriteFailure;
568 }
569 SetFilePointer(fd, fcb.pos, NULL, FILE_CURRENT);
570 UnlockFileEx(fd, 0, len, 0, &over);
571 leaveMutex();
572 if(count < fcb.len)
573 return errWriteIncomplete;
574
575 return errSuccess;
576
577#else
578 lseek(fd, fcb.pos, SEEK_SET);
579 int io = ::write(fd, fcb.address, fcb.len);
580 if(lockf(fd, F_ULOCK, fcb.len)) {
581 leaveMutex();
582 return errLockFailure;
583 }
584 leaveMutex();
585
586 if((size_t) io == fcb.len)
587 return errSuccess;
588
589 if(io > -1)
590 return errWriteIncomplete;
591
592 switch(errno) {
593 case EINTR:
594 return errWriteInterrupted;
595 default:
596 return errWriteFailure;
597 }
598#endif // WIN32
599}
600
601SharedFile::Error SharedFile::append(caddr_t address, ccxx_size_t len)
602{
603#ifdef _MSWINDOWS_
604 if(fd == INVALID_HANDLE_VALUE)
605#else
606 if(fd < 0)
607#endif
608 return errNotOpened;
609
610 enterMutex();
611 if(address)
612 fcb.address = address;
613
614 if(len)
615 fcb.len = len;
616
617#ifdef _MSWINDOWS_
618 fcb.pos = SetFilePointer(fd, 0l, NULL, FILE_END);
619 OVERLAPPED over;
620 over.hEvent = 0;
621 over.Offset = fcb.pos;
622 over.OffsetHigh = 0;
623 LONG eof = fcb.pos;
624 LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 0x7fffffff, 0, &over);
625 fcb.pos = SetFilePointer(fd, 0l, NULL, FILE_END);
626 DWORD count;
627 if(!WriteFile(fd, fcb.address, fcb.len, &count, NULL)) {
628 SetFilePointer(fd, eof, NULL, FILE_CURRENT);
629 UnlockFileEx(fd, 0, 0x7fffffff, 0, &over);
630 leaveMutex();
631 return errWriteFailure;
632 }
633 SetFilePointer(fd, eof, NULL, FILE_CURRENT);
634 UnlockFileEx(fd, 0, 0x7fffffff, 0, &over);
635 leaveMutex();
636 if(count < fcb.len)
637 return errWriteIncomplete;
638
639 return errSuccess;
640
641#else
642 fcb.pos = lseek(fd, 0l, SEEK_END);
643 if(lockf(fd, F_LOCK, -1)) {
644 leaveMutex();
645 return errLockFailure;
646 }
647 fcb.pos = lseek(fd, 0l, SEEK_END);
648 int io = ::write(fd, fcb.address, fcb.len);
649 lseek(fd, fcb.pos, SEEK_SET);
650 if(lockf(fd, F_ULOCK, -1)) {
651 leaveMutex();
652 return errLockFailure;
653 }
654 leaveMutex();
655
656 if((size_t) io == fcb.len)
657 return errSuccess;
658
659 if(io > -1)
660 return errWriteIncomplete;
661
662 switch(errno) {
663 case EINTR:
664 return errWriteInterrupted;
665 default:
666 return errWriteFailure;
667 }
668#endif // WIN32
669}
670
671off_t SharedFile::getPosition(void)
672{
673 return fcb.pos;
674}
675
676bool SharedFile::operator++(void)
677{
678 off_t eof;
679
680 enterMutex();
681 fcb.pos += fcb.len;
682#ifdef _MSWINDOWS_
683 eof = SetFilePointer(fd, 0l, NULL, FILE_END);
684#else
685 eof = lseek(fd, 0l, SEEK_END);
686#endif
687
688 if(fcb.pos >= eof) {
689 fcb.pos = eof;
690 leaveMutex();
691 return true;
692 }
693 leaveMutex();
694 return false;
695}
696
697bool SharedFile::operator--(void)
698{
699 enterMutex();
700 fcb.pos -= fcb.len;
701 if(fcb.pos <= 0) {
702 fcb.pos = 0;
703 leaveMutex();
704 return true;
705 }
706 leaveMutex();
707 return false;
708}
709
710size_t MappedFile::pageAligned(size_t size)
711{
712 size_t pages = size / Process::getPageSize();
713
714 if(size % Process::getPageSize())
715 ++pages;
716
717 return pages * Process::getPageSize();
718}
719
720#ifdef _MSWINDOWS_
721
722static void makemapname(const char *source, char *target)
723{
724 unsigned count = 60;
725 while(*source && count--) {
726 if(*source == '/' || *source == '\\')
727 *(target++) = '_';
728 else
729 *(target++) = toupper(*source);
730 ++source;
731 }
732 *target = 0;
733}
734
735MappedFile::MappedFile(const char *fname, Access mode, size_t size) :
736RandomFile(fname)
737{
738 DWORD share = 0, page = 0;
739 map = INVALID_HANDLE_VALUE;
740 fcb.address = NULL;
741
742 switch(mode) {
743 case accessReadOnly:
744 share = FILE_SHARE_READ;
745 page = PAGE_READONLY;
746 prot = FILE_MAP_READ;
747 break;
748 case accessWriteOnly:
749 share = FILE_SHARE_WRITE;
750 page = PAGE_WRITECOPY;
751 prot = FILE_MAP_COPY;
752 break;
753 case accessReadWrite:
754 share = FILE_SHARE_READ|FILE_SHARE_WRITE;
755 page = PAGE_READWRITE;
756 prot = FILE_MAP_WRITE;
757 }
758 if(share || page)
759 fd = CreateFile(pathname, mode, share, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
760 else
761 fd = INVALID_HANDLE_VALUE;
762
763 if(fd == INVALID_HANDLE_VALUE) {
764 error(errOpenFailed);
765 return;
766 }
767 SetFilePointer(fd, (LONG)size, 0, FILE_BEGIN);
768 SetEndOfFile(fd);
769 makemapname(fname, mapname);
770 map = CreateFileMapping(fd, NULL, page, 0, 0, mapname);
771 if(!map)
772 error(errMapFailed);
773 fcb.address = (caddr_t)MapViewOfFile(map, prot, 0, 0, size);
774 fcb.len = (ccxx_size_t)size;
775 fcb.pos = 0;
776 if(!fcb.address)
777 error(errMapFailed);
778}
779
780MappedFile::MappedFile(const char *fname, Access mode) :
781RandomFile(fname)
782{
783 DWORD share = 0, page = 0;
784 map = INVALID_HANDLE_VALUE;
785 fcb.address = NULL;
786
787 switch(mode) {
788 case accessReadOnly:
789 share = FILE_SHARE_READ;
790 page = PAGE_READONLY;
791 prot = FILE_MAP_READ;
792 break;
793 case accessWriteOnly:
794 share = FILE_SHARE_WRITE;
795 page = PAGE_WRITECOPY;
796 prot = FILE_MAP_COPY;
797 break;
798 case accessReadWrite:
799 share = FILE_SHARE_READ|FILE_SHARE_WRITE;
800 page = PAGE_READWRITE;
801 prot = FILE_MAP_WRITE;
802 }
803 if(share || page)
804 fd = CreateFile(pathname, mode, share, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
805 else
806 fd = INVALID_HANDLE_VALUE;
807
808 if(fd == INVALID_HANDLE_VALUE) {
809 error(errOpenFailed);
810 return;
811 }
812 makemapname(fname, mapname);
813 map = CreateFileMapping(fd, NULL, page, 0, 0, mapname);
814 if(!map)
815 error(errMapFailed);
816}
817
818MappedFile::MappedFile(const char *fname, pos_t pos, size_t len, Access mode) :
819RandomFile(fname)
820{
821 DWORD share = 0, page = 0;
822 map = INVALID_HANDLE_VALUE;
823 fcb.address = NULL;
824
825 switch(mode) {
826 case accessReadOnly:
827 share = FILE_SHARE_READ;
828 page = PAGE_READONLY;
829 prot = FILE_MAP_READ;
830 break;
831 case accessWriteOnly:
832 share = FILE_SHARE_WRITE;
833 page = PAGE_WRITECOPY;
834 prot = FILE_MAP_COPY;
835 break;
836 case accessReadWrite:
837 share = FILE_SHARE_READ|FILE_SHARE_WRITE;
838 page = PAGE_READWRITE;
839 prot = FILE_MAP_WRITE;
840 }
841 if(share || page)
842 fd = CreateFile(pathname, mode, share, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
843 else
844 fd = INVALID_HANDLE_VALUE;
845
846 if(fd == INVALID_HANDLE_VALUE) {
847 error(errOpenFailed);
848 return;
849 }
850 makemapname(fname, mapname);
851 map = CreateFileMapping(fd, NULL, page, 0, 0, mapname);
852 if(!map) {
853 error(errMapFailed);
854 return;
855 }
856 fcb.address = (caddr_t)MapViewOfFile(map, prot, 0, pos, len);
857 fcb.len = (ccxx_size_t)len;
858 fcb.pos = pos;
859 if(!fcb.address)
860 error(errMapFailed);
861}
862
863MappedFile::~MappedFile()
864{
865 if(fcb.address) {
866 unlock();
867 UnmapViewOfFile(fcb.address);
868 }
869
870 if(map != INVALID_HANDLE_VALUE)
871 CloseHandle(map);
872
873 final();
874}
875
876void MappedFile::sync(void)
877{
878}
879
880void MappedFile::sync(caddr_t address, size_t len)
881{
882}
883
884void MappedFile::release(caddr_t address, size_t len)
885{
886 if(fcb.address) {
887 unlock();
888 UnmapViewOfFile(fcb.address);
889 }
890 fcb.address = NULL;
891}
892
893caddr_t MappedFile::fetch(off_t pos, size_t len)
894{
895 if(fcb.address) {
896 unlock();
897 UnmapViewOfFile(fcb.address);
898 }
899
900 fcb.address = (caddr_t)MapViewOfFile(map, prot, 0, pos, len);
901 fcb.len = (ccxx_size_t)len;
902 fcb.pos = pos;
903 if(!fcb.address)
904 error(errMapFailed);
905
906 return fcb.address;
907}
908
909void MappedFile::update(size_t offset, size_t len)
910{
911}
912
913void MappedFile::update(caddr_t address, size_t len)
914{
915}
916
917bool MappedFile::lock(void)
918{
919 unlock();
920 if(VirtualLock(fcb.address, fcb.len))
921 fcb.locked = true;
922 return fcb.locked;
923}
924
925void MappedFile::unlock(void)
926{
927 if(!fcb.address)
928 fcb.locked = false;
929
930 if(!fcb.locked)
931 return;
932
933 VirtualUnlock(fcb.address, fcb.len);
934 fcb.locked = false;
935}
936
937#else
938#ifdef HAVE_MLOCK
939MappedFile::MappedFile(const char *fname, Access mode) :
940RandomFile(fname)
941{
942 fd = open(fname, (int)mode);
943 if(fd < 0 && mode != accessReadOnly)
944 fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC,
945 (int)attrPrivate);
946
947 if(fd < 0) {
948 error(errOpenFailed);
949 return;
950 }
951
952 switch(mode) {
953 case O_RDONLY:
954 prot = PROT_READ;
955 break;
956 case O_WRONLY:
957 prot = PROT_WRITE;
958 break;
959 default:
960 prot = PROT_READ | PROT_WRITE;
961 }
962}
963
964MappedFile::MappedFile(const char *fname, Access mode, size_t size) :
965RandomFile(fname)
966{
967 fd = open(fname, (int)mode | O_CREAT, 0660);
968
969 if(fd < 0) {
970 error(errOpenFailed);
971 return;
972 }
973
974 switch(mode) {
975 case O_RDONLY:
976 prot = PROT_READ;
977 break;
978 case O_WRONLY:
979 prot = PROT_WRITE;
980 break;
981 default:
982 prot = PROT_READ | PROT_WRITE;
983 }
984
985 enterMutex();
986 lseek(fd, size, SEEK_SET);
987 fcb.address = (caddr_t)mmap(NULL, size, prot, MAP_SHARED, fd, 0);
988 fcb.len = size;
989 fcb.pos = 0;
990 leaveMutex();
991 if((caddr_t)(fcb.address) == (caddr_t)(MAP_FAILED)) {
992 close(fd);
993 fd = -1;
994 error(errMapFailed);
995 }
996}
997
998MappedFile::MappedFile(const char *fname, pos_t pos, size_t len, Access mode) :
999RandomFile(fname)
1000{
1001 fd = open(fname, (int)mode);
1002 if(fd < 0) {
1003 error(errOpenFailed);
1004 return;
1005 }
1006
1007 switch(mode) {
1008 case O_RDONLY:
1009 prot = PROT_READ;
1010 break;
1011 case O_WRONLY:
1012 prot = PROT_WRITE;
1013 break;
1014 default:
1015 prot = PROT_READ | PROT_WRITE;
1016 }
1017
1018 enterMutex();
1019 lseek(fd, pos + len, SEEK_SET);
1020 fcb.address = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, pos);
1021 fcb.len = len;
1022 fcb.pos = pos;
1023 leaveMutex();
1024 if((caddr_t)(fcb.address) == (caddr_t)(MAP_FAILED)) {
1025 close(fd);
1026 fd = -1;
1027 error(errMapFailed);
1028 }
1029}
1030
1031MappedFile::~MappedFile()
1032{
1033 unlock();
1034 final();
1035}
1036
1037void MappedFile::sync(void)
1038{
1039 msync(fcb.address, fcb.len, MS_SYNC);
1040}
1041
1042void MappedFile::release(caddr_t address, size_t len)
1043{
1044 enterMutex();
1045 if(address)
1046 fcb.address = address;
1047
1048 if(len)
1049 fcb.len = len;
1050
1051 if(fcb.locked)
1052 unlock();
1053
1054 munmap(fcb.address, fcb.len);
1055 leaveMutex();
1056}
1057
1058caddr_t MappedFile::fetch(off_t pos, size_t len)
1059{
1060 enterMutex();
1061 unlock();
1062 fcb.len = len;
1063 fcb.pos = pos;
1064 lseek(fd, fcb.pos + len, SEEK_SET);
1065 fcb.address = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, pos);
1066 leaveMutex();
1067 return fcb.address;
1068}
1069
1070bool MappedFile::lock(void)
1071{
1072 unlock();
1073 if(!mlock(fcb.address, fcb.len))
1074 fcb.locked = true;
1075 return fcb.locked;
1076}
1077
1078void MappedFile::unlock(void)
1079{
1080 if(!fcb.address)
1081 fcb.locked = false;
1082
1083 if(!fcb.locked)
1084 return;
1085
1086 munlock(fcb.address, fcb.len);
1087 fcb.locked = false;
1088}
1089
1090void MappedFile::update(size_t offset, size_t len)
1091{
1092 int mode = MS_ASYNC;
1093 caddr_t address;
1094
1095 if(flags.immediate)
1096 mode = MS_SYNC;
1097
1098 enterMutex();
1099 address = fcb.address;
1100 address += offset;
1101 if(!len)
1102 len = fcb.len;
1103 leaveMutex();
1104 msync(address, len, mode);
1105}
1106
1107void MappedFile::update(caddr_t address, size_t len)
1108{
1109 int mode = MS_ASYNC;
1110 if(flags.immediate)
1111 mode = MS_SYNC;
1112
1113 msync(address, len, mode);
1114}
1115#endif
1116#endif // ndef WIN32
1117
1118#ifdef _MSWINDOWS_
1119#ifndef SECS_BETWEEN_EPOCHS
1120#define SECS_BETWEEN_EPOCHS 11644473600LL
1121#endif
1122
1123#ifndef SECS_TO_100NS
1124#define SECS_TO_100NS 10000000LL
1125#endif
1126#endif
1127
1128time_t lastAccessed(const char *path)
1129{
1130#ifdef _MSWINDOWS_
1131 __int64 ts;
1132 WIN32_FILE_ATTRIBUTE_DATA ino;
1133
1134 if(!GetFileAttributesEx(path, GetFileExInfoStandard, &ino))
1135 return 0;
1136
1137 ts = ((__int64)ino.ftLastAccessTime.dwHighDateTime << 32) +
1138 ino.ftLastAccessTime.dwLowDateTime;
1139
1140 ts -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS);
1141 ts /= SECS_TO_100NS;
1142
1143 return(time_t)ts;
1144#else
1145 struct stat ino;
1146
1147 if(stat(path, &ino))
1148 return 0;
1149
1150 return ino.st_atime;
1151#endif
1152}
1153
1154time_t lastModified(const char *path)
1155{
1156#ifdef _MSWINDOWS_
1157 __int64 ts;
1158 WIN32_FILE_ATTRIBUTE_DATA ino;
1159
1160 if(!GetFileAttributesEx(path, GetFileExInfoStandard, &ino))
1161 return 0;
1162
1163 ts = ((__int64)ino.ftLastWriteTime.dwHighDateTime << 32) +
1164 ino.ftLastWriteTime.dwLowDateTime;
1165
1166 ts -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS);
1167 ts /= SECS_TO_100NS;
1168
1169 return(time_t)ts;
1170#else
1171 struct stat ino;
1172
1173 if(stat(path, &ino))
1174 return 0;
1175
1176 return ino.st_mtime;
1177#endif
1178}
1179
1180bool isDir(const char *path)
1181{
1182#ifdef _MSWINDOWS_
1183 DWORD attr = GetFileAttributes(path);
1184 if(attr == (DWORD)~0l)
1185 return false;
1186
1187 if(attr & FILE_ATTRIBUTE_DIRECTORY)
1188 return true;
1189
1190 return false;
1191
1192#else
1193 struct stat ino;
1194
1195 if(stat(path, &ino))
1196 return false;
1197
1198 if(S_ISDIR(ino.st_mode))
1199 return true;
1200
1201 return false;
1202#endif // WIN32
1203}
1204
1205bool isFile(const char *path)
1206{
1207#ifdef _MSWINDOWS_
1208 DWORD attr = GetFileAttributes(path);
1209 if(attr == (DWORD)~0l)
1210 return false;
1211
1212 if(attr & FILE_ATTRIBUTE_DIRECTORY)
1213 return false;
1214
1215 return true;
1216
1217#else
1218 struct stat ino;
1219
1220 if(stat(path, &ino))
1221 return false;
1222
1223 if(S_ISREG(ino.st_mode))
1224 return true;
1225
1226 return false;
1227#endif // WIN32
1228}
1229
1230#ifndef _MSWINDOWS_
1231// the Win32 version is given in line in the header
1232bool isDevice(const char *path)
1233{
1234 struct stat ino;
1235
1236 if(stat(path, &ino))
1237 return false;
1238
1239 if(S_ISCHR(ino.st_mode))
1240 return true;
1241
1242 return false;
1243}
1244#endif
1245
1246bool canAccess(const char *path)
1247{
1248#ifdef _MSWINDOWS_
1249 DWORD attr = GetFileAttributes(path);
1250 if(attr == (DWORD)~0l)
1251 return false;
1252
1253 if(attr & FILE_ATTRIBUTE_SYSTEM)
1254 return false;
1255
1256 if(attr & FILE_ATTRIBUTE_HIDDEN)
1257 return false;
1258
1259 return true;
1260
1261#else
1262 if(!access(path, R_OK))
1263 return true;
1264
1265 return false;
1266
1267#endif
1268}
1269
1270bool canModify(const char *path)
1271{
1272#ifdef _MSWINDOWS_
1273 DWORD attr = GetFileAttributes(path);
1274
1275 if(!canAccess(path))
1276 return false;
1277
1278 if(attr & FILE_ATTRIBUTE_READONLY)
1279 return false;
1280
1281 if(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NORMAL))
1282 return true;
1283
1284 return false;
1285
1286#else
1287 if(!access(path, W_OK | R_OK))
1288 return true;
1289
1290 return false;
1291#endif
1292}
1293
1294#ifdef _MSWINDOWS_
1295
1296const char *File::getExtension(const char *path)
1297{
1298 const char *cp = strrchr(path, '\\');
1299 if(!cp)
1300 cp = strrchr(path, '/');
1301 if(!cp)
1302 cp = strrchr(path, ':');
1303
1304
1305 if(cp)
1306 ++cp;
1307 else
1308 cp = path;
1309
1310 if(*cp == '.')
1311 return "";
1312
1313 cp = strrchr(cp, '.');
1314
1315 if(!cp)
1316 cp = "";
1317
1318 return cp;
1319}
1320
1321const char *File::getFilename(const char *path)
1322{
1323 const char *cp = strrchr(path, '\\');
1324 if(cp)
1325 return ++cp;
1326
1327 cp = strrchr(path, '/');
1328 if(cp)
1329 return ++cp;
1330
1331 cp = strrchr(path, ':');
1332 if(cp)
1333 ++cp;
1334
1335 return path;
1336}
1337
1338char *File::getFilename(const char *path, char *buffer, size_t size)
1339{
1340 const char *cp = strrchr(path, '\\');
1341 if(!cp)
1342 cp = strrchr(path, '/');
1343 if(!cp)
1344 cp = strrchr(path, ':');
1345
1346 if(cp)
1347 snprintf(buffer, size, "%s", ++cp);
1348 else
1349 snprintf(buffer, size, "%s", path);
1350
1351 return buffer;
1352}
1353
1354char *File::getDirname(const char *path, char *buffer, size_t size)
1355{
1356 size_t len;
1357 const char *cp = strrchr(path, '\\');
1358
1359 snprintf(buffer, size, "%s", path);
1360
1361 if(!cp)
1362 cp = strrchr(path, '/');
1363 if(!cp)
1364 cp = strrchr(path, ':');
1365
1366 if(!cp)
1367 return buffer;
1368
1369 if(cp)
1370 len = cp - path;
1371
1372 if(len >= size)
1373 len = size - 1;
1374 buffer[len] = 0;
1375 return buffer;
1376}
1377
1378#else
1379
1380const char *File::getExtension(const char *path)
1381{
1382 const char *cp = strrchr(path, '/');
1383 if(cp)
1384 ++cp;
1385 else
1386 cp = path;
1387
1388 if(*cp == '.')
1389 return "";
1390
1391 cp = strrchr(cp, '.');
1392 if(cp)
1393 return cp;
1394 return "";
1395}
1396
1397char *File::getDirname(const char *path, char *buffer, size_t size)
1398{
1399 unsigned len;
1400 const char *cp = strrchr(path, '/');
1401
1402 snprintf(buffer, size, "%s", path);
1403
1404 if(!cp)
1405 return buffer;
1406
1407 if(cp)
1408 len = cp - path;
1409
1410 if(len >= size)
1411 len = size - 1;
1412 buffer[len] = 0;
1413 return buffer;
1414}
1415
1416const char *File::getFilename(const char *path)
1417{
1418 const char *cp = strrchr(path, '/');
1419
1420 if(cp)
1421 return ++cp;
1422
1423 return path;
1424}
1425
1426char *File::getFilename(const char *path, char *buffer, size_t size)
1427{
1428 const char *cp = strrchr(path, '/');
1429
1430 if(cp)
1431 snprintf(buffer, size, "%s", ++cp);
1432 else
1433 snprintf(buffer, size, "%s", path);
1434
1435 return buffer;
1436}
1437
1438#endif
1439
1440#ifdef HAVE_REALPATH
1441
1442char *File::getRealpath(const char *path, char *buffer, size_t size)
1443{
1444 char temp[PATH_MAX];
1445 setString(buffer, size, ".");
1446 if(!realpath(path, temp))
1447 return NULL;
1448 if(strlen(temp) >= size)
1449 return NULL;
1450 setString(buffer, size, temp);
1451 return buffer;
1452}
1453
1454#else
1455
1456#ifdef _MSWINDOWS_
1457static char *getFile(char *path)
1458{
1459 char *cp = strchr(path, '\\');
1460 if(!cp)
1461 cp = strchr(path, '/');
1462 if(!cp)
1463 cp = strchr(path, ':');
1464 return cp;
1465}
1466#else
1467static char *getFile(char *path)
1468{
1469 return strchr(path, '/');
1470}
1471#endif
1472
1473char *File::getRealpath(const char *path, char *buffer, size_t size)
1474{
1475 if(size > PATH_MAX)
1476 size = PATH_MAX;
1477
1478#ifdef HAVE_LSTAT
1479 unsigned symlinks = 0;
1480#endif
1481#if !defined(DYNAMCIC_LOCAL_ARRAYS)
1482 char left[PATH_MAX];
1483#else
1484 char left[size];
1485#endif
1486 size_t left_len, buffer_len;
1487
1488#ifdef _MSWINDOWS_
1489 if(path[1] == ':')
1490#else
1491 if(path[0] == '/')
1492#endif
1493 {
1494 buffer[0] = '/';
1495 buffer[1] = 0;
1496 if(!path[1])
1497 return buffer;
1498
1499 buffer_len = 1;
1500 snprintf(left, size, "%s", path + 1);
1501 left_len = strlen(left);
1502 }
1503 else {
1504 if(!Dir::getPrefix(buffer, size)) {
1505 snprintf(buffer, size, "%s", ".");
1506 return NULL;
1507 }
1508 buffer_len = strlen(buffer);
1509 snprintf(left, size, "%s", path);
1510 left_len = strlen(left);
1511 }
1512
1513 if(left_len >= size || buffer_len >= size)
1514 return NULL;
1515
1516 while(left_len > 0) {
1517#ifdef HAVE_LSTAT
1518 struct stat ino;
1519#endif
1520#if !defined(DYNAMIC_LOCAL_ARRAYS)
1521 char next_token[PATH_MAX];
1522#else
1523 char next_token[size];
1524#endif
1525 char *p;
1526 const char *s = (p = getFile(left)) ? p : left + left_len;
1527
1528 memmove(next_token, left, s - left);
1529 left_len -= s - left;
1530 if(p != NULL)
1531 memmove(left, s + 1, left_len + 1);
1532
1533 next_token[s - left] = 0;
1534 if(buffer[buffer_len - 1] != '/') {
1535 if(buffer_len +1 >= size)
1536 return NULL;
1537
1538 buffer[buffer_len++] = '/';
1539 buffer[buffer_len] = 0;
1540 }
1541 if(!next_token[0])
1542 continue;
1543 else if(!strcmp(next_token, "."))
1544 continue;
1545 else if(!strcmp(next_token, "..")) {
1546 if(buffer_len > 1) {
1547 char *q;
1548 buffer[buffer_len - 1] = 0;
1549#ifdef _MSWINDOWS_
1550 q = strrchr(buffer, '\\');
1551 if(!q)
1552 q = strrchr(buffer, '/');
1553 if(!q)
1554 q = strchr(buffer, ':');
1555#else
1556 q = strrchr(buffer, '/');
1557#endif
1558 *q = 0;
1559 buffer_len = q - buffer;
1560 }
1561 continue;
1562 }
1563 snprintf(next_token, size, "%s", buffer);
1564 buffer_len = strlen(buffer);
1565 if(buffer_len >= size)
1566 return NULL;
1567
1568#ifndef HAVE_LSTAT
1569 if(!isFile(buffer) && !isDir(buffer))
1570 return buffer;
1571
1572 continue;
1573#else
1574 if(lstat(buffer, &ino) < 0) {
1575 if(errno == ENOENT && !p)
1576 return buffer;
1577
1578 return NULL;
1579 }
1580
1581 if((ino.st_mode & S_IFLNK) == S_IFLNK) {
1582 char symlink[size];
1583 int slen;
1584
1585 if (symlinks++ > MAXSYMLINKS)
1586 return NULL;
1587
1588 slen = readlink(buffer, symlink, size);
1589
1590 if (slen < 0)
1591 return NULL;
1592 symlink[slen] = 0;
1593
1594 if (symlink[0] == '/') {
1595 buffer[1] = 0;
1596 buffer_len = 1;
1597 } else if (buffer_len > 1) {
1598 char *q;
1599
1600 buffer[buffer_len - 1] = 0;
1601 q = strrchr(buffer, '/');
1602 *q = 0;
1603 buffer_len = q - buffer;
1604 }
1605 if (symlink[slen - 1] != '/' && p) {
1606 if (slen >= size)
1607 return NULL;
1608
1609 symlink[slen] = '/';
1610 symlink[slen + 1] = 0;
1611 }
1612 if(p) {
1613 snprintf(symlink, size, "%s", left);
1614 left_len = strlen(symlink);
1615 }
1616 if(left_len >= size)
1617 return NULL;
1618 snprintf(left, size, "%s", symlink);
1619 left_len = strlen(left);
1620 }
1621#endif
1622
1623 }
1624
1625#ifdef _MSWINDOWS_
1626 if(buffer_len > 1 && buffer[buffer_len - 1] == '\\')
1627 buffer[buffer_len - 1] = 0;
1628 else if(buffer_len > 1 && buffer[buffer_len - 1] == '/')
1629 buffer[buffer_len - 1] = 0;
1630#else
1631 if(buffer_len > 1 && buffer[buffer_len - 1] == '/')
1632 buffer[buffer_len - 1] = 0;
1633#endif
1634 return buffer;
1635}
1636
1637#endif
1638
1639END_NAMESPACE