OSDN Git Service

* ntdll.h (STATUS_ACCESS_DENIED): Define.
authorcorinna <corinna>
Wed, 1 Aug 2007 14:46:09 +0000 (14:46 +0000)
committercorinna <corinna>
Wed, 1 Aug 2007 14:46:09 +0000 (14:46 +0000)
* syscalls.cc (check_dir_not_empty): New static function.
(unlink_nt): Move code checking for non-empty dir to check_dir_not_empty
and call check_dir_not_empty instead.
(rename): Add fault handler.  Check oldpath and newpath for trailing
. and .. path components and return EINVAL if so.  Check oldpath
for being on a vrtual file system.  If renaming a dir fails with
STATUS_ACCESS_DENIED, check if the target dir is non-empty and return
ENOTEMPTY if so.

winsup/cygwin/ChangeLog
winsup/cygwin/ntdll.h
winsup/cygwin/syscalls.cc

index 3d3ea9b..222d03f 100644 (file)
@@ -1,5 +1,17 @@
 2007-08-01  Corinna Vinschen  <corinna@vinschen.de>
 
+       * ntdll.h (STATUS_ACCESS_DENIED): Define.
+       * syscalls.cc (check_dir_not_empty): New static function.
+       (unlink_nt): Move code checking for non-empty dir to check_dir_not_empty
+       and call check_dir_not_empty instead.
+       (rename): Add fault handler.  Check oldpath and newpath for trailing
+       . and .. path components and return EINVAL if so.  Check oldpath
+       for being on a vrtual file system.  If renaming a dir fails with
+       STATUS_ACCESS_DENIED, check if the target dir is non-empty and return
+       ENOTEMPTY if so.
+
+2007-08-01  Corinna Vinschen  <corinna@vinschen.de>
+
        * localtime.cc (tzsetwall): Don't set TZ.
 
 2007-08-01  Corinna Vinschen  <corinna@vinschen.de>
index 8936dd4..0eca362 100644 (file)
@@ -17,6 +17,7 @@
 #define STATUS_INVALID_PARAMETER      ((NTSTATUS) 0xc000000d)
 #define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010)
 #define STATUS_NO_MEDIA_IN_DEVICE     ((NTSTATUS) 0xc0000013)
+#define STATUS_ACCESS_DENIED          ((NTSTATUS) 0xc0000022)
 #define STATUS_BUFFER_TOO_SMALL       ((NTSTATUS) 0xc0000023)
 #define STATUS_OBJECT_NAME_NOT_FOUND  ((NTSTATUS) 0xc0000034)
 #define STATUS_SHARING_VIOLATION      ((NTSTATUS) 0xc0000043)
index 6e1f781..1c202e3 100644 (file)
@@ -228,6 +228,38 @@ try_to_bin (path_conv &win32_path, HANDLE h)
                  recycler, status);
 }
 
+static NTSTATUS
+check_dir_not_empty (HANDLE dir)
+{
+  IO_STATUS_BLOCK io;
+  const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION)
+                      + 3 * NAME_MAX * sizeof (WCHAR);
+  PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION)
+                                alloca (bufsiz);
+  NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni,
+                                         bufsiz, FileNamesInformation,
+                                         FALSE, NULL, TRUE);
+  if (!NT_SUCCESS (status))
+    {
+      syscall_printf ("Checking if directory is empty failed, "
+                     "status = %p", status);
+      return status;
+    }
+  int cnt = 1;
+  while (pfni->NextEntryOffset)
+    {
+      pfni = (PFILE_NAMES_INFORMATION)
+            ((caddr_t) pfni + pfni->NextEntryOffset);
+      ++cnt;
+    }
+  if (cnt > 2)
+    {
+      syscall_printf ("Directory not empty");
+      return STATUS_DIRECTORY_NOT_EMPTY;
+    }
+  return STATUS_SUCCESS;
+}
+
 NTSTATUS
 unlink_nt (path_conv &pc)
 {
@@ -284,33 +316,12 @@ unlink_nt (path_conv &pc)
                               flags | FILE_SYNCHRONOUS_IO_NONALERT);
          if (NT_SUCCESS (status))
            {
-             const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION)
-                                  + 3 * NAME_MAX * sizeof (WCHAR);
-             PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION)
-                                            alloca (bufsiz);
-             status = NtQueryDirectoryFile (fh, NULL, NULL, 0, &io, pfni,
-                                            bufsiz, FileNamesInformation,
-                                            FALSE, NULL, TRUE);
+             status = check_dir_not_empty (fh);
              if (!NT_SUCCESS (status))
                {
                  NtClose (fh);
-                 syscall_printf ("Checking if directory is empty failed, "
-                                 "status = %p", status);
                  return status;
                }
-             int cnt = 1;
-             while (pfni->NextEntryOffset)
-               {
-                 pfni = (PFILE_NAMES_INFORMATION)
-                        ((caddr_t) pfni + pfni->NextEntryOffset);
-                 ++cnt;
-               }
-             if (cnt > 2)
-               {
-                 NtClose (fh);
-                 syscall_printf ("Directory not empty");
-                 return STATUS_DIRECTORY_NOT_EMPTY;
-               }
            }
        }
     }
@@ -1347,7 +1358,18 @@ rename (const char *oldpath, const char *newpath)
   IO_STATUS_BLOCK io;
   ULONG size;
   PFILE_RENAME_INFORMATION pfri;
-  
+
+  myfault efault;
+  if (efault.faulted (EFAULT))
+    return -1;
+
+  if (has_dot_last_component (oldpath, true)
+      || has_dot_last_component (newpath, true))
+    {
+      set_errno (EINVAL);
+      goto out;
+    }
+
   oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
   if (oldpc.error)
     {
@@ -1359,6 +1381,11 @@ rename (const char *oldpath, const char *newpath)
       set_errno (ENOENT);
       goto out;
     }
+  if (oldpc.isspecial ()) /* No renames from virtual FS */
+    {
+      set_errno (EROFS);
+      goto out;
+    }
   olen = strlen (oldpath);
   if (oldpc.known_suffix
       && (strcasematch (oldpath + olen - 4, ".lnk")
@@ -1371,7 +1398,7 @@ rename (const char *oldpath, const char *newpath)
       set_errno (newpc.error);
       goto out;
     }
-  if (newpc.isspecial ()) /* No renames out of the FS */
+  if (newpc.isspecial ()) /* No renames to virtual FSes */
     {
       set_errno (EROFS);
       goto out;
@@ -1509,7 +1536,22 @@ rename (const char *oldpath, const char *newpath)
       res = 0;
     }
   else
-    __seterrno_from_nt_status (status);
+    {
+      /* Check in case of STATUS_ACCESS_DENIED and pc.isdir(),
+         whether we tried to rename to an existing non-empty dir.
+        In this case we have to set errno to EEXIST. */
+      if (status == STATUS_ACCESS_DENIED && dstpc->isdir ()
+         && NT_SUCCESS (NtOpenFile (&fh, FILE_LIST_DIRECTORY | SYNCHRONIZE,
+                                   dstpc->get_object_attr (attr, sec_none_nih),
+                                   &io, FILE_SHARE_VALID_FLAGS,
+                                   FILE_OPEN_FOR_BACKUP_INTENT
+                                   | FILE_SYNCHRONOUS_IO_NONALERT)))
+       {
+         status = check_dir_not_empty (fh);
+         NtClose (fh);
+       }
+      __seterrno_from_nt_status (status);
+    }
   NtClose (fh);
 
 out: