mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-18 23:12:15 +08:00
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.
This commit is contained in:
parent
1e6459d3e5
commit
52dba6a5c4
@ -1,3 +1,15 @@
|
||||
2009-09-26 Eric Blake <ebb9@byu.net>
|
||||
|
||||
* 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.
|
||||
|
||||
2009-09-25 Eric Blake <ebb9@byu.net>
|
||||
|
||||
* syscalls.cc (fchmodat): lchmod is not yet implemented.
|
||||
|
@ -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,
|
||||
2008, 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,30 @@ mkdir (const char *dir, mode_t mode)
|
||||
{
|
||||
int res = -1;
|
||||
fhandler_base *fh = NULL;
|
||||
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. */
|
||||
|
||||
if (!*dir)
|
||||
{
|
||||
set_errno (ENOENT);
|
||||
goto done;
|
||||
}
|
||||
if (isdirsep (dir[strlen (dir) - 1]))
|
||||
{
|
||||
/* This converts // to /, but since both give EEXIST, we're okay. */
|
||||
char *buf;
|
||||
char *p = stpcpy (buf = tp.c_get (), dir) - 1;
|
||||
dir = buf;
|
||||
while (p > dir && isdirsep (*p))
|
||||
*p-- = '\0';
|
||||
}
|
||||
if (!(fh = build_fh_name (dir, NULL, PC_SYM_NOFOLLOW)))
|
||||
goto done; /* errno already set */;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1186,7 +1186,8 @@ fhandler_disk_file::ftruncate (_off64_t length, bool allow_truncate)
|
||||
int
|
||||
fhandler_disk_file::link (const char *newpath)
|
||||
{
|
||||
path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
||||
size_t nlen = strlen (newpath);
|
||||
path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX | PC_NULLEMPTY, stat_suffixes);
|
||||
if (newpc.error)
|
||||
{
|
||||
set_errno (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 ())
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user