]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/mach/hurd/getcwd.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / mach / hurd / getcwd.c
index a167730a0ad9f7abf14fa294ffe854c83fb7c970..1b9381d55efee45d1cb5bb11b17f6b999cbc4c1c 100644 (file)
@@ -1,20 +1,19 @@
-/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
 #include <sys/types.h>
@@ -33,21 +32,24 @@ Cambridge, MA 02139, USA.  */
    in SIZE bytes of BUF.  Returns NULL if the directory couldn't be
    determined or SIZE was too small.  If successful, returns BUF.  In GNU,
    if BUF is NULL, an array is allocated with `malloc'; the array is SIZE
-   bytes long, unless SIZE <= 0, in which case it is as big as necessary.  */
+   bytes long, unless SIZE <= 0, in which case it is as big as necessary.
+   If our root directory cannot be reached, the result will not begin with
+   a slash to indicate that it is relative to some unknown root directory.  */
 
 char *
-_hurd_canonicalize_directory_name_internal (file_t thisdir,
+__hurd_canonicalize_directory_name_internal (file_t thisdir,
                                            char *buf,
                                            size_t size)
 {
   error_t err;
   mach_port_t rootid, thisid, rootdevid, thisdevid;
-  ino_t rootino, thisino;
+  ino64_t rootino, thisino;
   char *file_name;
-  register char *file_namep;
+  char *file_namep;
   file_t parent;
   char *dirbuf = NULL;
   unsigned int dirbufsize = 0;
+  const size_t orig_size = size;
 
   inline void cleanup (void)
     {
@@ -57,7 +59,6 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
       __mach_port_deallocate (__mach_task_self (), thisid);
       __mach_port_deallocate (__mach_task_self (), thisdevid);
       __mach_port_deallocate (__mach_task_self (), rootid);
-      __mach_port_deallocate (__mach_task_self (), rootdevid);
 
       if (dirbuf != NULL)
        __vm_deallocate (__mach_task_self (),
@@ -65,7 +66,7 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
     }
 
 
-  if (size == 0)
+  if (size <= 0)
     {
       if (buf != NULL)
        {
@@ -110,13 +111,13 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
         THISID, THISDEV, and THISINO are its identity.
         Look in its parent (..) for a file with the same file number.  */
 
-      struct dirent *d;
+      struct dirent64 *d;
       mach_port_t dotid, dotdevid;
-      ino_t dotino;
+      ino64_t dotino;
       int mount_point;
       file_t newp;
       char *dirdata;
-      unsigned int dirdatasize;
+      size_t dirdatasize;
       int direntry, nentries;
 
 
@@ -128,13 +129,20 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
        __mach_port_deallocate (__mach_task_self (), parent);
       parent = newp;
 
-      /* Get this directory's identity and figure out if it's a mount point. */
+      /* Get this directory's identity and figure out if it's a mount
+         point.  */
       if (err = __io_identity (parent, &dotid, &dotdevid, &dotino))
        goto errlose;
-      __mach_port_deallocate (__mach_task_self (), dotid);
-      __mach_port_deallocate (__mach_task_self (), dotdevid);
       mount_point = dotdevid != thisdevid;
 
+      if (thisid == dotid)
+       {
+         /* `..' == `.' but it is not our root directory.  */
+         __mach_port_deallocate (__mach_task_self (), dotid);
+         __mach_port_deallocate (__mach_task_self (), dotdevid);
+         break;
+       }
+
       /* Search for the last directory.  */
       direntry = 0;
       dirdata = dirbuf;
