OSDN Git Service

* fhandler_clipboard.cc: new file
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / path.cc
index 5f40ee1..63a8efd 100644 (file)
@@ -62,7 +62,6 @@ details. */
 #include "cygerrno.h"
 #include "fhandler.h"
 #include "path.h"
-#include "thread.h"
 #include "sync.h"
 #include "sigproc.h"
 #include "pinfo.h"
@@ -70,6 +69,7 @@ details. */
 #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);
@@ -168,6 +168,7 @@ path_conv::check (const char *src, unsigned opt,
   char path_copy[MAX_PATH];
   char tmp_buf[MAX_PATH];
   symlink_info sym;
+  bool need_directory = 0;
 
   char *rel_path, *full_path;
 
@@ -189,6 +190,16 @@ path_conv::check (const char *src, unsigned opt,
   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,
@@ -275,7 +286,7 @@ path_conv::check (const char *src, unsigned opt,
             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;
@@ -317,7 +328,6 @@ path_conv::check (const char *src, unsigned opt,
          }
 
       /* Copy tail of full_path to discovered symlink. */
-      char *p;
       for (p = sym.contents + buflen; *tail; tail++)
        *p++ = *tail == '\\' ? '/' : *tail;
       *p = '\0';
@@ -354,6 +364,18 @@ fillin:
     }
 
 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);
@@ -408,6 +430,8 @@ const char *windows_device_names[] =
   "nul",
   "\\dev\\zero",
   "\\dev\\%srandom",
+  "\\dev\\mem",
+  "\\dev\\clipboard",
 };
 
 static int
@@ -477,6 +501,18 @@ get_device_number (const char *name, int &unit, BOOL from_conv)
          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"))
@@ -540,15 +576,13 @@ normalize_posix_path (const char *src, char *dst)
     }
   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;
@@ -647,17 +681,15 @@ normalize_win32_path (const char *src, char *dst)
 
   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.  */
@@ -1124,8 +1156,13 @@ mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_
     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);
 }
@@ -2088,7 +2125,7 @@ symlink (const char *topath, const char *frompath)
       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 ();
@@ -2126,6 +2163,7 @@ done:
 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++)
@@ -2209,21 +2247,6 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
          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))
@@ -2277,9 +2300,10 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
          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);
@@ -2370,8 +2394,8 @@ hash_path_name (unsigned long hash, const char *name)
        {
          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 != '\\')
@@ -2389,12 +2413,12 @@ hash_path_name (unsigned long hash, const char *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, "\\");
        }
     }
 
@@ -2403,7 +2427,8 @@ hashit:
      \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' &&
@@ -2414,36 +2439,7 @@ hashit:
 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? */
@@ -2459,6 +2455,7 @@ extern "C"
 int
 chdir (const char *dir)
 {
+  MALLOC_CHECK;
   syscall_printf ("dir %s", dir);
   path_conv path (dir, PC_FULL | PC_SYM_FOLLOW);
 
@@ -2507,6 +2504,7 @@ chdir (const char *dir)
      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;
 }
 
@@ -2775,7 +2773,7 @@ cygwin_split_path (const char *path, char *dir, char *file)
     })
 
 /* 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)
@@ -2792,7 +2790,7 @@ strncasematch (const char *s1, const char *s2, size_t n)
 }
 
 /* Return TRUE if two strings match */
-int __stdcall
+extern "C" int __stdcall
 strcasematch (const char *s1, const char *s2)
 {
   if (s1 == s2)
@@ -2807,7 +2805,7 @@ strcasematch (const char *s1, const char *s2)
   return *s2 == '\0';
 }
 
-char * __stdcall
+extern "C" char * __stdcall
 strcasestr (const char *searchee, const char *lookfor)
 {
   if (*searchee == 0)
@@ -2881,10 +2879,11 @@ cwdstuff::fixup_after_exec (char *win32_cwd, char *posix_cwd, DWORD hash_cwd)
 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++)
@@ -2899,6 +2898,7 @@ cwdstuff::get_initial ()
       __seterrno ();
       lock->release ();
       debug_printf ("get_initial_cwd failed, %E");
+      lock->release ();
       return 0;
     }
   set (NULL);
@@ -2940,7 +2940,13 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd)
 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;
@@ -2960,14 +2966,19 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
     }
   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;
 }
 
@@ -2980,5 +2991,6 @@ cwdstuff::copy (char * &posix_cwd, char * &win32_cwd, DWORD hash_cwd)
   posix_cwd = cstrdup (posix);
   win32_cwd = cstrdup (win32);
   hash_cwd = hash;
+  MALLOC_CHECK;
   lock->release ();
 }