This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
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