diff options
Diffstat (limited to 'winsup/cygwin/syscalls.cc')
-rw-r--r-- | winsup/cygwin/syscalls.cc | 2014 |
1 files changed, 1051 insertions, 963 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index d53bf347b..fe3a88da3 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1163,31 +1163,31 @@ getsid (pid_t pid) extern "C" ssize_t read (int fd, void *ptr, size_t len) { - pthread_testcancel (); - - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - size_t res = (size_t) -1; - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; + pthread_testcancel (); - if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) + __try { - set_errno (EBADF); - goto done; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; - /* Could block, so let user know we at least got here. */ - syscall_printf ("read(%d, %p, %d) %sblocking", - fd, ptr, len, cfd->is_nonblocking () ? "non" : ""); + if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) + { + set_errno (EBADF); + __leave; + } - cfd->read (ptr, res = len); + /* Could block, so let user know we at least got here. */ + syscall_printf ("read(%d, %p, %d) %sblocking", + fd, ptr, len, cfd->is_nonblocking () ? "non" : ""); -done: + cfd->read (ptr, len); + res = len; + } + __except (EFAULT) {} + __endtry syscall_printf ("%lR = read(%d, %p, %d)", res, fd, ptr, len); MALLOC_CHECK; return (ssize_t) res; @@ -1198,38 +1198,38 @@ EXPORT_ALIAS (read, _read) extern "C" ssize_t readv (int fd, const struct iovec *const iov, const int iovcnt) { - pthread_testcancel (); - - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - ssize_t res = -1; - const ssize_t tot = check_iovec_for_read (iov, iovcnt); - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; + pthread_testcancel (); - if (tot <= 0) + __try { - res = tot; - goto done; - } + const ssize_t tot = check_iovec_for_read (iov, iovcnt); - if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) - { - set_errno (EBADF); - goto done; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; - /* Could block, so let user know we at least got here. */ - syscall_printf ("readv(%d, %p, %d) %sblocking", - fd, iov, iovcnt, cfd->is_nonblocking () ? "non" : ""); + if (tot <= 0) + { + res = tot; + __leave; + } + + if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) + { + set_errno (EBADF); + __leave; + } - res = cfd->readv (iov, iovcnt, tot); + /* Could block, so let user know we at least got here. */ + syscall_printf ("readv(%d, %p, %d) %sblocking", + fd, iov, iovcnt, cfd->is_nonblocking () ? "non" : ""); -done: + res = cfd->readv (iov, iovcnt, tot); + } + __except (EFAULT) {} + __endtry syscall_printf ("%lR = readv(%d, %p, %d)", res, fd, iov, iovcnt); MALLOC_CHECK; return res; @@ -1238,9 +1238,10 @@ done: extern "C" ssize_t pread (int fd, void *ptr, size_t len, off_t off) { + ssize_t res; + pthread_testcancel (); - ssize_t res; cygheap_fdget cfd (fd); if (cfd < 0) res = -1; @@ -1254,35 +1255,33 @@ pread (int fd, void *ptr, size_t len, off_t off) extern "C" ssize_t write (int fd, const void *ptr, size_t len) { - pthread_testcancel (); - - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - ssize_t res = -1; - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; + pthread_testcancel (); - if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) + __try { - set_errno (EBADF); - goto done; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; - /* Could block, so let user know we at least got here. */ - if (fd == 1 || fd == 2) - paranoid_printf ("write(%d, %p, %d)", fd, ptr, len); - else - syscall_printf ("write(%d, %p, %d)", fd, ptr, len); + if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) + { + set_errno (EBADF); + __leave; + } - res = cfd->write (ptr, len); + /* Could block, so let user know we at least got here. */ + if (fd == 1 || fd == 2) + paranoid_printf ("write(%d, %p, %d)", fd, ptr, len); + else + syscall_printf ("write(%d, %p, %d)", fd, ptr, len); -done: + res = cfd->write (ptr, len); + } + __except (EFAULT) {} + __endtry syscall_printf ("%lR = write(%d, %p, %d)", res, fd, ptr, len); - MALLOC_CHECK; return res; } @@ -1292,45 +1291,44 @@ EXPORT_ALIAS (write, _write) extern "C" ssize_t writev (const int fd, const struct iovec *const iov, const int iovcnt) { - pthread_testcancel (); - - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - ssize_t res = -1; - const ssize_t tot = check_iovec_for_write (iov, iovcnt); - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; + pthread_testcancel (); - if (tot <= 0) + __try { - res = tot; - goto done; - } + const ssize_t tot = check_iovec_for_write (iov, iovcnt); - if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) - { - set_errno (EBADF); - goto done; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; - /* Could block, so let user know we at least got here. */ - if (fd == 1 || fd == 2) - paranoid_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); - else - syscall_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); + if (tot <= 0) + { + res = tot; + __leave; + } - res = cfd->writev (iov, iovcnt, tot); + if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) + { + set_errno (EBADF); + __leave; + } -done: + /* Could block, so let user know we at least got here. */ + if (fd == 1 || fd == 2) + paranoid_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); + else + syscall_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); + + res = cfd->writev (iov, iovcnt, tot); + } + __except (EFAULT) {} + __endtry if (fd == 1 || fd == 2) paranoid_printf ("%lR = writev(%d, %p, %d)", res, fd, iov, iovcnt); else syscall_printf ("%lR = writev(%d, %p, %d)", res, fd, iov, iovcnt); - MALLOC_CHECK; return res; } @@ -1361,75 +1359,76 @@ open (const char *unix_path, int flags, ...) va_list ap; mode_t mode = 0; - syscall_printf ("open(%s, %y)", unix_path, flags); pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - /* errno already set */; - else if (!*unix_path) - set_errno (ENOENT); - else + + __try { - /* check for optional mode argument */ - va_start (ap, flags); - mode = va_arg (ap, mode_t); - va_end (ap); + syscall_printf ("open(%s, %y)", unix_path, flags); + if (!*unix_path) + set_errno (ENOENT); + else + { + /* check for optional mode argument */ + va_start (ap, flags); + mode = va_arg (ap, mode_t); + va_end (ap); - fhandler_base *fh; - cygheap_fdnew fd; + fhandler_base *fh; + cygheap_fdnew fd; - if (fd >= 0) - { - /* This is a temporary kludge until all utilities can catch up with - a change in behavior that implements linux functionality: opening - a tty should not automatically cause it to become the controlling - tty for the process. */ - int opt = PC_OPEN | ((flags & (O_NOFOLLOW | O_EXCL)) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW); - if (!(flags & O_NOCTTY) && fd > 2 && myself->ctty != -2) - { - flags |= O_NOCTTY; - opt |= PC_CTTY; /* flag that, if opened, this fhandler could - later be capable of being a controlling - terminal if /dev/tty is opened. */ - } - if (!(fh = build_fh_name (unix_path, opt, stat_suffixes))) - res = -1; // errno already set - else if ((flags & O_NOFOLLOW) && fh->issymlink ()) - { - delete fh; - res = -1; - set_errno (ELOOP); - } - else if ((flags & O_DIRECTORY) && fh->exists () && !fh->pc.isdir ()) + if (fd >= 0) { - delete fh; - res = -1; - set_errno (ENOTDIR); - } - else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) && fh->exists ()) - { - delete fh; - res = -1; - set_errno (EEXIST); - } - else if ((fh->is_fs_special () && fh->device_access_denied (flags)) - || !fh->open_with_arch (flags, (mode & 07777) & ~cygheap->umask)) - { - delete fh; - res = -1; - } - else - { - fd = fh; - if (fd <= 2) - set_std_handle (fd); - res = fd; + /* This is a temporary kludge until all utilities can catch up + with a change in behavior that implements linux functionality: + opening a tty should not automatically cause it to become the + controlling tty for the process. */ + int opt = PC_OPEN | ((flags & (O_NOFOLLOW | O_EXCL)) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW); + if (!(flags & O_NOCTTY) && fd > 2 && myself->ctty != -2) + { + flags |= O_NOCTTY; + /* flag that, if opened, this fhandler could later be capable + of being a controlling terminal if /dev/tty is opened. */ + opt |= PC_CTTY; + } + if (!(fh = build_fh_name (unix_path, opt, stat_suffixes))) + ; // errno already set + else if ((flags & O_NOFOLLOW) && fh->issymlink ()) + { + delete fh; + set_errno (ELOOP); + } + else if ((flags & O_DIRECTORY) && fh->exists () + && !fh->pc.isdir ()) + { + delete fh; + set_errno (ENOTDIR); + } + else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + && fh->exists ()) + { + delete fh; + set_errno (EEXIST); + } + else if ((fh->is_fs_special () + && fh->device_access_denied (flags)) + || !fh->open_with_arch (flags, (mode & 07777) + & ~cygheap->umask)) + delete fh; + else + { + fd = fh; + if (fd <= 2) + set_std_handle (fd); + res = fd; + } } } - } - syscall_printf ("%R = open(%s, %y)", res, unix_path, flags); + syscall_printf ("%R = open(%s, %y)", res, unix_path, flags); + } + __except (EFAULT) {} + __endtry return res; } @@ -1893,34 +1892,33 @@ stat_worker (path_conv &pc, struct stat *buf) { int res = -1; - myfault efault; - if (efault.faulted (EFAULT)) - goto error; - - if (pc.error) - { - debug_printf ("got %d error from path_conv", pc.error); - set_errno (pc.error); - } - else if (pc.exists ()) + __try { - fhandler_base *fh; + if (pc.error) + { + debug_printf ("got %d error from path_conv", pc.error); + set_errno (pc.error); + } + else if (pc.exists ()) + { + fhandler_base *fh; - if (!(fh = build_fh_pc (pc))) - goto error; + if (!(fh = build_fh_pc (pc))) + __leave; - debug_printf ("(%S, %p, %p), file_attributes %d", - pc.get_nt_native_path (), buf, fh, (DWORD) *fh); - memset (buf, 0, sizeof (*buf)); - res = fh->fstat (buf); - if (!res) - fh->stat_fixup (buf); - delete fh; + debug_printf ("(%S, %p, %p), file_attributes %d", + pc.get_nt_native_path (), buf, fh, (DWORD) *fh); + memset (buf, 0, sizeof (*buf)); + res = fh->fstat (buf); + if (!res) + fh->stat_fixup (buf); + delete fh; + } + else + set_errno (ENOENT); } - else - set_errno (ENOENT); - - error: + __except (EFAULT) {} + __endtry MALLOC_CHECK; syscall_printf ("%d = (%S,%p)", res, pc.get_nt_native_path (), buf); return res; @@ -2112,497 +2110,511 @@ rename (const char *oldpath, const char *newpath) FILE_STANDARD_INFORMATION ofsi; PFILE_RENAME_INFORMATION pfri; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (!*oldpath || !*newpath) + __try { - /* Reject rename("","x"), rename("x",""). */ - set_errno (ENOENT); - goto out; - } - if (has_dot_last_component (oldpath, true)) - { - /* Reject rename("dir/.","x"). */ - oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); - set_errno (oldpc.isdir () ? EINVAL : ENOTDIR); - goto out; - } - if (has_dot_last_component (newpath, true)) - { - /* Reject rename("dir","x/."). */ - newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); - set_errno (!newpc.exists () ? ENOENT : newpc.isdir () ? EINVAL : ENOTDIR); - goto out; - } - - /* A trailing slash requires that the pathname points to an existing - directory. If it's not, it's a ENOTDIR condition. The same goes - for newpath a bit further down this function. */ - olen = strlen (oldpath); - if (isdirsep (oldpath[olen - 1])) - { - char *buf; - char *p = stpcpy (buf = tp.c_get (), oldpath) - 1; - oldpath = buf; - while (p >= oldpath && isdirsep (*p)) - *p-- = '\0'; - olen = p + 1 - oldpath; - if (!olen) + if (!*oldpath || !*newpath) { - /* The root directory cannot be renamed. This also rejects - the corner case of rename("/","/"), even though it is the - same file. */ - set_errno (EINVAL); - goto out; + /* Reject rename("","x"), rename("x",""). */ + set_errno (ENOENT); + __leave; } - old_dir_requested = true; - } - oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); - if (oldpc.error) - { - set_errno (oldpc.error); - goto out; - } - if (!oldpc.exists ()) - { - set_errno (ENOENT); - goto out; - } - if (oldpc.isspecial () && !oldpc.issocket () && !oldpc.is_fs_special ()) - { - /* No renames from virtual FS */ - set_errno (EROFS); - goto out; - } - if (oldpc.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT) && !oldpc.issymlink ()) - { - /* Volume mount point. If we try to rename a volume mount point, NT - returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==> - errno EXDEV. That's bad since mv(1) will now perform a cross-device - move. So what we do here is to treat the volume mount point just - like Linux treats a mount point. */ - set_errno (EBUSY); - goto out; - } - if (old_dir_requested && !oldpc.isdir ()) - { - /* Reject rename("file/","x"). */ - set_errno (ENOTDIR); - goto out; - } - if (oldpc.known_suffix - && (ascii_strcasematch (oldpath + olen - 4, ".lnk") - || ascii_strcasematch (oldpath + olen - 4, ".exe"))) - old_explicit_suffix = true; - - nlen = strlen (newpath); - if (isdirsep (newpath[nlen - 1])) - { - char *buf; - char *p = stpcpy (buf = tp.c_get (), newpath) - 1; - newpath = buf; - while (p >= newpath && isdirsep (*p)) - *p-- = '\0'; - nlen = p + 1 - newpath; - if (!nlen) /* The root directory is never empty. */ + if (has_dot_last_component (oldpath, true)) { - set_errno (ENOTEMPTY); - goto out; + /* Reject rename("dir/.","x"). */ + oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + set_errno (oldpc.isdir () ? EINVAL : ENOTDIR); + __leave; } - new_dir_requested = true; - } - newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); - if (newpc.error) - { - set_errno (newpc.error); - goto out; - } - if (newpc.isspecial () && !newpc.issocket ()) /* No renames to virtual FSes */ - { - set_errno (EROFS); - goto out; - } - if (new_dir_requested && !(newpc.exists () - ? newpc.isdir () : oldpc.isdir ())) - { - /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */ - set_errno (newpc.exists () ? ENOTDIR : ENOENT); - goto out; - } - if (newpc.exists () && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ())) - { - /* Reject rename("file","dir") and rename("dir","file"). */ - set_errno (newpc.isdir () ? EISDIR : ENOTDIR); - goto out; - } - if (newpc.known_suffix - && (ascii_strcasematch (newpath + nlen - 4, ".lnk") - || ascii_strcasematch (newpath + nlen - 4, ".exe"))) - new_explicit_suffix = true; - - /* This test is necessary in almost every case, so just do it once here. */ - equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - oldpc.objcaseinsensitive ()); - - /* First check if oldpath and newpath only differ by case. If so, it's - just a request to change the case of the filename. By simply setting - the file attributes to INVALID_FILE_ATTRIBUTES (which translates to - "file doesn't exist"), all later tests are skipped. */ - if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path - && old_explicit_suffix == new_explicit_suffix) - { - if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - FALSE)) + if (has_dot_last_component (newpath, true)) { - res = 0; - goto out; + /* Reject rename("dir","x/."). */ + newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); + set_errno (!newpc.exists () ? ENOENT + : newpc.isdir () ? EINVAL : ENOTDIR); + __leave; } - newpc.file_attributes (INVALID_FILE_ATTRIBUTES); - } - else if (oldpc.isdir ()) - { - /* Check for newpath being identical or a subdir of oldpath. */ - if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - TRUE)) + + /* A trailing slash requires that the pathname points to an existing + directory. If it's not, it's a ENOTDIR condition. The same goes + for newpath a bit further down this function. */ + olen = strlen (oldpath); + if (isdirsep (oldpath[olen - 1])) { - if (newpc.get_nt_native_path ()->Length - == oldpc.get_nt_native_path ()->Length) - { - res = 0; - goto out; - } - if (*(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer - + oldpc.get_nt_native_path ()->Length) == L'\\') + char *buf; + char *p = stpcpy (buf = tp.c_get (), oldpath) - 1; + oldpath = buf; + while (p >= oldpath && isdirsep (*p)) + *p-- = '\0'; + olen = p + 1 - oldpath; + if (!olen) { + /* The root directory cannot be renamed. This also rejects + the corner case of rename("/","/"), even though it is the + same file. */ set_errno (EINVAL); - goto out; + __leave; } + old_dir_requested = true; } - } - else if (!newpc.exists ()) - { - if (equal_path && old_explicit_suffix != new_explicit_suffix) + oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (oldpc.error) { - newpc.check (newpath, PC_SYM_NOFOLLOW); - if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - oldpc.objcaseinsensitive ())) + set_errno (oldpc.error); + __leave; + } + if (!oldpc.exists ()) + { + set_errno (ENOENT); + __leave; + } + if (oldpc.isspecial () && !oldpc.issocket () && !oldpc.is_fs_special ()) + { + /* No renames from virtual FS */ + set_errno (EROFS); + __leave; + } + if (oldpc.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT) + && !oldpc.issymlink ()) + { + /* Volume mount point. If we try to rename a volume mount point, NT + returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==> + errno EXDEV. That's bad since mv(1) will now perform a + cross-device move. So what we do here is to treat the volume + mount point just like Linux treats a mount point. */ + set_errno (EBUSY); + __leave; + } + if (old_dir_requested && !oldpc.isdir ()) + { + /* Reject rename("file/","x"). */ + set_errno (ENOTDIR); + __leave; + } + if (oldpc.known_suffix + && (ascii_strcasematch (oldpath + olen - 4, ".lnk") + || ascii_strcasematch (oldpath + olen - 4, ".exe"))) + old_explicit_suffix = true; + + nlen = strlen (newpath); + if (isdirsep (newpath[nlen - 1])) + { + char *buf; + char *p = stpcpy (buf = tp.c_get (), newpath) - 1; + newpath = buf; + while (p >= newpath && isdirsep (*p)) + *p-- = '\0'; + nlen = p + 1 - newpath; + if (!nlen) /* The root directory is never empty. */ { - res = 0; - goto out; + set_errno (ENOTEMPTY); + __leave; } + new_dir_requested = true; } - else if (oldpc.is_lnk_special () - && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), - &ro_u_lnk, TRUE)) - rename_append_suffix (newpc, newpath, nlen, ".lnk"); - else if (oldpc.is_binary () && !old_explicit_suffix - && oldpc.known_suffix - && !nt_path_has_executable_suffix (newpc.get_nt_native_path ())) - /* Never append .exe suffix if oldpath had .exe suffix given - explicitely, or if oldpath wasn't already a .exe file, or - if the destination filename has one of the blessed executable - suffixes. - Note: To rename an executable foo.exe to bar-without-suffix, - the .exe suffix must be given explicitly in oldpath. */ - rename_append_suffix (newpc, newpath, nlen, ".exe"); - } - else - { - if (equal_path && old_explicit_suffix != new_explicit_suffix) + newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (newpc.error) + { + set_errno (newpc.error); + __leave; + } + if (newpc.isspecial () && !newpc.issocket ()) + { + /* No renames to virtual FSes */ + set_errno (EROFS); + __leave; + } + if (new_dir_requested && !(newpc.exists () + ? newpc.isdir () : oldpc.isdir ())) + { + /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */ + set_errno (newpc.exists () ? ENOTDIR : ENOENT); + __leave; + } + if (newpc.exists () + && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ())) + { + /* Reject rename("file","dir") and rename("dir","file"). */ + set_errno (newpc.isdir () ? EISDIR : ENOTDIR); + __leave; + } + if (newpc.known_suffix + && (ascii_strcasematch (newpath + nlen - 4, ".lnk") + || ascii_strcasematch (newpath + nlen - 4, ".exe"))) + new_explicit_suffix = true; + + /* This test is necessary in almost every case, so do it once here. */ + equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + oldpc.objcaseinsensitive ()); + + /* First check if oldpath and newpath only differ by case. If so, it's + just a request to change the case of the filename. By simply setting + the file attributes to INVALID_FILE_ATTRIBUTES (which translates to + "file doesn't exist"), all later tests are skipped. */ + if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path + && old_explicit_suffix == new_explicit_suffix) { - newpc.check (newpath, PC_SYM_NOFOLLOW); if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), newpc.get_nt_native_path (), - oldpc.objcaseinsensitive ())) + FALSE)) { res = 0; - goto out; + __leave; } + newpc.file_attributes (INVALID_FILE_ATTRIBUTES); } - else if (oldpc.is_lnk_special ()) + else if (oldpc.isdir ()) { - if (!newpc.is_lnk_special () - && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), - &ro_u_lnk, TRUE)) + /* Check for newpath being identical or a subdir of oldpath. */ + if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + TRUE)) { - rename_append_suffix (new2pc, newpath, nlen, ".lnk"); - removepc = &newpc; + if (newpc.get_nt_native_path ()->Length + == oldpc.get_nt_native_path ()->Length) + { + res = 0; + __leave; + } + if (*(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer + + oldpc.get_nt_native_path ()->Length) == L'\\') + { + set_errno (EINVAL); + __leave; + } } } - else if (oldpc.is_binary ()) + else if (!newpc.exists ()) { - /* Never append .exe suffix if oldpath had .exe suffix given - explicitely, or if newfile is a binary (in which case the given - name probably makes sense as it is), or if the destination - filename has one of the blessed executable suffixes. */ - if (!old_explicit_suffix && oldpc.known_suffix - && !newpc.is_binary () - && !nt_path_has_executable_suffix (newpc.get_nt_native_path ())) + if (equal_path && old_explicit_suffix != new_explicit_suffix) { - rename_append_suffix (new2pc, newpath, nlen, ".exe"); - removepc = &newpc; + newpc.check (newpath, PC_SYM_NOFOLLOW); + if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + oldpc.objcaseinsensitive ())) + { + res = 0; + __leave; + } } + else if (oldpc.is_lnk_special () + && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), + &ro_u_lnk, TRUE)) + rename_append_suffix (newpc, newpath, nlen, ".lnk"); + else if (oldpc.is_binary () && !old_explicit_suffix + && oldpc.known_suffix + && !nt_path_has_executable_suffix + (newpc.get_nt_native_path ())) + /* Never append .exe suffix if oldpath had .exe suffix given + explicitely, or if oldpath wasn't already a .exe file, or + if the destination filename has one of the blessed executable + suffixes. + Note: To rename an executable foo.exe to bar-without-suffix, + the .exe suffix must be given explicitly in oldpath. */ + rename_append_suffix (newpc, newpath, nlen, ".exe"); } else { - /* If the new path is an existing .lnk symlink or a .exe file, - but the new path has not been specified with explicit suffix, - rename to the new name without suffix, as expected, but also - remove the clashing symlink or executable. Did I ever mention - how I hate the file suffix idea? */ - if ((newpc.is_lnk_special () - || RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), - &ro_u_exe, TRUE)) - && !new_explicit_suffix) + if (equal_path && old_explicit_suffix != new_explicit_suffix) { - new2pc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); - newpc.get_nt_native_path ()->Length -= 4 * sizeof (WCHAR); - if (new2pc.is_binary () || new2pc.is_lnk_special ()) - removepc = &new2pc; + newpc.check (newpath, PC_SYM_NOFOLLOW); + if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + oldpc.objcaseinsensitive ())) + { + res = 0; + __leave; + } } - } - } - dstpc = (removepc == &newpc) ? &new2pc : &newpc; - - /* Check cross-device before touching anything. Otherwise we might end - up with an unlinked target dir even if the actual rename didn't work. */ - if (oldpc.fs_type () != dstpc->fs_type () - || oldpc.fs_serial_number () != dstpc->fs_serial_number ()) - { - set_errno (EXDEV); - goto out; - } - - /* Opening the file must be part of the transaction. It's not sufficient - to call only NtSetInformationFile under the transaction. Therefore we - have to start the transaction here, if necessary. */ - if (wincap.has_transactions () - && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) - && (dstpc->isdir () - || (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)))) - start_transaction (old_trans, trans); - - int retry_count; - retry_count = 0; -retry: - /* Talking about inconsistent behaviour... - - DELETE is required to rename a file. So far, so good. - - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the - FileRenameInformation call fails with STATUS_ACCESS_DENIED. However, - on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used - and the file we try to rename is a symlink. Urgh. - - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE mode if - the file has the R/O attribute set and returns STATUS_ACCESS_DENIED in - that case. */ - { - ULONG access = DELETE | (oldpc.fs_is_cifs () ? FILE_READ_ATTRIBUTES : 0); - ULONG sharing = FILE_SHARE_READ | FILE_SHARE_WRITE - | (oldpc.fs_is_samba () ? 0 : FILE_SHARE_DELETE); - ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT - | (oldpc.is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0); - status = NtOpenFile (&fh, access, - oldpc.get_object_attr (attr, sec_none_nih), - &io, sharing, flags); - } - if (!NT_SUCCESS (status)) - { - debug_printf ("status %y", status); - if (status == STATUS_SHARING_VIOLATION - && cygwait (10L) != WAIT_SIGNALED) - { - /* Typical BLODA problem. Some virus scanners check newly generated - files and while doing that disallow DELETE access. That's really - bad because it breaks applications which copy files by creating - a temporary filename and then rename the temp filename to the - target filename. This renaming fails due to the jealous virus - scanner and the application fails to create the target file. - - This kludge tries to work around that by yielding until the - sharing violation goes away, or a signal arrived, or after - about a second, give or take. */ - if (++retry_count < 40) + else if (oldpc.is_lnk_special ()) { - yield (); - goto retry; + if (!newpc.is_lnk_special () + && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), + &ro_u_lnk, TRUE)) + { + rename_append_suffix (new2pc, newpath, nlen, ".lnk"); + removepc = &newpc; + } + } + else if (oldpc.is_binary ()) + { + /* Never append .exe suffix if oldpath had .exe suffix given + explicitely, or if newfile is a binary (in which case the given + name probably makes sense as it is), or if the destination + filename has one of the blessed executable suffixes. */ + if (!old_explicit_suffix && oldpc.known_suffix + && !newpc.is_binary () + && !nt_path_has_executable_suffix + (newpc.get_nt_native_path ())) + { + rename_append_suffix (new2pc, newpath, nlen, ".exe"); + removepc = &newpc; + } + } + else + { + /* If the new path is an existing .lnk symlink or a .exe file, + but the new path has not been specified with explicit suffix, + rename to the new name without suffix, as expected, but also + remove the clashing symlink or executable. Did I ever mention + how I hate the file suffix idea? */ + if ((newpc.is_lnk_special () + || RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), + &ro_u_exe, TRUE)) + && !new_explicit_suffix) + { + new2pc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); + newpc.get_nt_native_path ()->Length -= 4 * sizeof (WCHAR); + if (new2pc.is_binary () || new2pc.is_lnk_special ()) + removepc = &new2pc; + } } } - else if (NT_TRANSACTIONAL_ERROR (status) && trans) + dstpc = (removepc == &newpc) ? &new2pc : &newpc; + + /* Check cross-device before touching anything. Otherwise we might end + up with an unlinked target dir even if the actual rename didn't work.*/ + if (oldpc.fs_type () != dstpc->fs_type () + || oldpc.fs_serial_number () != dstpc->fs_serial_number ()) { - /* If NtOpenFile fails due to transactional problems, stop - transaction and go ahead without. */ - stop_transaction (status, old_trans, trans); - debug_printf ("Transaction failure. Retry open."); - goto retry; + set_errno (EXDEV); + __leave; } - __seterrno_from_nt_status (status); - goto out; - } - /* Renaming a dir to another, existing dir fails always, even if - ReplaceIfExists is set to TRUE and the existing dir is empty. So - we have to remove the destination dir first. This also covers the - case that the destination directory is not empty. In that case, - unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */ - if (dstpc->isdir ()) - { - status = unlink_nt (*dstpc); + /* Opening the file must be part of the transaction. It's not sufficient + to call only NtSetInformationFile under the transaction. Therefore we + have to start the transaction here, if necessary. */ + if (wincap.has_transactions () + && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) + && (dstpc->isdir () + || (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)))) + start_transaction (old_trans, trans); + + int retry_count; + retry_count = 0; + retry: + /* Talking about inconsistent behaviour... + - DELETE is required to rename a file. So far, so good. + - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the + FileRenameInformation call fails with STATUS_ACCESS_DENIED. However, + on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used + and the file we try to rename is a symlink. Urgh. + - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE + mode if the file has the R/O attribute set and returns + STATUS_ACCESS_DENIED in that case. */ + { + ULONG access = DELETE + | (oldpc.fs_is_cifs () ? FILE_READ_ATTRIBUTES : 0); + ULONG sharing = FILE_SHARE_READ | FILE_SHARE_WRITE + | (oldpc.fs_is_samba () ? 0 : FILE_SHARE_DELETE); + ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT + | (oldpc.is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0); + status = NtOpenFile (&fh, access, + oldpc.get_object_attr (attr, sec_none_nih), + &io, sharing, flags); + } if (!NT_SUCCESS (status)) { + debug_printf ("status %y", status); + if (status == STATUS_SHARING_VIOLATION + && cygwait (10L) != WAIT_SIGNALED) + { + /* Typical BLODA problem. Some virus scanners check newly + generated files and while doing that disallow DELETE access. + That's really bad because it breaks applications which copy + files by creating a temporary filename and then rename the + temp filename to the target filename. This renaming fails due + to the jealous virus scanner and the application fails to + create the target file. + + This kludge tries to work around that by yielding until the + sharing violation goes away, or a signal arrived, or after + about a second, give or take. */ + if (++retry_count < 40) + { + yield (); + goto retry; + } + } + else if (NT_TRANSACTIONAL_ERROR (status) && trans) + { + /* If NtOpenFile fails due to transactional problems, stop + transaction and go ahead without. */ + stop_transaction (status, old_trans, trans); + debug_printf ("Transaction failure. Retry open."); + goto retry; + } __seterrno_from_nt_status (status); - goto out; + __leave; } - } - /* You can't copy a file if the destination exists and has the R/O - attribute set. Remove the R/O attribute first. But first check - if a removepc exists. If so, dstpc points to a non-existing file - due to a mangled suffix. */ - else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)) - { - status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES, - dstpc->get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT - | (dstpc->is_rep_symlink () - ? FILE_OPEN_REPARSE_POINT : 0)); - if (!NT_SUCCESS (status)) + + /* Renaming a dir to another, existing dir fails always, even if + ReplaceIfExists is set to TRUE and the existing dir is empty. So + we have to remove the destination dir first. This also covers the + case that the destination directory is not empty. In that case, + unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */ + if (dstpc->isdir ()) { - __seterrno_from_nt_status (status); - goto out; + status = unlink_nt (*dstpc); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } } - status = NtSetAttributesFile (nfh, dstpc->file_attributes () - & ~FILE_ATTRIBUTE_READONLY); - NtClose (nfh); - if (!NT_SUCCESS (status)) + /* You can't copy a file if the destination exists and has the R/O + attribute set. Remove the R/O attribute first. But first check + if a removepc exists. If so, dstpc points to a non-existing file + due to a mangled suffix. */ + else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)) { - __seterrno_from_nt_status (status); - goto out; + status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES, + dstpc->get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT + | (dstpc->is_rep_symlink () + ? FILE_OPEN_REPARSE_POINT : 0)); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } + status = NtSetAttributesFile (nfh, dstpc->file_attributes () + & ~FILE_ATTRIBUTE_READONLY); + NtClose (nfh); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } } - } - /* SUSv3: If the old argument and the new argument resolve to the same - existing file, rename() shall return successfully and perform no - other action. - The test tries to be as quick as possible. Due to the above cross device - check we already know both files are on the same device. So it just - tests if oldpath has more than 1 hardlink, then it opens newpath - and tests for identical file ids. If so, oldpath and newpath refer to - the same file. */ - if ((removepc || dstpc->exists ()) - && !oldpc.isdir () - && NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofsi, sizeof ofsi, - FileStandardInformation)) - && ofsi.NumberOfLinks > 1 - && NT_SUCCESS (NtOpenFile (&nfh, READ_CONTROL, + /* SUSv3: If the old argument and the new argument resolve to the same + existing file, rename() shall return successfully and perform no + other action. + The test tries to be as quick as possible. Due to the above cross + device check we already know both files are on the same device. So + it just tests if oldpath has more than 1 hardlink, then it opens + newpath and tests for identical file ids. If so, oldpath and newpath + refer to the same file. */ + if ((removepc || dstpc->exists ()) + && !oldpc.isdir () + && NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofsi, sizeof ofsi, + FileStandardInformation)) + && ofsi.NumberOfLinks > 1 + && NT_SUCCESS (NtOpenFile (&nfh, READ_CONTROL, (removepc ?: dstpc)->get_object_attr (attr, sec_none_nih), &io, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT | ((removepc ?: dstpc)->is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0)))) - { - FILE_INTERNAL_INFORMATION ofii, nfii; - - if (NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofii, sizeof ofii, - FileInternalInformation)) - && NT_SUCCESS (NtQueryInformationFile (nfh, &io, &nfii, sizeof nfii, - FileInternalInformation)) - && ofii.FileId.QuadPart == nfii.FileId.QuadPart) { - debug_printf ("%s and %s are the same file", oldpath, newpath); + FILE_INTERNAL_INFORMATION ofii, nfii; + + if (NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofii, sizeof ofii, + FileInternalInformation)) + && NT_SUCCESS (NtQueryInformationFile (nfh, &io, &nfii, + sizeof nfii, + FileInternalInformation)) + && ofii.FileId.QuadPart == nfii.FileId.QuadPart) + { + debug_printf ("%s and %s are the same file", oldpath, newpath); + NtClose (nfh); + res = 0; + __leave; + } NtClose (nfh); - res = 0; - goto out; } - NtClose (nfh); - } - /* Create FILE_RENAME_INFORMATION struct. Using a tmp_pathbuf area allows - for paths of up to 32757 chars. This test is just for paranoia's sake. */ - if (dstpc->get_nt_native_path ()->Length > NT_MAX_PATH * sizeof (WCHAR) - - sizeof (FILE_RENAME_INFORMATION)) - { - debug_printf ("target filename too long"); - set_errno (EINVAL); - goto out; - } - pfri = (PFILE_RENAME_INFORMATION) tp.w_get (); - pfri->ReplaceIfExists = TRUE; - pfri->RootDirectory = NULL; - pfri->FileNameLength = dstpc->get_nt_native_path ()->Length; - memcpy (&pfri->FileName, dstpc->get_nt_native_path ()->Buffer, - pfri->FileNameLength); - status = NtSetInformationFile (fh, &io, pfri, - sizeof *pfri + pfri->FileNameLength, - FileRenameInformation); - /* This happens if the access rights don't allow deleting the destination. - Even if the handle to the original file is opened with BACKUP - and/or RECOVERY, these flags don't apply to the destination of the - rename operation. So, a privileged user can't rename a file to an - existing file, if the permissions of the existing file aren't right. - Like directories, we have to handle this separately by removing the - destination before renaming. */ - if (status == STATUS_ACCESS_DENIED && dstpc->exists () && !dstpc->isdir ()) - { - if (wincap.has_transactions () - && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) - && !trans) + /* Create FILE_RENAME_INFORMATION struct. Using a tmp_pathbuf area + allows for paths of up to 32757 chars. This test is just for + paranoia's sake. */ + if (dstpc->get_nt_native_path ()->Length + > NT_MAX_PATH * sizeof (WCHAR) - sizeof (FILE_RENAME_INFORMATION)) { - start_transaction (old_trans, trans); - /* As mentioned earlier, opening the file must be part of the - transaction. Therefore we have to reopen the file here if the - transaction hasn't been started already. Unfortunately we can't - use the NT "reopen file from existing handle" feature. In that - case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT. We *have* - to close the handle to the file first, *then* we can re-open it. - Fortunately nothing has happened yet, so the atomicity of the - rename functionality is not spoiled. */ - NtClose (fh); -retry_reopen: - status = NtOpenFile (&fh, DELETE, - oldpc.get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT - | (oldpc.is_rep_symlink () - ? FILE_OPEN_REPARSE_POINT : 0)); - if (!NT_SUCCESS (status)) + debug_printf ("target filename too long"); + set_errno (EINVAL); + __leave; + } + pfri = (PFILE_RENAME_INFORMATION) tp.w_get (); + pfri->ReplaceIfExists = TRUE; + pfri->RootDirectory = NULL; + pfri->FileNameLength = dstpc->get_nt_native_path ()->Length; + memcpy (&pfri->FileName, dstpc->get_nt_native_path ()->Buffer, + pfri->FileNameLength); + status = NtSetInformationFile (fh, &io, pfri, + sizeof *pfri + pfri->FileNameLength, + FileRenameInformation); + /* This happens if the access rights don't allow deleting the destination. + Even if the handle to the original file is opened with BACKUP + and/or RECOVERY, these flags don't apply to the destination of the + rename operation. So, a privileged user can't rename a file to an + existing file, if the permissions of the existing file aren't right. + Like directories, we have to handle this separately by removing the + destination before renaming. */ + if (status == STATUS_ACCESS_DENIED && dstpc->exists () + && !dstpc->isdir ()) + { + if (wincap.has_transactions () + && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) + && !trans) { - if (NT_TRANSACTIONAL_ERROR (status) && trans) + start_transaction (old_trans, trans); + /* As mentioned earlier, opening the file must be part of the + transaction. Therefore we have to reopen the file here if the + transaction hasn't been started already. Unfortunately we + can't use the NT "reopen file from existing handle" feature. + In that case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT. + We *have* to close the handle to the file first, *then* we can + re-open it. Fortunately nothing has happened yet, so the + atomicity of the rename functionality is not spoiled. */ + NtClose (fh); + retry_reopen: + status = NtOpenFile (&fh, DELETE, + oldpc.get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT + | (oldpc.is_rep_symlink () + ? FILE_OPEN_REPARSE_POINT : 0)); + if (!NT_SUCCESS (status)) { - /* If NtOpenFile fails due to transactional problems, stop - transaction and go ahead without. */ - stop_transaction (status, old_trans, trans); - debug_printf ("Transaction failure. Retry open."); - goto retry_reopen; + if (NT_TRANSACTIONAL_ERROR (status) && trans) + { + /* If NtOpenFile fails due to transactional problems, + stop transaction and go ahead without. */ + stop_transaction (status, old_trans, trans); + debug_printf ("Transaction failure. Retry open."); + goto retry_reopen; + } + __seterrno_from_nt_status (status); + __leave; } - __seterrno_from_nt_status (status); - goto out; } + if (NT_SUCCESS (status = unlink_nt (*dstpc))) + status = NtSetInformationFile (fh, &io, pfri, + sizeof *pfri + pfri->FileNameLength, + FileRenameInformation); + } + if (NT_SUCCESS (status)) + { + if (removepc) + unlink_nt (*removepc); + res = 0; } - if (NT_SUCCESS (status = unlink_nt (*dstpc))) - status = NtSetInformationFile (fh, &io, pfri, - sizeof *pfri + pfri->FileNameLength, - FileRenameInformation); + else + __seterrno_from_nt_status (status); } - if (NT_SUCCESS (status)) + __except (EFAULT) { - if (removepc) - unlink_nt (*removepc); - res = 0; + res = -1; } - else - __seterrno_from_nt_status (status); - -out: + __endtry if (fh) NtClose (fh); /* Stop transaction if we started one. */ if (trans) stop_transaction (status, old_trans, trans); - syscall_printf ("%R = rename(%s, %s)", res, oldpath, newpath); + if (get_errno () != EFAULT) + syscall_printf ("%R = rename(%s, %s)", res, oldpath, newpath); return res; } @@ -2611,28 +2623,28 @@ system (const char *cmdstring) { pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - int res; - const char* command[4]; - if (cmdstring == NULL) return 1; - command[0] = "sh"; - command[1] = "-c"; - command[2] = cmdstring; - command[3] = (const char *) NULL; + int res = -1; + const char* command[4]; - if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1) + __try { - // when exec fails, return value should be as if shell - // executed exit (127) - res = 127; - } + command[0] = "sh"; + command[1] = "-c"; + command[2] = cmdstring; + command[3] = (const char *) NULL; + if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1) + { + // when exec fails, return value should be as if shell + // executed exit (127) + res = 127; + } + } + __except (EFAULT) {} + __endtry return res; } @@ -2677,24 +2689,25 @@ fpathconf (int fd, int v) extern "C" long int pathconf (const char *file, int v) { - fhandler_base *fh; + fhandler_base *fh = NULL; long ret = -1; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (!*file) + __try { - set_errno (ENOENT); - return -1; + if (!*file) + { + set_errno (ENOENT); + return -1; + } + if (!(fh = build_fh_name (file, PC_SYM_FOLLOW, stat_suffixes))) + return -1; + if (!fh->exists ()) + set_errno (ENOENT); + else + ret = fh->fpathconf (v); } - if (!(fh = build_fh_name (file, PC_SYM_FOLLOW, stat_suffixes))) - return -1; - if (!fh->exists ()) - set_errno (ENOENT); - else - ret = fh->fpathconf (v); + __except (EFAULT) {} + __endtry delete fh; return ret; } @@ -2703,10 +2716,8 @@ extern "C" int ttyname_r (int fd, char *buf, size_t buflen) { int ret = 0; - myfault efault; - if (efault.faulted ()) - ret = EFAULT; - else + + __try { cygheap_fdget cfd (fd, true); if (cfd < 0) @@ -2717,8 +2728,13 @@ ttyname_r (int fd, char *buf, size_t buflen) ret = ERANGE; else strcpy (buf, cfd->ttyname ()); + debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf); } - debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf); + __except (NO_ERROR) + { + ret = EFAULT; + } + __endtry return ret; } @@ -2975,14 +2991,16 @@ _get_osfhandle (int fd) extern "C" int fstatvfs (int fd, struct statvfs *sfs) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - cygheap_fdget cfd (fd); - if (cfd < 0) - return -1; - return cfd->fstatvfs (sfs); + __try + { + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; + return cfd->fstatvfs (sfs); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -2991,30 +3009,31 @@ statvfs (const char *name, struct statvfs *sfs) int res = -1; fhandler_base *fh = NULL; - myfault efault; - if (efault.faulted (EFAULT)) - goto error; + __try + { + if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes))) + __leave; - if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes))) - goto error; + if (fh->error ()) + { + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); + } + else if (fh->exists ()) + { + debug_printf ("(%s, %p), file_attributes %d", name, sfs, (DWORD) *fh); + res = fh->fstatvfs (sfs); + } + else + set_errno (ENOENT); - if (fh->error ()) - { - debug_printf ("got %d error from build_fh_name", fh->error ()); - set_errno (fh->error ()); - } - else if (fh->exists ()) - { - debug_printf ("(%s, %p), file_attributes %d", name, sfs, (DWORD) *fh); - res = fh->fstatvfs (sfs); } - else - set_errno (ENOENT); - + __except (EFAULT) {} + __endtry delete fh; - error: MALLOC_CHECK; - syscall_printf ("%R = statvfs(%s,%p)", res, name, sfs); + if (get_errno () != EFAULT) + syscall_printf ("%R = statvfs(%s,%p)", res, name, sfs); return res; } @@ -3155,55 +3174,58 @@ mknod_worker (const char *path, mode_t type, mode_t mode, _major_t major, extern "C" int mknod32 (const char *path, mode_t mode, dev_t dev) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!*path) + __try { - set_errno (ENOENT); - return -1; - } + if (!*path) + { + set_errno (ENOENT); + __leave; + } - if (strlen (path) >= PATH_MAX) - return -1; + if (strlen (path) >= PATH_MAX) + __leave; - path_conv w32path (path, PC_SYM_NOFOLLOW); - if (w32path.exists ()) - { - set_errno (EEXIST); - return -1; - } + path_conv w32path (path, PC_SYM_NOFOLLOW); + if (w32path.exists ()) + { + set_errno (EEXIST); + __leave; + } - mode_t type = mode & S_IFMT; - _major_t major = _major (dev); - _minor_t minor = _minor (dev); - switch (type) - { - case S_IFCHR: - case S_IFBLK: - break; + mode_t type = mode & S_IFMT; + _major_t major = _major (dev); + _minor_t minor = _minor (dev); + switch (type) + { + case S_IFCHR: + case S_IFBLK: + break; - case S_IFIFO: - major = _major (FH_FIFO); - minor = _minor (FH_FIFO); - break; + case S_IFIFO: + major = _major (FH_FIFO); + minor = _minor (FH_FIFO); + break; - case 0: - case S_IFREG: - { - int fd = open (path, O_CREAT, mode); - if (fd < 0) - return -1; - close (fd); - return 0; - } + case 0: + case S_IFREG: + { + int fd = open (path, O_CREAT, mode); + if (fd < 0) + __leave; + close (fd); + return 0; + } - default: - set_errno (EINVAL); - return -1; - } + default: + set_errno (EINVAL); + __leave; + } - return mknod_worker (w32path.get_win32 (), type, mode, major, minor); + return mknod_worker (w32path.get_win32 (), type, mode, major, minor); + } + __except (EFAULT) + __endtry + return -1; } extern "C" int @@ -3912,15 +3934,19 @@ endutent () extern "C" void utmpname (const char *file) { - myfault efault; - if (efault.faulted () || !*file) + __try { - debug_printf ("Invalid file"); - return; + if (*file) + { + endutent (); + utmp_file = strdup (file); + debug_printf ("New UTMP file: %s", utmp_file); + return; + } } - endutent (); - utmp_file = strdup (file); - debug_printf ("New UTMP file: %s", utmp_file); + __except (NO_ERROR) {} + __endtry + debug_printf ("Invalid file"); } EXPORT_ALIAS (utmpname, utmpxname) @@ -3965,94 +3991,99 @@ getutent () extern "C" struct utmp * getutid (const struct utmp *id) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - if (utmp_fd < 0) + __try { - internal_setutent (false); if (utmp_fd < 0) - return NULL; - } - - utmp *ut = utmp_data; - while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) - { - switch (id->ut_type) { - case RUN_LVL: - case BOOT_TIME: - case OLD_TIME: - case NEW_TIME: - if (id->ut_type == ut->ut_type) - return ut; - break; - case INIT_PROCESS: - case LOGIN_PROCESS: - case USER_PROCESS: - case DEAD_PROCESS: - if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0) - return ut; - break; - default: - return NULL; + internal_setutent (false); + if (utmp_fd < 0) + __leave; + } + utmp *ut = utmp_data; + while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) + { + switch (id->ut_type) + { + case RUN_LVL: + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + if (id->ut_type == ut->ut_type) + return ut; + break; + case INIT_PROCESS: + case LOGIN_PROCESS: + case USER_PROCESS: + case DEAD_PROCESS: + if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0) + return ut; + break; + default: + break; + } } } + __except (EFAULT) {} + __endtry return NULL; } extern "C" struct utmp * getutline (const struct utmp *line) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - if (utmp_fd < 0) + __try { - internal_setutent (false); if (utmp_fd < 0) - return NULL; - } - - utmp *ut = utmp_data; - while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) - if ((ut->ut_type == LOGIN_PROCESS || - ut->ut_type == USER_PROCESS) && - !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line))) - return ut; + { + internal_setutent (false); + if (utmp_fd < 0) + __leave; + } + utmp *ut = utmp_data; + while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) + if ((ut->ut_type == LOGIN_PROCESS || + ut->ut_type == USER_PROCESS) && + !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line))) + return ut; + } + __except (EFAULT) {} + __endtry return NULL; } extern "C" struct utmp * pututline (const struct utmp *ut) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - internal_setutent (true); - if (utmp_fd < 0) + __try { - debug_printf ("error: utmp_fd %d", utmp_fd); - return NULL; - } - debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n", - ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id); - debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n", - ut->ut_user, ut->ut_host); + internal_setutent (true); + if (utmp_fd < 0) + { + debug_printf ("error: utmp_fd %d", utmp_fd); + __leave; + } + debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n", + ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id); + debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n", + ut->ut_user, ut->ut_host); - struct utmp *u; - if ((u = getutid (ut))) - { - lseek (utmp_fd, -sizeof *ut, SEEK_CUR); - write (utmp_fd, ut, sizeof *ut); - } - else - locked_append (utmp_fd, ut, sizeof *ut); - /* The documentation says to return a pointer to this which implies that - this has to be cast from a const. That doesn't seem right but the - documentation seems pretty clear on this. */ - return (struct utmp *) ut; + struct utmp *u; + if ((u = getutid (ut))) + { + lseek (utmp_fd, -sizeof *ut, SEEK_CUR); + write (utmp_fd, ut, sizeof *ut); + } + else + locked_append (utmp_fd, ut, sizeof *ut); + /* The documentation says to return a pointer to this which implies that + this has to be cast from a const. That doesn't seem right but the + documentation seems pretty clear on this. */ + return (struct utmp *) ut; + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" void @@ -4070,7 +4101,7 @@ endutxent () extern "C" struct utmpx * getutxent () { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; return copy_ut_to_utx (getutent (), &utx); } @@ -4078,40 +4109,49 @@ getutxent () extern "C" struct utmpx * getutxid (const struct utmpx *id) { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec; - return copy_ut_to_utx (getutid ((struct utmp *) id), &utx); + __try + { + ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec; + return copy_ut_to_utx (getutid ((struct utmp *) id), &utx); + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" struct utmpx * getutxline (const struct utmpx *line) { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec; - return copy_ut_to_utx (getutline ((struct utmp *) line), &utx); + __try + { + ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec; + return copy_ut_to_utx (getutline ((struct utmp *) line), &utx); + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" struct utmpx * pututxline (const struct utmpx *utmpx) { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec; - return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx); + __try + { + ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec; + return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx); + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" void @@ -4475,51 +4515,57 @@ extern "C" int openat (int dirfd, const char *pathname, int flags, ...) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; - va_list ap; - mode_t mode; + va_list ap; + mode_t mode; - va_start (ap, flags); - mode = va_arg (ap, mode_t); - va_end (ap); - return open (path, flags, mode); + va_start (ap, flags); + mode = va_arg (ap, mode_t); + va_end (ap); + return open (path, flags, mode); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int faccessat (int dirfd, const char *pathname, int mode, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - int res = -1; - char *path = tp.c_get (); - if (!gen_full_path_at (path, dirfd, pathname)) + + __try { - if ((mode & ~(F_OK|R_OK|W_OK|X_OK)) - || (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EACCESS))) - set_errno (EINVAL); - else + char *path = tp.c_get (); + if (!gen_full_path_at (path, dirfd, pathname)) { - fhandler_base *fh = build_fh_name (path, (flags & AT_SYMLINK_NOFOLLOW - ? PC_SYM_NOFOLLOW - : PC_SYM_FOLLOW) - | PC_KEEP_HANDLE, - stat_suffixes); - if (fh) + if ((mode & ~(F_OK|R_OK|W_OK|X_OK)) + || (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EACCESS))) + set_errno (EINVAL); + else { - res = fh->fhaccess (mode, !!(flags & AT_EACCESS)); - delete fh; + fhandler_base *fh = build_fh_name (path, + (flags & AT_SYMLINK_NOFOLLOW + ? PC_SYM_NOFOLLOW + : PC_SYM_FOLLOW) + | PC_KEEP_HANDLE, + stat_suffixes); + if (fh) + { + res = fh->fhaccess (mode, !!(flags & AT_EACCESS)); + delete fh; + } } } } + __except (EFAULT) {} + __endtry debug_printf ("returning %d", res); return res; } @@ -4528,40 +4574,46 @@ extern "C" int fchmodat (int dirfd, const char *pathname, mode_t mode, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags) + __try { - /* BSD has lchmod, but Linux does not. POSIX says - AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux - blindly fails even for non-symlinks. */ - set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP); - return -1; + if (flags) + { + /* BSD has lchmod, but Linux does not. POSIX says + AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux + blindly fails even for non-symlinks. */ + set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return chmod (path, mode); } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return chmod (path, mode); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int fchownat (int dirfd, const char *pathname, uid_t uid, gid_t gid, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_SYMLINK_NOFOLLOW) + __try { - set_errno (EINVAL); - return -1; - } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid); + if (flags & ~AT_SYMLINK_NOFOLLOW) + { + set_errno (EINVAL); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4569,21 +4621,24 @@ fstatat (int dirfd, const char *__restrict pathname, struct stat *__restrict st, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_SYMLINK_NOFOLLOW) + __try { - set_errno (EINVAL); - return -1; - } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) - | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes); - return stat_worker (pc, st); + if (flags & ~AT_SYMLINK_NOFOLLOW) + { + set_errno (EINVAL); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) + | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes); + return stat_worker (pc, st); + } + __except (EFAULT) {} + __endtry + return -1; } extern int utimens_worker (path_conv &, const struct timespec *); @@ -4593,34 +4648,40 @@ utimensat (int dirfd, const char *pathname, const struct timespec *times, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (flags & ~AT_SYMLINK_NOFOLLOW) + __try { - set_errno (EINVAL); - return -1; - } - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW), - stat_suffixes); - return utimens_worker (win32, times); + char *path = tp.c_get (); + if (flags & ~AT_SYMLINK_NOFOLLOW) + { + set_errno (EINVAL); + __leave; + } + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW), + stat_suffixes); + return utimens_worker (win32, times); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int futimesat (int dirfd, const char *pathname, const struct timeval *times) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname, true)) - return -1; - return utimes (path, times); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname, true)) + __leave; + return utimes (path, times); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4629,70 +4690,82 @@ linkat (int olddirfd, const char *oldpathname, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_SYMLINK_FOLLOW) - { - set_errno (EINVAL); - return -1; - } - char *oldpath = tp.c_get (); - if (gen_full_path_at (oldpath, olddirfd, oldpathname)) - return -1; - char *newpath = tp.c_get (); - if (gen_full_path_at (newpath, newdirfd, newpathname)) - return -1; - if (flags & AT_SYMLINK_FOLLOW) + __try { - path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); - if (old_name.error) + if (flags & ~AT_SYMLINK_FOLLOW) { - set_errno (old_name.error); - return -1; + set_errno (EINVAL); + __leave; } - strcpy (oldpath, old_name.normalized_path); + char *oldpath = tp.c_get (); + if (gen_full_path_at (oldpath, olddirfd, oldpathname)) + __leave; + char *newpath = tp.c_get (); + if (gen_full_path_at (newpath, newdirfd, newpathname)) + __leave; + if (flags & AT_SYMLINK_FOLLOW) + { + path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); + if (old_name.error) + { + set_errno (old_name.error); + __leave; + } + strcpy (oldpath, old_name.normalized_path); + } + return link (oldpath, newpath); } - return link (oldpath, newpath); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int mkdirat (int dirfd, const char *pathname, mode_t mode) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return mkdir (path, mode); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return mkdir (path, mode); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int mkfifoat (int dirfd, const char *pathname, mode_t mode) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return mkfifo (path, mode); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return mkfifo (path, mode); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int mknodat (int dirfd, const char *pathname, mode_t mode, dev_t dev) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return mknod32 (path, mode, dev); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return mknod32 (path, mode, dev); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" ssize_t @@ -4700,13 +4773,16 @@ readlinkat (int dirfd, const char *__restrict pathname, char *__restrict buf, size_t bufsize) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return readlink (path, buf, bufsize); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return readlink (path, buf, bufsize); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4714,16 +4790,19 @@ renameat (int olddirfd, const char *oldpathname, int newdirfd, const char *newpathname) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *oldpath = tp.c_get (); - if (gen_full_path_at (oldpath, olddirfd, oldpathname)) - return -1; - char *newpath = tp.c_get (); - if (gen_full_path_at (newpath, newdirfd, newpathname)) - return -1; - return rename (oldpath, newpath); + __try + { + char *oldpath = tp.c_get (); + if (gen_full_path_at (oldpath, olddirfd, oldpathname)) + __leave; + char *newpath = tp.c_get (); + if (gen_full_path_at (newpath, newdirfd, newpathname)) + __leave; + return rename (oldpath, newpath); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4732,42 +4811,51 @@ scandirat (int dirfd, const char *pathname, struct dirent ***namelist, int (*compar) (const struct dirent **, const struct dirent **)) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return scandir (pathname, namelist, select, compar); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return scandir (pathname, namelist, select, compar); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int symlinkat (const char *oldpath, int newdirfd, const char *newpathname) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *newpath = tp.c_get (); - if (gen_full_path_at (newpath, newdirfd, newpathname)) - return -1; - return symlink (oldpath, newpath); + __try + { + char *newpath = tp.c_get (); + if (gen_full_path_at (newpath, newdirfd, newpathname)) + __leave; + return symlink (oldpath, newpath); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int unlinkat (int dirfd, const char *pathname, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_REMOVEDIR) + __try { - set_errno (EINVAL); - return -1; + if (flags & ~AT_REMOVEDIR) + { + set_errno (EINVAL); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path); } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path); + __except (EFAULT) {} + __endtry + return -1; } |