#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 == '.')
goto sawdot;
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);
}
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 ();
}