#include "cygerrno.h"
#include "fhandler.h"
#include "path.h"
-#include "thread.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "shared_info.h"
#include "registry.h"
#include "security.h"
+#include <assert.h>
static int normalize_win32_path (const char *src, char *dst);
static void slashify (const char *src, char *dst, int trailing_slash_p);
char path_copy[MAX_PATH];
char tmp_buf[MAX_PATH];
symlink_info sym;
+ bool need_directory = 0;
char *rel_path, *full_path;
for (;;)
{
MALLOC_CHECK;
+ assert (src);
+ char *p = strrchr (src, '/');
+ if (p)
+ {
+ if (p[1] == '\0' || strcmp (p, "/.") == 0)
+ need_directory = 1;
+ }
+ else if ((p = strrchr (src, '\\')) &&
+ (p[1] == '\0' || strcmp (p, "\\.") == 0))
+ need_directory = 1;
/* Must look up path in mount table, etc. */
error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
full_path,
these operations again on the newly derived path. */
else if (len > 0)
{
- if (component == 0 && !(opt & PC_SYM_FOLLOW))
+ if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
{
set_symlink (); // last component of path is a symlink.
fileattr = sym.fileattr;
}
/* Copy tail of full_path to discovered symlink. */
- char *p;
for (p = sym.contents + buflen; *tail; tail++)
*p++ = *tail == '\\' ? '/' : *tail;
*p = '\0';
}
out:
+ /* Deal with Windows stupidity which considers filename\. to be valid
+ even when "filename" is not a directory. */
+ if (!need_directory || error)
+ /* nothing to do */;
+ else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
+ path_flags &= ~PATH_SYMLINK;
+ else
+ {
+ debug_printf ("%s is a non-directory", path);
+ error = ENOTDIR;
+ return;
+ }
DWORD serial, volflags;
strcpy (tmp_buf, full_path);
"nul",
"\\dev\\zero",
"\\dev\\%srandom",
+ "\\dev\\mem",
+ "\\dev\\clipboard",
};
static int
devn = FH_RANDOM;
unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
}
+ else if (deveq ("mem"))
+ {
+ devn = FH_MEM;
+ unit = 1;
+ }
+ else if (deveq ("clipboard"))
+ devn = FH_CLIPBOARD;
+ else if (deveq ("port"))
+ {
+ devn = FH_MEM;
+ unit = 4;
+ }
else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
devn = FH_SERIAL;
else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
}
if (!isslash (src[0]))
{
- char cwd[MAX_PATH];
- if (!cygcwd.get (cwd))
+ if (!cygcwd.get (dst))
return get_errno ();
- if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
+ if (strlen (dst) + 1 + strlen (src) >= MAX_PATH)
{
debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
return ENAMETOOLONG;
}
- strcpy (dst, cwd);
dst = strchr (dst, '\0');
if (*src == '.')
- {
- if (dst == dst_start + 1)
- dst--;
- goto sawdot;
- }
+ goto sawdot;
if (dst > dst_start && !isslash (dst[-1]))
*dst++ = '/';
}
if (src[1] != '.')
{
if (!src[1])
- goto done;
+ {
+ if (dst == dst_start)
+ *dst++ = '/';
+ goto done;
+ }
if (!isslash (src[1]))
break;
}
if (!SLASH_P (src[0]) && strchr (src, ':') == NULL)
{
- char cwd[MAX_PATH];
- if (!cygcwd.get (cwd, 0))
+ if (!cygcwd.get (dst, 0))
return get_errno ();
- if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
+ if (strlen (dst) + 1 + strlen (src) >= MAX_PATH)
{
debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
return ENAMETOOLONG;
}
- strcpy (dst, cwd);
dst += strlen (dst);
- if (!*cwd || !SLASH_P (dst[-1]))
+ if (!SLASH_P (dst[-1]))
*dst++ = '\\';
}
/* Two leading \'s? If so, preserve them. */
dst[len++] = '\000';
else
{
+ int n;
dst[len++] = '/';
- strcpy (dst + len, src + 3);
+ if (SLASH_P (src[2]))
+ n = 3;
+ else
+ n = 2;
+ strcpy (dst + len, src + n);
}
slashify (dst, dst, trailing_slash_p);
}
char posix_path[MAX_PATH];
HKEY key = r.get_key ();
DWORD i, posix_path_size;
- int found_cygdrive = FALSE;
+ int res;
/* Loop through subkeys */
/* FIXME: we would like to not check MAX_MOUNTS but the heap in the
shared area is currently statically allocated so we can't have an
arbitrarily large number of mounts. */
- for (DWORD i = 0; ; i++)
+ for (i = 0; ; i++)
{
char native_path[MAX_PATH];
int mount_flags;
/* FIXME: if maximum posix_path_size is 256, we're going to
run into problems if we ever try to store a mount point that's
over 256 but is under MAX_PATH! */
- LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
+ res = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
NULL, NULL, NULL);
- if (err == ERROR_NO_MORE_ITEMS)
+ if (res == ERROR_NO_MORE_ITEMS)
break;
- else if (err != ERROR_SUCCESS)
+ else if (res != ERROR_SUCCESS)
{
- debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
+ debug_printf ("RegEnumKeyEx failed, error %d!\n", res);
break;
}
- if (iscygdrive (posix_path))
- {
- found_cygdrive = TRUE;
- continue;
- }
-
/* Get a reg_key based on i. */
reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
mount_flags = subkey.get_int ("flags", 0);
/* Add mount_item corresponding to registry mount point. */
- int res = cygwin_shared->mount.add_item (native_path, posix_path, mount_flags, FALSE);
+ res = cygwin_shared->mount.add_item (native_path, posix_path, mount_flags, FALSE);
if (res && get_errno () == EMFILE)
break; /* The number of entries exceeds MAX_MOUNTS */
}
-
- if (!found_cygdrive)
- return;
-
-loop:
- for (i = 0; ;i++)
- {
- posix_path_size = MAX_PATH;
- LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
- NULL, NULL, NULL);
-
- if (err != ERROR_SUCCESS)
- break;
-
- if (iscygdrive (posix_path))
- {
- /* This shouldn't be in the mount table. */
- (void) r.kill (posix_path);
- goto loop;
- }
- }
}
/* from_registry: Build the entire mount table from the registry. Also,
int
mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
{
+ int res = 0;
+
/* Add the mount to the right registry location, depending on
whether MOUNT_SYSTEM is set in the mount flags. */
if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
reg_key reg_user;
/* Start by deleting existing mount if one exists. */
- reg_user.kill (posix_path);
+ res = reg_user.kill (posix_path);
+ if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
+ goto err;
/* Create the new mount. */
reg_key subkey = reg_key (reg_user.get_key (),
KEY_ALL_ACCESS,
posix_path, NULL);
- subkey.set_string ("native", native_path);
- subkey.set_int ("flags", mountflags);
+ res = subkey.set_string ("native", native_path);
+ if (res != ERROR_SUCCESS)
+ goto err;
+ res = subkey.set_int ("flags", mountflags);
}
else /* local_machine mount */
{
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
- if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
- {
- set_errno (EACCES);
- return -1;
- }
-
/* Start by deleting existing mount if one exists. */
- reg_sys.kill (posix_path);
+ res = reg_sys.kill (posix_path);
+ if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
+ goto err;
/* Create the new mount. */
reg_key subkey = reg_key (reg_sys.get_key (),
KEY_ALL_ACCESS,
posix_path, NULL);
- subkey.set_string ("native", native_path);
- subkey.set_int ("flags", mountflags);
+ res = subkey.set_string ("native", native_path);
+ if (res != ERROR_SUCCESS)
+ goto err;
+ res = subkey.set_int ("flags", mountflags);
}
return 0; /* Success! */
+ err:
+ __seterrno_from_win_error (res);
+ return -1;
}
/* del_reg_mount: delete mount item from registry indicated in flags.
int
mount_info::del_reg_mount (const char * posix_path, unsigned flags)
{
- int killres;
+ int res;
if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
{
reg_key reg_user (KEY_ALL_ACCESS,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
- killres = reg_user.kill (posix_path);
+ res = reg_user.kill (posix_path);
}
else /* Delete from system registry */
{
CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
-
- if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
- {
- set_errno (EACCES);
- return -1;
- }
-
- killres = reg_sys.kill (posix_path);
+ res = reg_sys.kill (posix_path);
}
- if (killres != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS)
{
- __seterrno_from_win_error (killres);
+ __seterrno_from_win_error (res);
return -1;
}
/* Ensure that there is never a final slash */
nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
- r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
+ int res;
+ res = r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
+ if (res != ERROR_SUCCESS)
+ {
+ __seterrno_from_win_error (res);
+ return -1;
+ }
r.set_int ("cygdrive flags", flags);
/* This also needs to go in the in-memory copy of "cygdrive", but only if
if ((native == NULL) || (*native == 0) ||
(posix == NULL) || (*posix == 0) ||
- (!slash_unc_prefix_p (native) && !isabspath (native)))
+ !isabspath (native) || !isabspath (posix) ||
+ slash_unc_prefix_p (posix) || isdrive (posix))
{
set_errno (EINVAL);
return -1;
break;
}
- if (i == nmounts)
+ if (i == nmounts && nmounts == MAX_MOUNTS)
{
- if (nmounts < MAX_MOUNTS)
- i = nmounts++;
- else
- {
- set_errno (EMFILE);
- return -1;
- }
+ set_errno (EMFILE);
+ return -1;
}
if (reg_p && add_reg_mount (nativetmp, posixtmp, mountflags))
return -1;
+ if (i == nmounts)
+ nmounts++;
mount[i].init (nativetmp, posixtmp, mountflags);
sort ();
win32_path = NULL;
}
else
- {
- if (iscygdrive (posix_path))
- {
- set_errno (EINVAL);
- return res; /* Don't try to add cygdrive prefix. */
- }
-
- res = cygwin_shared->mount.add_item (win32_path, posix_path, flags, TRUE);
- }
+ res = cygwin_shared->mount.add_item (win32_path, posix_path, flags, TRUE);
syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
return res;
goto done;
}
- h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
+ h = CreateFileA(win32_path, GENERIC_WRITE, 0, &sec_none_nih,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
__seterrno ();
static __inline char *
has_suffix (const char *path, const suffix_info *suffixes)
{
+ assert (path);
char *ext = strrchr (path, '.');
if (ext)
for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
continue;
}
- /* Windows allows path\. even when `path' isn't a directory.
- Detect this scenario and disallow it, since it is non-UNIX like.
- FIXME: This code actually checks for things like foo/ and foo/..
- even though those usages have already been (erroneously?) eaten
- by cygwin_shared->mount.conv_to_win32_path in path_conv::check. */
-
- char *p = strrchr (path, '\\');
- if (p && !(fileattr & FILE_ATTRIBUTE_DIRECTORY) &&
- (*++p == '\0' || (*p == '.' && (*++p == '\0' || (*p == '.' && p[1] == '\0')))))
- {
- debug_printf ("%s is a non-directory", path);
- error = ENOTDIR;
- goto file_not_symlink;
- }
-
/* A symlink will have the `system' file attribute. */
/* Only files can be symlinks (which can be symlinks to directories). */
if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
else
{
/* Not a symlink, see if executable. */
- if (!(pflags & (PATH_EXEC | PATH_CYGWIN_EXEC)) && got >= 2 &&
+ if (!(pflags & PATH_ALL_EXEC) && got >= 2 &&
((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
- (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
+ (cookie_buf[0] == ':' && cookie_buf[1] == '\n') ||
+ (cookie_buf[0] == 'M' && cookie_buf[1] == 'Z')))
pflags |= PATH_EXEC;
close_and_return:
CloseHandle (h);
{
char *nn, *newname = (char *) alloca (strlen (name) + 2);
nn = strncpy (newname, name, 2);
- if (islower (*nn))
- *newname = toupper (*nn);
+ if (isupper (*nn))
+ *newname = tolower (*nn);
*(nn += 2) = '\0';
name += 2;
if (*name != '\\')
Otherwise the inodes same will differ depending on whether a file is
referenced with an absolute value or relatively. */
- if (*name != '\\')
+ if (!hash && !isabspath (name))
{
hash = cygcwd.get_hash ();
if (name[0] == '.' && name[1] == '\0')
return hash;
- hash = hash_path_name (hash, "\\");
+ hash += hash_path_name (hash, "\\");
}
}
\a\b\. but allow a single \ if that's all there is. */
do
{
- hash += *name + (*name << 17);
+ int ch = tolower(*name);
+ hash += ch + (ch << 17);
hash ^= hash >> 2;
}
while (*++name != '\0' &&
char *
getcwd (char *buf, size_t ulen)
{
- char *res;
- char *usebuf, uselen;
-
- if (buf != NULL)
- {
- usebuf = buf;
- uselen = TRUE;
- }
- else
- {
- if (ulen >= 0)
- uselen = TRUE;
- else
- {
- uselen = FALSE;
- ulen = MAX_PATH + 1;
- }
-
- usebuf = (char *) malloc (ulen);
- usebuf [ulen - 1] = '\0';
- }
-
- res = cygcwd.get (usebuf, 1, 1, ulen);
-
- if (res && !uselen)
- usebuf = (char *) realloc (usebuf, strlen (usebuf) + 1);
- else if (!res && buf == NULL)
- free (usebuf);
-
- return res;
+ return cygcwd.get (buf, 1, 1, ulen);
}
/* getwd: standards? */
int
chdir (const char *dir)
{
+ MALLOC_CHECK;
syscall_printf ("dir %s", dir);
path_conv path (dir, PC_FULL | PC_SYM_FOLLOW);
it was worth locking just for strace. */
syscall_printf ("%d = chdir() cygcwd.posix '%s' native '%s'", res,
cygcwd.posix, native_dir);
+ MALLOC_CHECK;
return res;
}
})
/* Return TRUE if two strings match up to length n */
-int __stdcall
+extern "C" int __stdcall
strncasematch (const char *s1, const char *s2, size_t n)
{
if (s1 == s2)
}
/* Return TRUE if two strings match */
-int __stdcall
+extern "C" int __stdcall
strcasematch (const char *s1, const char *s2)
{
if (s1 == s2)
return *s2 == '\0';
}
-char * __stdcall
+extern "C" char * __stdcall
strcasestr (const char *searchee, const char *lookfor)
{
if (*searchee == 0)
bool
cwdstuff::get_initial ()
{
+ lock->acquire ();
+
if (win32)
return 1;
- lock->acquire ();
int i;
DWORD len, dlen;
for (i = 0, dlen = MAX_PATH, len = 0; i < 3; dlen *= 2, i++)
__seterrno ();
lock->release ();
debug_printf ("get_initial_cwd failed, %E");
+ lock->release ();
return 0;
}
set (NULL);
char *
cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
{
- size_t len = ulen;
+ MALLOC_CHECK;
+
+ if (ulen == 0)
+ {
+ set_errno (EINVAL);
+ goto out;
+ }
if (!get_initial ()) /* Get initial cwd and set cwd lock */
return NULL;
}
else
{
+ if (!buf)
+ buf = (char *) malloc (strlen (tocopy) + 1);
strcpy (buf, tocopy);
if (!buf[0]) /* Should only happen when chroot */
strcpy (buf, "/");
}
lock->release ();
- syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d)",
- buf, buf, len, need_posix, with_chroot);
+
+out:
+ syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
+ buf, buf, ulen, need_posix, with_chroot, errno);
+ MALLOC_CHECK;
return buf;
}
posix_cwd = cstrdup (posix);
win32_cwd = cstrdup (win32);
hash_cwd = hash;
+ MALLOC_CHECK;
lock->release ();
}