Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <eblake@redhat.com>2009-09-26 19:51:53 +0400
committerEric Blake <eblake@redhat.com>2009-09-26 19:51:53 +0400
commit52dba6a5c45e8d8ba1e237a15213311dc11d91fb (patch)
tree58e8c9e0fea63d08c7f3e63ba3956e3196403d94 /winsup/cygwin/syscalls.cc
parent1e6459d3e5248a8253e73b602615820d14ee6483 (diff)
Fix some POSIX-compliance bugs in link, rename, mkdir.
* syscalls.cc (link): Delete obsolete comment. Reject directories and missing source up front. (rename): Use correct errno for trailing '.'. Detect empty strings. 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.
Diffstat (limited to 'winsup/cygwin/syscalls.cc')
-rw-r--r--winsup/cygwin/syscalls.cc103
1 files changed, 65 insertions, 38 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index da9cda507..94410fed3 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);
@@ -1651,7 +1648,6 @@ rename (const char *oldpath, const char *newpath)
{
tmp_pathbuf tp;
int res = -1;
- char *oldbuf, *newbuf;
path_conv oldpc, newpc, new2pc, *dstpc, *removepc = NULL;
bool old_dir_requested = false, new_dir_requested = false;
bool old_explicit_suffix = false, new_explicit_suffix = false;
@@ -1670,16 +1666,21 @@ rename (const char *oldpath, const char *newpath)
if (efault.faulted (EFAULT))
return -1;
+ if (!*oldpath || !*newpath)
+ {
+ set_errno (ENOENT);
+ goto out;
+ }
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;
}
@@ -1689,10 +1690,20 @@ rename (const char *oldpath, const char *newpath)
olen = strlen (oldpath);
if (isdirsep (oldpath[olen - 1]))
{
- stpcpy (oldbuf = tp.c_get (), oldpath);
- while (olen > 0 && isdirsep (oldbuf[olen - 1]))
- oldbuf[--olen] = '\0';
- oldpath = oldbuf;
+ 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;
+ }
old_dir_requested = true;
}
oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
@@ -1724,10 +1735,17 @@ rename (const char *oldpath, const char *newpath)
nlen = strlen (newpath);
if (isdirsep (newpath[nlen - 1]))
{
- stpcpy (newbuf = tp.c_get (), newpath);
- while (nlen > 0 && isdirsep (newbuf[nlen - 1]))
- newbuf[--nlen] = '\0';
- newpath = newbuf;
+ 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. */
+ {
+ set_errno (ENOTEMPTY);
+ goto out;
+ }
new_dir_requested = true;
}
newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
@@ -1741,9 +1759,22 @@ rename (const char *oldpath, const char *newpath)
set_errno (EROFS);
goto out;
}
- if (new_dir_requested && !newpc.isdir ())
+ if (new_dir_requested)
{
- set_errno (ENOTDIR);
+ if (!newpc.exists())
+ {
+ set_errno (ENOENT);
+ goto out;
+ }
+ if (!newpc.isdir ())
+ {
+ set_errno (ENOTDIR);
+ goto out;
+ }
+ }
+ if (newpc.exists () && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ()))
+ {
+ set_errno (newpc.isdir () ? EISDIR : ENOTDIR);
goto out;
}
if (newpc.known_suffix
@@ -1774,22 +1805,23 @@ rename (const char *oldpath, const char *newpath)
}
else if (oldpc.isdir ())
{
- if (newpc.exists () && !newpc.isdir ())
- {
- set_errno (ENOTDIR);
- goto out;
- }
- /* Check for newpath being a subdir of oldpath. */
+ /* Check for newpath being identical or a subdir of oldpath. */
if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (),
newpc.get_nt_native_path (),
- TRUE)
- && newpc.get_nt_native_path ()->Length >
- oldpc.get_nt_native_path ()->Length
- && *(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer
- + oldpc.get_nt_native_path ()->Length) == L'\\')
+ TRUE))
{
- set_errno (EINVAL);
- goto out;
+ 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'\\')
+ {
+ set_errno (EINVAL);
+ goto out;
+ }
}
}
else if (!newpc.exists ())
@@ -1816,11 +1848,6 @@ rename (const char *oldpath, const char *newpath)
.exe suffix must be given explicitly in oldpath. */
rename_append_suffix (newpc, newpath, nlen, ".exe");
}
- else if (newpc.isdir ())
- {
- set_errno (EISDIR);
- goto out;
- }
else
{
if (equal_path && old_explicit_suffix != new_explicit_suffix)