-/* 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>
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)
{
__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 (),
}
- if (size == 0)
+ if (size <= 0)
{
if (buf != NULL)
{
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;
__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;
offset = 0;
while (offset < dirdatasize)
{
- d = (struct dirent *) &dirdata[offset];
+ d = (struct dirent64 *) &dirdata[offset];
offset += d->d_reclen;
/* Ignore `.' and `..'. */
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)
}
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:
if (file_namep - file_name < d->d_namlen + 1)
{
- if (buf != NULL)
+ if (orig_size > 0)
{
errno = ERANGE;
return NULL;
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;
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;
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;
}
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)