blob: 57b708c515b80916a76f4485e0f24064db0e858f [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
2//
3// This file is part of GNU uCommon C++.
4//
5// GNU uCommon C++ is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published
7// by the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GNU uCommon C++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17
18#ifndef _MSC_VER
19#include <sys/stat.h>
20#endif
21
22#ifndef _XOPEN_SOURCE
23#define _XOPEN_SOURCE 600
24#endif
25
26#include <ucommon-config.h>
27
28// broken BSD; XOPEN should not imply _POSIX_C_SOURCE,
29// _POSIX_C_SOURCE should not stop __BSD_VISIBLE
30
31#define u_int unsigned int
32#define u_short unsigned short
33#define u_long unsigned long
34#define u_char unsigned char
35
36#include <ucommon/export.h>
37#include <ucommon/thread.h>
38#include <ucommon/fsys.h>
39#include <ucommon/string.h>
40#include <ucommon/memory.h>
41#include <ucommon/shell.h>
42
43#ifdef HAVE_SYSLOG_H
44#include <syslog.h>
45#endif
46
47#ifdef HAVE_LINUX_VERSION_H
48#include <linux/version.h>
49#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
50#ifdef HAVE_POSIX_FADVISE
51#undef HAVE_POSIX_FADVISE
52#endif
53#endif
54#endif
55
56#include <stdio.h>
57#include <fcntl.h>
58#include <errno.h>
59#include <string.h>
60#include <ctype.h>
61
62#ifdef HAVE_POSIX_FADVISE
63#ifndef POSIX_FADV_RANDOM
64#undef HAVE_POSIX_FADVISE
65#endif
66#endif
67
68#ifdef HAVE_DIRENT_H
69#include <dirent.h>
70#endif
71
72#ifdef _MSWINDOWS_
73#include <direct.h>
74#include <winioctl.h>
75#include <io.h>
76#endif
77
78#ifdef HAVE_SYS_INOTIFY_H
79#include <sys/inotify.h>
80#endif
81
82#ifdef HAVE_SYS_EVENT_H
83#include <sys/event.h>
84#endif
85
86using namespace UCOMMON_NAMESPACE;
87
88const fsys::offset_t fsys::end = (offset_t)(-1);
89
90#ifdef _MSWINDOWS_
91
92// removed from some sdk versions...
93struct LOCAL_REPARSE_DATA_BUFFER
94{
95 DWORD ReparseTag;
96 WORD ReparseDataLength;
97 WORD Reserved;
98
99 // IO_REPARSE_TAG_MOUNT_POINT specifics follow
100 WORD SubstituteNameOffset;
101 WORD SubstituteNameLength;
102 WORD PrintNameOffset;
103 WORD PrintNameLength;
104 WCHAR PathBuffer[1];
105};
106
107int fsys::remapError(void)
108{
109 DWORD err = GetLastError();
110
111 switch(err)
112 {
113 case ERROR_FILE_NOT_FOUND:
114 case ERROR_PATH_NOT_FOUND:
115 case ERROR_INVALID_NAME:
116 case ERROR_BAD_PATHNAME:
117 return ENOENT;
118 case ERROR_TOO_MANY_OPEN_FILES:
119 return EMFILE;
120 case ERROR_ACCESS_DENIED:
121 case ERROR_WRITE_PROTECT:
122 case ERROR_SHARING_VIOLATION:
123 case ERROR_LOCK_VIOLATION:
124 return EACCES;
125 case ERROR_INVALID_HANDLE:
126 return EBADF;
127 case ERROR_NOT_ENOUGH_MEMORY:
128 case ERROR_OUTOFMEMORY:
129 return ENOMEM;
130 case ERROR_INVALID_DRIVE:
131 case ERROR_BAD_UNIT:
132 case ERROR_BAD_DEVICE:
133 return ENODEV;
134 case ERROR_NOT_SAME_DEVICE:
135 return EXDEV;
136 case ERROR_NOT_SUPPORTED:
137 case ERROR_CALL_NOT_IMPLEMENTED:
138 return ENOSYS;
139 case ERROR_END_OF_MEDIA:
140 case ERROR_EOM_OVERFLOW:
141 case ERROR_HANDLE_DISK_FULL:
142 case ERROR_DISK_FULL:
143 return ENOSPC;
144 case ERROR_BAD_NETPATH:
145 case ERROR_BAD_NET_NAME:
146 return EACCES;
147 case ERROR_FILE_EXISTS:
148 case ERROR_ALREADY_EXISTS:
149 return EEXIST;
150 case ERROR_CANNOT_MAKE:
151 case ERROR_NOT_OWNER:
152 return EPERM;
153 case ERROR_NO_PROC_SLOTS:
154 return EAGAIN;
155 case ERROR_BROKEN_PIPE:
156 case ERROR_NO_DATA:
157 return EPIPE;
158 case ERROR_OPEN_FAILED:
159 return EIO;
160 case ERROR_NOACCESS:
161 return EFAULT;
162 case ERROR_IO_DEVICE:
163 case ERROR_CRC:
164 case ERROR_NO_SIGNAL_SENT:
165 return EIO;
166 case ERROR_CHILD_NOT_COMPLETE:
167 case ERROR_SIGNAL_PENDING:
168 case ERROR_BUSY:
169 return EBUSY;
170 case ERROR_DIR_NOT_EMPTY:
171 return ENOTEMPTY;
172 case ERROR_DIRECTORY:
173 return ENOTDIR;
174 default:
175 return EINVAL;
176 }
177}
178
179int dir::create(const char *path, unsigned perms)
180{
181 if(!CreateDirectory(path, NULL))
182 return remapError();
183
184 if(perms & 06)
185 perms |= 01;
186 if(perms & 060)
187 perms |= 010;
188 if(perms & 0600)
189 perms |= 0100;
190
191 return mode(path, perms);
192}
193
194fd_t fsys::null(void)
195{
196 SECURITY_ATTRIBUTES sattr;
197
198 sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
199 sattr.bInheritHandle = TRUE;
200 sattr.lpSecurityDescriptor = NULL;
201
202 return CreateFile("nul", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
203}
204
205int fsys::pipe(fd_t& input, fd_t& output, size_t size)
206{
207 input = output = NULL;
208 SECURITY_ATTRIBUTES sattr;
209
210 sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
211 sattr.bInheritHandle = TRUE;
212 sattr.lpSecurityDescriptor = NULL;
213
214 if(!CreatePipe(&input, &output, &sattr, size))
215 return remapError();
216
217 return 0;
218}
219
220int fsys::info(const char *path, struct stat *buf)
221{
222 if(_stat(path, (struct _stat *)(buf)))
223 return remapError();
224 return 0;
225}
226
227int fsys::trunc(offset_t offset)
228{
229 if(fsys::seek(offset) != 0)
230 return remapError();
231
232 if(SetEndOfFile(fd))
233 return 0;
234
235 return remapError();
236}
237
238int fsys::info(struct stat *buf)
239{
240 int fn = _open_osfhandle((intptr_t)(fd), O_RDONLY);
241
242 int rtn = _fstat(fn, (struct _stat *)(buf));
243 _close(fn);
244 if(rtn)
245 error = remapError();
246 return rtn;
247}
248
249int fsys::prefix(const char *path)
250{
251 if (_chdir(path))
252 return remapError();
253 return 0;
254}
255
256int fsys::prefix(char *path, size_t len)
257{
258 if (_getcwd(path, len))
259 return remapError();
260 return 0;
261}
262
263int fsys::mode(const char *path, unsigned value)
264{
265 if(_chmod(path, value))
266 return remapError();
267 return 0;
268}
269
270bool fsys::is_exists(const char *path)
271{
272 if(_access(path, F_OK))
273 return false;
274 return true;
275}
276
277bool fsys::is_readable(const char *path)
278{
279 if(_access(path, R_OK))
280 return false;
281 return true;
282}
283
284bool fsys::is_writable(const char *path)
285{
286 if(_access(path, W_OK))
287 return false;
288 return true;
289}
290
291bool fsys::is_executable(const char *path)
292{
293 path = strrchr(path, '.');
294
295 if(!path)
296 return false;
297
298 if(eq_case(path, ".exe"))
299 return true;
300
301 if(eq_case(path, ".bat"))
302 return true;
303
304 if(eq_case(path, ".com"))
305 return true;
306
307 if(eq_case(path, ".cmd"))
308 return true;
309
310 if(eq_case(path, ".ps1"))
311 return true;
312
313 return false;
314}
315
316bool fsys::is_tty(fd_t fd)
317{
318 if(fd == INVALID_HANDLE_VALUE)
319 return false;
320 DWORD type = GetFileType(fd);
321 if(type == FILE_TYPE_CHAR)
322 return true;
323 return false;
324}
325
326bool fsys::is_tty(void)
327{
328 error = 0;
329 if(fd == INVALID_HANDLE_VALUE)
330 return false;
331 DWORD type = GetFileType(fd);
332 if(!type)
333 error = remapError();
334 if(type == FILE_TYPE_CHAR)
335 return true;
336 return false;
337}
338
339void dir::close(void)
340{
341 error = 0;
342
343 if(ptr) {
344 if(::FindClose(fd)) {
345 delete ptr;
346 ptr = NULL;
347 fd = INVALID_HANDLE_VALUE;
348 }
349 else
350 error = remapError();
351 }
352 else
353 error = EBADF;
354}
355
356int fsys::close(void)
357{
358 error = 0;
359
360 if(fd == INVALID_HANDLE_VALUE)
361 return EBADF;
362
363 if(::CloseHandle(fd))
364 fd = INVALID_HANDLE_VALUE;
365 else
366 error = remapError();
367 return error;
368}
369
370ssize_t dir::read(char *buf, size_t len)
371{
372 ssize_t rtn = -1;
373 if(ptr) {
374 snprintf((char *)buf, len, ptr->cFileName);
375 rtn = strlen(ptr->cFileName);
376 if(!FindNextFile(fd, ptr))
377 close();
378 return rtn;
379 }
380 return -1;
381}
382
383ssize_t fsys::read(void *buf, size_t len)
384{
385 ssize_t rtn = -1;
386 DWORD count;
387
388 if(ReadFile(fd, (LPVOID) buf, (DWORD)len, &count, NULL))
389 rtn = count;
390 else
391 error = remapError();
392
393 return rtn;
394}
395
396ssize_t fsys::write(const void *buf, size_t len)
397{
398 ssize_t rtn = -1;
399 DWORD count;
400
401 if(WriteFile(fd, (LPVOID) buf, (DWORD)len, &count, NULL))
402 rtn = count;
403 else
404 error = remapError();
405
406 return rtn;
407}
408
409int fsys::sync(void)
410{
411 return 0;
412}
413
414fd_t fsys::input(const char *path)
415{
416 SECURITY_ATTRIBUTES sattr;
417
418 sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
419 sattr.bInheritHandle = TRUE;
420 sattr.lpSecurityDescriptor = NULL;
421
422 return CreateFile(path, GENERIC_READ, FILE_SHARE_READ, &sattr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
423}
424
425fd_t fsys::output(const char *path)
426{
427 SECURITY_ATTRIBUTES sattr;
428
429 sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
430 sattr.bInheritHandle = TRUE;
431 sattr.lpSecurityDescriptor = NULL;
432
433 return CreateFile(path, GENERIC_WRITE, 0, &sattr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
434}
435
436fd_t fsys::append(const char *path)
437{
438 SECURITY_ATTRIBUTES sattr;
439
440 sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
441 sattr.bInheritHandle = TRUE;
442 sattr.lpSecurityDescriptor = NULL;
443
444 fd_t fd = CreateFile(path, GENERIC_WRITE, 0, &sattr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
445
446 if(fd != INVALID_HANDLE_VALUE)
447 SetFilePointer(fd, 0, NULL, FILE_END);
448
449 return fd;
450}
451
452void fsys::release(fd_t fd)
453{
454 CloseHandle(fd);
455}
456
457void dir::open(const char *path)
458{
459 close();
460 error = 0;
461
462 char tpath[256];
463 DWORD attr = GetFileAttributes(path);
464
465 if((attr == (DWORD)~0l) || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
466 error = ENOTDIR;
467 return;
468 }
469
470 snprintf(tpath, sizeof(tpath), "%s%s", path, "\\*");
471 ptr = new WIN32_FIND_DATA;
472 fd = FindFirstFile(tpath, ptr);
473 if(fd == INVALID_HANDLE_VALUE) {
474 delete ptr;
475 ptr = NULL;
476 error = remapError();
477 }
478 return;
479}
480
481void fsys::open(const char *path, access_t access)
482{
483 bool append = false;
484 DWORD amode = 0;
485 DWORD smode = 0;
486 DWORD attr = FILE_ATTRIBUTE_NORMAL;
487 char buf[128];
488
489 close();
490 error = 0;
491
492 if(access == DEVICE) {
493#ifdef _MSWINDOWS_
494 if(isalpha(path[0]) && path[1] == ':') {
495 if(!QueryDosDevice(path, buf, sizeof(buf))) {
496 error = ENODEV;
497 return;
498 }
499 path = buf;
500 }
501#else
502 if(!strchr(path, '/')) {
503 if(path[0] == 'S' && isdigit(path[1]))
504 snprintf(buf, sizeof(buf) "/dev/tty%s", path);
505 else if(strncmp(path, "USB", 3))
506 snprintf(buf, sizeof(buf), "/dev/tty%s", path);
507 else
508 snprintf(buf, sizeof(buf), "/dev/%s", path);
509
510 char *cp = strchr(buf, ':');
511 if(cp)
512 *cp = 0;
513 path = buf;
514 }
515#endif
516 if(!is_device(buf)) {
517 error = ENODEV;
518 return;
519 }
520 }
521
522 switch(access)
523 {
524 case STREAM:
525#ifdef FILE_FLAG_SEQUENTIAL_SCAN
526 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
527#endif
528 case RDONLY:
529 amode = GENERIC_READ;
530 smode = FILE_SHARE_READ;
531 break;
532 case WRONLY:
533 amode = GENERIC_WRITE;
534 break;
535 case DEVICE:
536 smode = FILE_SHARE_READ;
537 attr |= FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING;
538 case EXCLUSIVE:
539 amode = GENERIC_READ | GENERIC_WRITE;
540 break;
541 case RANDOM:
542 attr |= FILE_FLAG_RANDOM_ACCESS;
543 case REWRITE:
544 amode = GENERIC_READ | GENERIC_WRITE;
545 smode = FILE_SHARE_READ;
546 break;
547 case APPEND:
548 amode = GENERIC_WRITE;
549 append = true;
550 break;
551 case SHARED:
552 amode = GENERIC_READ | GENERIC_WRITE;
553 smode = FILE_SHARE_READ | FILE_SHARE_WRITE;
554 break;
555 }
556
557 fd = CreateFile(path, amode, smode, NULL, OPEN_EXISTING, attr, NULL);
558 if(fd != INVALID_HANDLE_VALUE && append)
559 seek(end);
560 else if(fd == INVALID_HANDLE_VALUE)
561 error = remapError();
562}
563
564void fsys::open(const char *path, unsigned fmode, access_t access)
565{
566 bool append = false;
567 DWORD amode = 0;
568 DWORD cmode = 0;
569 DWORD smode = 0;
570 DWORD attr = FILE_ATTRIBUTE_NORMAL;
571
572 fmode &= 0666;
573
574 close();
575 error = 0;
576
577 const char *cp = strrchr(path, '\\');
578 const char *cp2 = strrchr(path, '/');
579 if(cp2 > cp)
580 cp = cp2;
581
582 if(!cp)
583 cp = path;
584 else
585 ++cp;
586
587 if(*cp == '.')
588 attr = FILE_ATTRIBUTE_HIDDEN;
589
590 switch(access)
591 {
592 case DEVICE:
593 error = ENOSYS;
594 return;
595
596 case RDONLY:
597 amode = GENERIC_READ;
598 cmode = OPEN_ALWAYS;
599 smode = FILE_SHARE_READ;
600 break;
601 case STREAM:
602 case WRONLY:
603 amode = GENERIC_WRITE;
604 cmode = CREATE_ALWAYS;
605 break;
606 case EXCLUSIVE:
607 amode = GENERIC_READ | GENERIC_WRITE;
608 cmode = OPEN_ALWAYS;
609 break;
610 case RANDOM:
611 attr |= FILE_FLAG_RANDOM_ACCESS;
612 case REWRITE:
613 amode = GENERIC_READ | GENERIC_WRITE;
614 cmode = OPEN_ALWAYS;
615 smode = FILE_SHARE_READ;
616 break;
617 case APPEND:
618 amode = GENERIC_WRITE;
619 cmode = OPEN_ALWAYS;
620 append = true;
621 break;
622 case SHARED:
623 amode = GENERIC_READ | GENERIC_WRITE;
624 cmode = OPEN_ALWAYS;
625 smode = FILE_SHARE_READ | FILE_SHARE_WRITE;
626 break;
627 }
628 fd = CreateFile(path, amode, smode, NULL, cmode, attr, NULL);
629 if(fd != INVALID_HANDLE_VALUE && append)
630 seek(end);
631 else if(fd == INVALID_HANDLE_VALUE)
632 error = remapError();
633 if(fd != INVALID_HANDLE_VALUE)
634 mode(path, fmode);
635}
636
637fsys::fsys(const fsys& copy)
638{
639 error = 0;
640 fd = INVALID_HANDLE_VALUE;
641
642 if(copy.fd == INVALID_HANDLE_VALUE)
643 return;
644
645 HANDLE pHandle = GetCurrentProcess();
646 if(!DuplicateHandle(pHandle, copy.fd, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
647 fd = INVALID_HANDLE_VALUE;
648 error = remapError();
649 }
650}
651
652int fsys::inherit(fd_t& from, bool enable)
653{
654 HANDLE pHandle = GetCurrentProcess();
655
656 if(!enable) {
657 if(!SetHandleInformation(from, HANDLE_FLAG_INHERIT, 0))
658 return remapError();
659 return 0;
660 }
661
662 fd_t fd;
663 if(DuplicateHandle(pHandle, from, pHandle, &fd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
664 release(from);
665 from = fd;
666 return 0;
667 }
668
669 return remapError();
670}
671
672void fsys::operator=(fd_t from)
673{
674 HANDLE pHandle = GetCurrentProcess();
675
676 if(fd != INVALID_HANDLE_VALUE) {
677 if(!CloseHandle(fd)) {
678 error = remapError();
679 return;
680 }
681 }
682 if(DuplicateHandle(pHandle, from, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS))
683 error = 0;
684 else {
685 fd = INVALID_HANDLE_VALUE;
686 error = remapError();
687 }
688}
689
690void fsys::operator=(const fsys& from)
691{
692 HANDLE pHandle = GetCurrentProcess();
693
694 if(fd != INVALID_HANDLE_VALUE) {
695 if(!CloseHandle(fd)) {
696 error = remapError();
697 return;
698 }
699 }
700 if(DuplicateHandle(pHandle, from.fd, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS))
701 error = 0;
702 else {
703 fd = INVALID_HANDLE_VALUE;
704 error = remapError();
705 }
706}
707
708int fsys::drop(offset_t size)
709{
710 error = ENOSYS;
711 return ENOSYS;
712}
713
714int fsys::seek(offset_t pos)
715{
716 DWORD rpos = pos;
717 int mode = FILE_BEGIN;
718
719 if(rpos == (DWORD)end) {
720 rpos = 0;
721 mode = FILE_END;
722 }
723 if(SetFilePointer(fd, rpos, NULL, mode) == INVALID_SET_FILE_POINTER) {
724 error = remapError();
725 return error;
726 }
727 return 0;
728}
729
730#else
731
732ssize_t dir::read(char *buf, size_t len)
733{
734 if(ptr) {
735 dirent *entry = ::readdir((DIR *)ptr);
736
737 if(!entry)
738 return 0;
739
740 String::set((char *)buf, len, entry->d_name);
741 return strlen(entry->d_name);
742 }
743 return -1;
744}
745
746ssize_t fsys::read(void *buf, size_t len)
747{
748#ifdef __PTH__
749 int rtn = ::pth_read(fd, buf, len);
750#else
751 int rtn = ::read(fd, buf, len);
752#endif
753
754 if(rtn < 0)
755 error = remapError();
756 return rtn;
757}
758
759int fsys::sync(void)
760{
761 int rtn = ::fsync(fd);
762 if(rtn < 0)
763 error = remapError();
764 else
765 return 0;
766 return error;
767}
768
769ssize_t fsys::write(const void *buf, size_t len)
770{
771#ifdef __PTH__
772 int rtn = pth_write(fd, buf, len);
773#else
774 int rtn = ::write(fd, buf, len);
775#endif
776
777 if(rtn < 0)
778 error = remapError();
779 return rtn;
780}
781
782fd_t fsys::null(void)
783{
784 return ::open("/dev/null", O_RDWR);
785}
786
787int fsys::pipe(fd_t& input, fd_t& output, size_t size)
788{
789 input = output = -1;
790 int pfd[2];
791 if(::pipe(pfd))
792 return remapError();
793 input = pfd[0];
794 output = pfd[1];
795 return 0;
796}
797
798bool fsys::is_tty(fd_t fd)
799{
800 if(isatty(fd))
801 return true;
802 return false;
803}
804
805bool fsys::is_tty(void)
806{
807 if(isatty(fd))
808 return true;
809 return false;
810}
811
812void dir::close(void)
813{
814 error = 0;
815 if(ptr) {
816 if(::closedir((DIR *)ptr))
817 error = remapError();
818 ptr = NULL;
819 }
820 else
821 error = EBADF;
822}
823
824int fsys::close(void)
825{
826 error = 0;
827 if(fd != INVALID_HANDLE_VALUE) {
828 if(::close(fd) == 0)
829 fd = INVALID_HANDLE_VALUE;
830 else
831 error = remapError();
832 }
833 else
834 return EBADF; // not opened, but state still error free
835 return error;
836}
837
838fd_t fsys::input(const char *path)
839{
840 return ::open(path, O_RDONLY);
841}
842
843fd_t fsys::output(const char *path)
844{
845 return ::open(path, O_WRONLY | O_CREAT | O_TRUNC, EVERYONE);
846}
847
848fd_t fsys::append(const char *path)
849{
850 return ::open(path, O_WRONLY | O_CREAT | O_APPEND, EVERYONE);
851}
852
853void fsys::release(fd_t fd)
854{
855 ::close(fd);
856}
857
858void fsys::open(const char *path, unsigned fmode, access_t access)
859{
860 unsigned flags = 0;
861
862 close();
863 error = 0;
864
865 switch(access)
866 {
867 case DEVICE:
868 error = ENOSYS;
869 return;
870
871 case RDONLY:
872 flags = O_RDONLY | O_CREAT;
873 break;
874 case STREAM:
875 case WRONLY:
876 flags = O_WRONLY | O_CREAT | O_TRUNC;
877 break;
878 case RANDOM:
879 case SHARED:
880 case REWRITE:
881 case EXCLUSIVE:
882 flags = O_RDWR | O_CREAT;
883 break;
884 case APPEND:
885 flags = O_RDWR | O_APPEND | O_CREAT;
886 break;
887 }
888 fd = ::open(path, flags, fmode);
889 if(fd == INVALID_HANDLE_VALUE)
890 error = remapError();
891#ifdef HAVE_POSIX_FADVISE
892 else {
893 if(access == RANDOM)
894 posix_fadvise(fd, (off_t)0, (off_t)0, POSIX_FADV_RANDOM);
895 }
896#endif
897}
898
899int dir::create(const char *path, unsigned perms)
900{
901 if(perms & 06)
902 perms |= 01;
903 if(perms & 060)
904 perms |= 010;
905 if(perms & 0600)
906 perms |= 0100;
907
908 if(::mkdir(path, perms))
909 return remapError();
910 return 0;
911}
912
913void dir::open(const char *path)
914{
915 close();
916 error = 0;
917
918 ptr = opendir(path);
919 if(!ptr)
920 error = remapError();
921}
922
923void fsys::open(const char *path, access_t access)
924{
925 unsigned flags = 0;
926
927 close();
928 error = 0;
929
930 switch(access)
931 {
932 case STREAM:
933#if defined(O_STREAMING)
934 flags = O_RDONLY | O_STREAMING;
935 break;
936#endif
937 case RDONLY:
938 flags = O_RDONLY;
939 break;
940 case WRONLY:
941 flags = O_WRONLY;
942 break;
943 case EXCLUSIVE:
944 case RANDOM:
945 case SHARED:
946 case REWRITE:
947 case DEVICE:
948 flags = O_RDWR | O_NONBLOCK;
949 break;
950 case APPEND:
951 flags = O_RDWR | O_APPEND;
952 break;
953 }
954 fd = ::open(path, flags);
955 if(fd == INVALID_HANDLE_VALUE) {
956 error = remapError();
957 return;
958 }
959#ifdef HAVE_POSIX_FADVISE
960 // Linux kernel bug prevents use of POSIX_FADV_NOREUSE in streaming...
961 if(access == STREAM)
962 posix_fadvise(fd, (off_t)0, (off_t)0, POSIX_FADV_SEQUENTIAL);
963 else if(access == RANDOM)
964 posix_fadvise(fd, (off_t)0, (off_t)0, POSIX_FADV_RANDOM);
965#endif
966 if(access == DEVICE) {
967 flags = fcntl(fd, F_GETFL);
968 flags &= ~O_NONBLOCK;
969 fcntl(fd, F_SETFL, flags);
970 }
971}
972
973int fsys::info(const char *path, struct stat *ino)
974{
975 if(::stat(path, ino))
976 return remapError();
977 return 0;
978}
979
980#ifdef HAVE_FTRUNCATE
981int fsys::trunc(offset_t offset)
982{
983 if(fsys::seek(offset) != 0)
984 return remapError();
985
986 if(::ftruncate(fd, offset) == 0)
987 return 0;
988 return remapError();
989}
990#else
991int fsys::trunc(offset_t offset)
992{
993 if(fsys::seek(offset) != 0)
994 return remapError();
995
996 return ENOSYS;
997}
998#endif
999
1000int fsys::info(struct stat *ino)
1001{
1002 if(::fstat(fd, ino)) {
1003 error = remapError();
1004 return error;
1005 }
1006 return 0;
1007}
1008
1009int fsys::prefix(const char *path)
1010{
1011 if(::chdir(path))
1012 return remapError();
1013 return 0;
1014}
1015
1016int fsys::prefix(char *path, size_t len)
1017{
1018 if(::getcwd(path, len))
1019 return remapError();
1020 return 0;
1021}
1022
1023int fsys::mode(const char *path, unsigned value)
1024{
1025 if(::chmod(path, value))
1026 return remapError();
1027 return 0;
1028}
1029
1030bool fsys::is_exists(const char *path)
1031{
1032 if(::access(path, F_OK))
1033 return false;
1034
1035 return true;
1036}
1037
1038bool fsys::is_readable(const char *path)
1039{
1040 if(::access(path, R_OK))
1041 return false;
1042
1043 return true;
1044}
1045
1046bool fsys::is_writable(const char *path)
1047{
1048 if(::access(path, W_OK))
1049 return false;
1050
1051 return true;
1052}
1053
1054bool fsys::is_executable(const char *path)
1055{
1056 if(is_dir(path))
1057 return false;
1058
1059 if(::access(path, X_OK))
1060 return false;
1061
1062 return true;
1063}
1064
1065fsys::fsys(const fsys& copy)
1066{
1067 fd = INVALID_HANDLE_VALUE;
1068 error = 0;
1069
1070 if(copy.fd != INVALID_HANDLE_VALUE) {
1071 fd = ::dup(copy.fd);
1072 }
1073 else
1074 fd = INVALID_HANDLE_VALUE;
1075}
1076
1077int fsys::inherit(fd_t& fd, bool enable)
1078{
1079 unsigned long flags;
1080 if(fd > -1) {
1081 flags = fcntl(fd, F_GETFL);
1082 if(enable)
1083 flags &= ~FD_CLOEXEC;
1084 else
1085 flags |= FD_CLOEXEC;
1086 if(fcntl(fd, F_SETFL, flags))
1087 return remapError();
1088 }
1089 return 0;
1090}
1091
1092void fsys::operator=(fd_t from)
1093{
1094 close();
1095 if(fd == INVALID_HANDLE_VALUE && from != INVALID_HANDLE_VALUE) {
1096 fd = ::dup(from);
1097 if(fd == INVALID_HANDLE_VALUE)
1098 error = remapError();
1099 }
1100}
1101
1102void fsys::operator=(const fsys& from)
1103{
1104 close();
1105 if(fd == INVALID_HANDLE_VALUE && from.fd != INVALID_HANDLE_VALUE) {
1106 fd = ::dup(from.fd);
1107 if(fd == INVALID_HANDLE_VALUE)
1108 error = remapError();
1109 }
1110}
1111
1112int fsys::drop(offset_t size)
1113{
1114#ifdef HAVE_POSIX_FADVISE
1115 if(posix_fadvise(fd, (off_t)0, size, POSIX_FADV_DONTNEED)) {
1116 error = remapError();
1117 return error;
1118 }
1119 return 0;
1120#else
1121 error = ENOSYS;
1122 return ENOSYS;
1123#endif
1124}
1125
1126int fsys::seek(offset_t pos)
1127{
1128 unsigned long rpos = pos;
1129 int mode = SEEK_SET;
1130
1131 if(rpos == (unsigned long)end) {
1132 rpos = 0;
1133 mode = SEEK_END;
1134 }
1135 if(lseek(fd, rpos, mode) == ~0l) {
1136 error = remapError();
1137 return error;
1138 }
1139 return 0;
1140}
1141
1142#endif
1143
1144dso::dso()
1145{
1146 ptr = 0;
1147 error = 0;
1148}
1149
1150dso::dso(const char *path)
1151{
1152 ptr = 0;
1153 error = 0;
1154 map(path);
1155}
1156
1157dso::~dso()
1158{
1159 release();
1160}
1161
1162dir::dir() :
1163fsys()
1164{
1165 ptr = NULL;
1166}
1167
1168dir::~dir()
1169{
1170 close();
1171}
1172
1173fsys::fsys()
1174{
1175 fd = INVALID_HANDLE_VALUE;
1176 error = 0;
1177}
1178
1179dir::dir(const char *path) :
1180fsys()
1181{
1182 ptr = NULL;
1183 open(path);
1184}
1185
1186fsys::fsys(const char *path, access_t access)
1187{
1188 fd = INVALID_HANDLE_VALUE;
1189 open(path, access);
1190}
1191
1192fsys::fsys(const char *path, unsigned fmode, access_t access)
1193{
1194 fd = INVALID_HANDLE_VALUE;
1195 open(path, fmode, access);
1196}
1197
1198fsys::~fsys()
1199{
1200 close();
1201}
1202
1203void fsys::operator*=(fd_t& from)
1204{
1205 if(fd != INVALID_HANDLE_VALUE)
1206 close();
1207 fd = from;
1208 from = INVALID_HANDLE_VALUE;
1209}
1210
1211int fsys::linkinfo(const char *path, char *buffer, size_t size)
1212{
1213#if defined(_MSWINDOWS_)
1214 HANDLE h;
1215 char reparse[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1216 DWORD rsize;
1217
1218 if(!fsys::is_link(path))
1219 return EINVAL;
1220
1221 h = CreateFile(path, GENERIC_READ, 0, 0, OPEN_EXISTING,
1222 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
1223
1224 if(!h || h == INVALID_HANDLE_VALUE)
1225 return EINVAL;
1226
1227 memset(reparse, 0, sizeof(reparse));
1228 LOCAL_REPARSE_DATA_BUFFER *rb = (LOCAL_REPARSE_DATA_BUFFER*)&reparse;
1229
1230 if(!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID *)rb, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &rsize, 0)) {
1231 CloseHandle(h);
1232 return remapError();
1233 }
1234
1235#ifdef UNICODE
1236 String::set(buffer, size, rb.PathBuffer);
1237#else
1238 WideCharToMultiByte(CP_THREAD_ACP, 0, rb->PathBuffer, rb->SubstituteNameLength / sizeof(WCHAR) + 1, buffer, size, "", FALSE);
1239#endif
1240 CloseHandle(h);
1241 return 0;
1242#elif defined(HAVE_READLINK)
1243 if(::readlink(path, buffer, size))
1244 return remapError();
1245 return 0;
1246#else
1247 return EINVAL;
1248#endif
1249}
1250
1251int fsys::hardlink(const char *path, const char *target)
1252{
1253#ifdef _MSWINDOWS_
1254 if(!CreateHardLink(target, path, NULL))
1255 return remapError();
1256 return 0;
1257#else
1258 if(::link(path, target))
1259 return remapError();
1260 return 0;
1261#endif
1262}
1263
1264int fsys::link(const char *path, const char *target)
1265{
1266#if defined(_MSWINDOWS_)
1267 TCHAR dest[512];
1268 HANDLE h;
1269 char reparse[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1270 char *part;
1271 DWORD size;
1272 WORD len;
1273
1274 lstrcpy(dest, "\\??\\");
1275 if(!GetFullPathName(path, sizeof(dest) - (4 * sizeof(TCHAR)), &dest[4], &part) || GetFileAttributes(&dest[4]) == INVALID_FILE_ATTRIBUTES)
1276 return remapError();
1277
1278 memset(reparse, 0, sizeof(reparse));
1279 LOCAL_REPARSE_DATA_BUFFER *rb = (LOCAL_REPARSE_DATA_BUFFER*)&reparse;
1280
1281 if(!MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, dest, lstrlenA(dest) + 1, rb->PathBuffer, lstrlenA(dest) + 1))
1282 return remapError();
1283
1284 len = lstrlenW(rb->PathBuffer) * 2;
1285 rb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1286 rb->ReparseDataLength = len + 12;
1287 rb->SubstituteNameLength = len;
1288 rb->PrintNameOffset = len + 2;
1289 h = CreateFile(target, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
1290 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
1291 if(!h || h == INVALID_HANDLE_VALUE)
1292 return hardlink(path, target);
1293 if(!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, (LPVOID)rb, rb->ReparseDataLength + FIELD_OFFSET(LOCAL_REPARSE_DATA_BUFFER, SubstituteNameOffset), NULL, 0, &size, 0)) {
1294 CloseHandle(h);
1295 return hardlink(path, target);
1296 }
1297 CloseHandle(h);
1298 return 0;
1299#elif defined(HAVE_SYMLINK)
1300 if(::symlink(path, target))
1301 return remapError();
1302 return 0;
1303#else
1304 if(::link(path, target))
1305 return remapError();
1306 return 0;
1307#endif
1308}
1309
1310int fsys::unlink(const char *path)
1311{
1312#ifdef _MSWINDOWS_
1313 HANDLE h = INVALID_HANDLE_VALUE;
1314 if(is_link(path))
1315 h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
1316 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
1317 if(!h || h != INVALID_HANDLE_VALUE) {
1318 REPARSE_GUID_DATA_BUFFER rb;
1319 memset(&rb, 0, sizeof(rb));
1320 DWORD size;
1321 rb.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1322 if(!DeviceIoControl(h, FSCTL_DELETE_REPARSE_POINT, &rb,
1323 REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &size, 0)) {
1324 CloseHandle(h);
1325 return remapError();
1326 }
1327 CloseHandle(h);
1328 ::remove(path);
1329 return 0;
1330 }
1331#endif
1332 if(::remove(path))
1333 return remapError();
1334 return 0;
1335}
1336
1337int fsys::erase(const char *path)
1338{
1339 if(is_device(path))
1340 return ENOSYS;
1341
1342 if(::remove(path))
1343 return remapError();
1344 return 0;
1345}
1346
1347int dir::remove(const char *path)
1348{
1349 if(is_device(path))
1350 return ENOSYS;
1351
1352#ifdef _MSWINDOWS_
1353 if(RemoveDirectory(path))
1354 return 0;
1355 int error = remapError();
1356 if(error == ENOTEMPTY)
1357 return ENOTEMPTY;
1358#else
1359 if(!::rmdir(path))
1360 return 0;
1361 if(errno != ENOTDIR)
1362 return errno;
1363#endif
1364
1365 if(::remove(path))
1366 return remapError();
1367 return 0;
1368}
1369
1370int fsys::copy(const char *oldpath, const char *newpath, size_t size)
1371{
1372 int result = 0;
1373 char *buffer = new char[size];
1374 fsys src, dest;
1375 ssize_t count = size;
1376
1377 if(!buffer) {
1378 result = ENOMEM;
1379 goto end;
1380 }
1381
1382 remove(newpath);
1383
1384 src.open(oldpath, fsys::STREAM);
1385 if(!is(src))
1386 goto end;
1387
1388 dest.open(newpath, GROUP_PUBLIC, fsys::STREAM);
1389 if(!is(dest))
1390 goto end;
1391
1392 while(count > 0) {
1393 count = src.read(buffer, size);
1394 if(count < 0) {
1395 result = src.err();
1396 goto end;
1397 }
1398 if(count > 0)
1399 count = dest.write(buffer, size);
1400 if(count < 0) {
1401 result = dest.err();
1402 goto end;
1403 }
1404 }
1405
1406end:
1407 if(is(src))
1408 src.close();
1409
1410 if(is(dest))
1411 dest.close();
1412
1413 if(buffer)
1414 delete[] buffer;
1415
1416 if(result != 0)
1417 remove(newpath);
1418
1419 return result;
1420}
1421
1422int fsys::rename(const char *oldpath, const char *newpath)
1423{
1424 if(::rename(oldpath, newpath))
1425 return remapError();
1426 return 0;
1427}
1428
1429int fsys::load(const char *path)
1430{
1431 dso module;
1432
1433 module.map(path);
1434#ifdef _MSWINDOWS_
1435 if(module.ptr) {
1436 module.ptr = 0;
1437 return 0;
1438 }
1439 return remapError();
1440#else
1441 if(module.ptr) {
1442 module.ptr = 0;
1443 return 0;
1444 }
1445 return module.error;
1446#endif
1447}
1448
1449bool fsys::is_file(const char *path)
1450{
1451#ifdef _MSWINDOWS_
1452 DWORD attr = GetFileAttributes(path);
1453 if(attr == (DWORD)~0l)
1454 return false;
1455
1456 if(attr & FILE_ATTRIBUTE_DIRECTORY)
1457 return false;
1458
1459 return true;
1460
1461#else
1462 struct stat ino;
1463
1464 if(::stat(path, &ino))
1465 return false;
1466
1467 if(S_ISREG(ino.st_mode))
1468 return true;
1469
1470 return false;
1471#endif
1472}
1473
1474bool fsys::is_link(const char *path)
1475{
1476#if defined(_MSWINDOWS_)
1477 DWORD attr = GetFileAttributes(path);
1478 if (attr == 0xffffffff || !(attr & FILE_ATTRIBUTE_REPARSE_POINT))
1479 return false;
1480 return true;
1481#elif defined(HAVE_LSTAT)
1482 struct stat ino;
1483
1484 if(::lstat(path, &ino))
1485 return false;
1486
1487 if(S_ISLNK(ino.st_mode))
1488 return true;
1489
1490 return false;
1491#else
1492 return false;
1493#endif
1494}
1495
1496bool fsys::is_dir(const char *path)
1497{
1498#ifdef _MSWINDOWS_
1499 DWORD attr = GetFileAttributes(path);
1500 if(attr == (DWORD)~0l)
1501 return false;
1502
1503 if(attr & FILE_ATTRIBUTE_DIRECTORY)
1504 return true;
1505
1506 return false;
1507
1508#else
1509 struct stat ino;
1510
1511 if(::stat(path, &ino))
1512 return false;
1513
1514 if(S_ISDIR(ino.st_mode))
1515 return true;
1516
1517 return false;
1518#endif
1519}
1520
1521#ifdef _MSWINDOWS_
1522
1523void dso::map(const char *path)
1524{
1525 error = 0;
1526 ptr = LoadLibrary(path);
1527 if(!ptr)
1528 error = ENOEXEC;
1529}
1530
1531void dso::release(void)
1532{
1533 if(ptr)
1534 FreeLibrary(ptr);
1535 ptr = 0;
1536}
1537
1538dso::addr_t dso::find(const char *sym) const
1539{
1540 if(ptr == 0)
1541 return (dso::addr_t)NULL;
1542
1543 return (addr_t)GetProcAddress(ptr, sym);
1544}
1545
1546#elif defined(HAVE_DLFCN_H)
1547#include <dlfcn.h>
1548
1549#ifndef RTLD_GLOBAL
1550#define RTLD_GLOBAL 0
1551#endif
1552
1553void dso::map(const char *path)
1554{
1555 error = 0;
1556 ptr = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
1557 if(ptr == NULL)
1558 error = ENOEXEC;
1559}
1560
1561void dso::release(void)
1562{
1563 if(ptr)
1564 dlclose(ptr);
1565 ptr = NULL;
1566}
1567
1568dso::addr_t dso::find(const char *sym) const
1569{
1570 if(!ptr)
1571 return (dso::addr_t)NULL;
1572
1573 return (dso::addr_t)dlsym(ptr, (char *)sym);
1574}
1575
1576#elif HAVE_MACH_O_DYLD_H
1577#include <mach-o/dyld.h>
1578
1579void dso::map(const char *path)
1580{
1581 NSObjectFileImage oImage;
1582 NSSymbol sym = NULL;
1583 NSModule mod;
1584 void (*init)(void);
1585
1586 ptr = NULL;
1587 error = 0;
1588
1589 if(NSCreateObjectFileImageFromFile(path, &oImage) != NSObjectFileImageSuccess) {
1590 error = ENOEXEC;
1591 return;
1592 }
1593
1594 mod = NSLinkModule(oImage, path, NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
1595 NSDestroyObjectFileImage(oImage);
1596 if(mod == NULL) {
1597 error = ENOEXEC;
1598 return;
1599 }
1600
1601 sym = NSLookupSymbolInModule(mod, "__init");
1602 if(sym) {
1603 init = (void (*)(void))NSAddressOfSymbol(sym);
1604 init();
1605 }
1606 ptr = (void *)mod;
1607}
1608
1609void dso::release(void)
1610{
1611 if(!ptr)
1612 return;
1613
1614 NSModule mod = (NSModule)ptr;
1615 NSSymbol sym;
1616 void (*fini)(void);
1617 ptr = NULL;
1618
1619 sym = NSLookupSymbolInModule(mod, "__fini");
1620 if(sym != NULL) {
1621 fini = (void (*)(void))NSAddressOfSymbol(sym);
1622 fini();
1623 }
1624 NSUnlinkModule(mod, NSUNLINKMODULE_OPTION_NONE);
1625}
1626
1627dso::addr_t dso::find(const char *sym) const
1628{
1629 if(!ptr)
1630 return NULL;
1631
1632 NSModule mod = (NSModule)ptr;
1633 NSSymbol sym;
1634
1635 sym = NSLookupSymbolInModule(mod, sym);
1636 if(sym != NULL) {
1637 return (dso::addr_t)NSAddressOfSymbol(sym);
1638
1639 return (dso::addr_t)NULL;
1640}
1641
1642#elif HAVE_SHL_LOAD
1643#include <dl.h>
1644
1645void dso::map(const char *path)
1646{
1647 error = 0;
1648 ptr = (void *)shl_load(path, BIND_IMMEDIATE, 0l);
1649 if(!ptr)
1650 error = ENOEXEC;
1651}
1652
1653dso::addr_t dso::find(const char *sym) const
1654{
1655 if(!ptr)
1656 return (dso::addr_t)NULL;
1657
1658 shl_t image = (shl_t)ptr;
1659
1660 if(shl_findsym(&image, sym, 0, &value) == 0)
1661 return (dso::addr_t)value;
1662
1663 return (dso::addr_t)NULL;
1664}
1665
1666void dso::release(void)
1667{
1668 shl_t image = (shl_t)ptr;
1669 if(ptr)
1670 shl_unload(image);
1671 ptr = NULL;
1672}
1673
1674#else
1675
1676void fsys::map(const char *path)
1677{
1678 error = ENOEXEC;
1679 ptr = NULL;
1680}
1681
1682void dso::release(void)
1683{
1684}
1685
1686dso::addr_t dso::find(const char *sym) const
1687{
1688 return (dso::addr_t)NULL;
1689}
1690
1691#endif
1692
1693bool fsys::is_device(const char *path)
1694{
1695 if(!path)
1696 return false;
1697
1698#ifndef _MSWINDOWS_
1699 if(is_dir(path))
1700 return false;
1701
1702 if(!strncmp(path, "/dev/", 5))
1703 return true;
1704
1705 return false;
1706#else
1707 if(path[1] == ':' && !path[2] && isalpha(*path))
1708 return true;
1709
1710 if(!strncmp(path, "com", 3) || !strncmp(path, "lpt", 3)) {
1711 path += 3;
1712 while(isdigit(*path))
1713 ++path;
1714 if(!path || *path == ':')
1715 return true;
1716 return false;
1717 }
1718
1719 if(!strcmp(path, "aux") || !strcmp(path, "prn")) {
1720 if(!path[3] || path[3] == ':')
1721 return true;
1722 return false;
1723 }
1724
1725 if(!strncmp(path, "\\\\.\\", 4))
1726 return true;
1727
1728 if(!strnicmp(path, "\\\\?\\Device\\", 12))
1729 return true;
1730
1731 return false;
1732
1733#endif
1734}
1735
1736bool fsys::is_hidden(const char *path)
1737{
1738#ifdef _MSWINDOWS_
1739 DWORD attr = GetFileAttributes(path);
1740 if(attr == (DWORD)~0l)
1741 return false;
1742
1743 return ((attr & FILE_ATTRIBUTE_HIDDEN) != 0);
1744#else
1745 const char *cp = strrchr(path, '/');
1746 if(cp)
1747 ++cp;
1748 else
1749 cp = path;
1750
1751 if(*cp == '.')
1752 return true;
1753
1754 return false;
1755#endif
1756}
1757
1758fsys::fsys(fd_t handle)
1759{
1760 fd = handle;
1761 error = 0;
1762}
1763
1764void fsys::set(fd_t handle)
1765{
1766 close();
1767 fd = handle;
1768 error = 0;
1769}
1770
1771fd_t fsys::release(void)
1772{
1773 fd_t save = fd;
1774
1775 fd = INVALID_HANDLE_VALUE;
1776 error = 0;
1777 return save;
1778}
1779
1780int fsys::exec(const char *path, char **argv, char **envp)
1781{
1782 shell::pid_t pid = shell::spawn(path, argv, envp);
1783 return shell::wait(pid);
1784}
1785
1786string_t fsys::prefix(void)
1787{
1788 char buf[256];
1789
1790 prefix(buf, sizeof(buf));
1791 string_t s = buf;
1792 return s;
1793}