@@ -166,7 +174,7 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
          offset = 0;
          while (offset < dirdatasize)
            {
-             d = (struct dirent *) &dirdata[offset];
+             d = (struct dirent64 *) &dirdata[offset];
              offset += d->d_reclen;
 
              /* Ignore `.' and `..'.  */
@@ -180,13 +188,13 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
                  file_t try = __file_name_lookup_under (parent, d->d_name,
                                                         O_NOLINK, 0);
                  file_t id, devid;
-                 ino_t fileno;
+                 ino64_t fileno;
                  if (try == MACH_PORT_NULL)
                    goto lose;
                  err = __io_identity (try, &id, &devid, &fileno);
                  __mach_port_deallocate (__mach_task_self (), try);
                  if (err)
-                   goto errlose;
+                   goto inner_errlose;
                  __mach_port_deallocate (__mach_task_self (), id);
                  __mach_port_deallocate (__mach_task_self (), devid);
                  if (id == thisid)
@@ -196,14 +204,19 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
        }
 
       if (err)
-       goto errlose;
+       {
+       inner_errlose:          /* Goto ERRLOSE: after cleaning up.  */
+         __mach_port_deallocate (__mach_task_self (), dotid);
+         __mach_port_deallocate (__mach_task_self (), dotdevid);
+         goto errlose;
+       }
       else if (nentries == 0)
        {
          /* We got to the end of the directory without finding anything!
             We are in a directory that has been unlinked, or something is
             broken.  */
          err = ENOENT;
-         goto errlose;
+         goto inner_errlose;
        }
       else
       found:
@@ -212,7 +225,7 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
 
          if (file_namep - file_name < d->d_namlen + 1)
            {
-             if (buf != NULL)
+             if (orig_size > 0)
                {
                  errno = ERANGE;
                  return NULL;
@@ -226,8 +239,12 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
                      free (file_name);
                      return NULL;
                    }
-                 file_namep = &buf[file_namep - file_name];
+                 file_namep = &buf[file_namep - file_name + size / 2];
                  file_name = buf;
+                 /* Move current contents up to the end of the buffer.
+                    This is guaranteed to be non-overlapping.  */
+                 memcpy (file_namep, file_namep - size / 2,
+                         file_name + size - file_namep);
                }
            }
          file_namep -= d->d_namlen;
@@ -249,6 +266,11 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
        So the root is our current directory.  */
     *--file_namep = '/';
 
+  if (thisid != rootid)
+    /* We did not get to our root directory. The returned name should
+       not begin with a slash.  */
+    ++file_namep;
+
   memmove (file_name, file_namep, file_name + size - file_namep);
   cleanup ();
   return file_name;
@@ -260,18 +282,17 @@ _hurd_canonicalize_directory_name_internal (file_t thisdir,
   cleanup ();
   return NULL;
 }
+strong_alias (__hurd_canonicalize_directory_name_internal, _hurd_canonicalize_directory_name_internal)
 
 char *
-__canonicalize_directory_name_internal (thisdir, buf, size)
-     const char *thisdir;
-     char *buf;
-     size_t size;
+__canonicalize_directory_name_internal (const char *thisdir, char *buf,
+                                       size_t size)
 {
   char *result;
   file_t port = __file_name_lookup (thisdir, 0, 0);
   if (port == MACH_PORT_NULL)
     return NULL;
-  result = _hurd_canonicalize_directory_name_internal (port, buf, size);
+  result = __hurd_canonicalize_directory_name_internal (port, buf, size);
   __mach_port_deallocate (__mach_task_self (), port);
   return result;
 }
@@ -284,8 +305,17 @@ __canonicalize_directory_name_internal (thisdir, buf, size)
 char *
 __getcwd (char *buf, size_t size)
 {
-  return __USEPORT (CWDIR,
-                   _hurd_canonicalize_directory_name_internal (port,
-                                                               buf, size));
+  char *cwd =
+    __USEPORT (CWDIR,
+              __hurd_canonicalize_directory_name_internal (port,
+                                                           buf, size));
+  if (cwd && cwd[0] != '/')
+    {
+      /* `cwd' is an unknown root directory.  */
+      if (buf == NULL)
+         free (cwd);
+      return __hurd_fail (EGRATUITOUS), NULL;
+    }
+  return cwd;
 }
 weak_alias (__getcwd, getcwd)