This is the mail archive of the cygwin-patches mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [1.7] rename/renameat error


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Christopher Faylor on 9/23/2009 10:41 AM:
>> Also less risky would be to make changes locally in mkdir, link, and
>> rename for now.

Done - this patch narrows the scope of the changes to just the interfaces
in question.  I've also tested that it made it through the coreutils
testsuite without any regressions.

> 
> I'm not clear if this is a regression or not.  If it isn't a regression,
> I'd opt for leaving it until 1.7.2.

Now that I'm not touching path.cc, these are all much more self-contained,
and make cygwin more consistent with Linux.  For example:

touch a
ln -s c b
link a b/

should fail because b/ is not an existing directory, but without this
patch, it succeeds and creates the regular file c as a link to a.

2009-09-24  Eric Blake  <ebb9@byu.net>

	* syscalls.cc (link): Delete obsolete comment.  Reject directories
	and missing source up front.
	(rename): Use correct errno for trailing '.'.  Allow trailing
	slash to newpath iff oldpath is directory.
	* dir.cc (mkdir): Reject dangling symlink with trailing slash.
	* fhandler_disk_file.cc (fhandler_disk_file::link): Reject
	trailing slash.
	* fhandler.cc (fhandler_base::link): Match Linux errno.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             ebb9@byu.net
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkq8OaEACgkQ84KuGfSFAYAiLACghYLCFaIGmFR4AuzKAmBuQcg/
kFoAoJcX+ufE6YUq7S1AeVRvHtyZ30wc
=4otJ
-----END PGP SIGNATURE-----
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index 2b9125f..b7c31e4 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -1,6 +1,7 @@
 /* dir.cc: Posix directory-related routines

-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2006, 2007 Red Hat, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2006, 2007,
+   2009 Red Hat, Inc.

 This file is part of Cygwin.

@@ -21,6 +22,7 @@ details. */
 #include "dtable.h"
 #include "cygheap.h"
 #include "cygtls.h"
+#include "tls_pbuf.h"

 extern "C" int
 dirfd (DIR *dir)
@@ -273,11 +275,26 @@ mkdir (const char *dir, mode_t mode)
 {
   int res = -1;
   fhandler_base *fh = NULL;
+  size_t dlen;
+  char *newbuf;
+  tmp_pathbuf tp;

   myfault efault;
   if (efault.faulted (EFAULT))
     return -1;

+  /* POSIX says mkdir("symlink-to-missing/") should create the
+     directory "missing", but Linux rejects it with EEXIST.  Copy
+     Linux behavior for now.  */
+
+  dlen = strlen (dir);
+  if (isdirsep (dir[dlen - 1]))
+    {
+      stpcpy (newbuf = tp.c_get (), dir);
+      while (dlen > 0 && isdirsep (dir[dlen - 1]))
+        newbuf[--dlen] = '\0';
+      dir = newbuf;
+    }
   if (!(fh = build_fh_name (dir, NULL, PC_SYM_NOFOLLOW)))
     goto done;   /* errno already set */;

diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index b52d7c2..44311ca 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1541,7 +1541,7 @@ fhandler_base::ftruncate (_off64_t length, bool allow_truncate)
 int
 fhandler_base::link (const char *newpath)
 {
-  set_errno (EINVAL);
+  set_errno (EPERM);
   return -1;
 }

diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 214be47..4c4b559 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -1186,6 +1186,7 @@ fhandler_disk_file::ftruncate (_off64_t length, bool allow_truncate)
 int
 fhandler_disk_file::link (const char *newpath)
 {
+  size_t nlen = strlen (newpath);
   path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
   if (newpc.error)
     {
@@ -1200,7 +1201,13 @@ fhandler_disk_file::link (const char *newpath)
       return -1;
     }

-  char new_buf[strlen (newpath) + 5];
+  if (isdirsep (newpath[nlen - 1]) || has_dot_last_component (newpath, false))
+    {
+      set_errno (ENOENT);
+      return -1;
+    }
+
+  char new_buf[nlen + 5];
   if (!newpc.error)
     {
       if (pc.is_lnk_special ())
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 542a122..b00404d 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1124,13 +1124,6 @@ isatty (int fd)
 }
 EXPORT_ALIAS (isatty, _isatty)

-/* Under NT, try to make a hard link using backup API.  If that
-   fails or we are Win 95, just copy the file.
-   FIXME: We should actually be checking partition type, not OS.
-   Under NTFS, we should support hard links.  On FAT partitions,
-   we should just copy the file.
-*/
-
 extern "C" int
 link (const char *oldpath, const char *newpath)
 {
@@ -1145,6 +1138,10 @@ link (const char *oldpath, const char *newpath)
       debug_printf ("got %d error from build_fh_name", fh->error ());
       set_errno (fh->error ());
     }
+  else if (fh->pc.isdir ())
+    set_errno (EPERM); /* We do not permit linking directories.  */
+  else if (!fh->pc.exists ())
+    set_errno (ENOENT);
   else
     res = fh->link (newpath);

@@ -1650,13 +1647,13 @@ rename (const char *oldpath, const char *newpath)
   if (has_dot_last_component (oldpath, true))
     {
       oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
-      set_errno (oldpc.isdir () ? EBUSY : ENOTDIR);
+      set_errno (oldpc.isdir () ? EINVAL : ENOTDIR);
       goto out;
     }
   if (has_dot_last_component (newpath, true))
     {
       newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
-      set_errno (!newpc.exists () ? ENOENT : newpc.isdir () ? EBUSY : ENOTDIR);
+      set_errno (!newpc.exists () ? ENOENT : newpc.isdir () ? EINVAL : ENOTDIR);
       goto out;
     }

@@ -1701,6 +1698,11 @@ rename (const char *oldpath, const char *newpath)
   nlen = strlen (newpath);
   if (isdirsep (newpath[nlen - 1]))
     {
+      if (!oldpc.isdir())
+	{
+	  set_errno (ENOTDIR);
+	  goto out;
+	}
       stpcpy (newbuf = tp.c_get (), newpath);
       while (nlen > 0 && isdirsep (newbuf[nlen - 1]))
 	newbuf[--nlen] = '\0';
@@ -1718,7 +1720,7 @@ rename (const char *oldpath, const char *newpath)
       set_errno (EROFS);
       goto out;
     }
-  if (new_dir_requested && !newpc.isdir ())
+  if (new_dir_requested && newpc.exists() && !newpc.isdir ())
     {
       set_errno (ENOTDIR);
       goto out;
-- 
1.6.5.rc1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]