[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: question about getcwd

From: Jim Meyering
Subject: Re: question about getcwd
Date: Mon, 19 Feb 2007 21:09:00 +0100

Bruno Haible <address@hidden> wrote:
> Does the following accurately describe the behaviour of getcwd() in gnulib?
> I'm asking because lib/getcwd.c mentions a certain GNU extension, whereas
> lib/getcwd.h merely refers to the POSIX spec.
> /* Get the name of the current working directory, and put it in SIZE bytes
>    of BUF.
>    Return BUF if successful, or NULL if the directory couldn't be determined
>    or SIZE was too small.
>    See the POSIX:2001 specification
>    <http://www.opengroup.org/susv3xsh/getcwd.html>.
>    Additionally, the gnulib module 'getcwd' guarantees the following GNU
>    extension: 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.  */
> extern char * getcwd (char *buf, size_t size);

It omits an important detail:
Unlike most other getcwd implementations, this one may *potentially*
return a name that is arbitrarily long (and hence much longer than PATH_MAX).

Currently that doesn't ever happen because the only systems
that have openat support also have a mostly-working getcwd,
and *it* imposes the PATH_MAX maximum.

However, if a system were to have a getcwd that fails the mostly-working
test and does have openat support (or if you just include "openat.h"
near the top of getcwd.c to use /proc-based openat emulation), then
the replacement getcwd function can return a very long name.  I've just
tested it using the following patch:

  [note the addition of the dirfd call -- otherwise, it didn't work at all;
   the fdopendir call would end up closing fd.  I've just checked in that
   latter hunk. ]

Index: getcwd.c
RCS file: /sources/gnulib/gnulib/lib/getcwd.c,v
retrieving revision 1.19
diff -u -p -r1.19 getcwd.c
--- getcwd.c    19 Feb 2007 02:24:42 -0000      1.19
+++ getcwd.c    19 Feb 2007 19:36:04 -0000
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 #include <stddef.h>

+#include "openat.h"
 #include <fcntl.h> /* For AT_FDCWD on Solaris 9.  */

 #ifndef __set_errno
@@ -234,6 +235,7 @@ __getcwd (char *buf, size_t size)
       dirstream = fdopendir (fd);
       if (dirstream == NULL)
        goto lose;
+      fd = dirfd (dirstream);
       fd_needs_closing = false;
       dirstream = __opendir (dotlist);

and the following main program:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include "error.h"
  char *t = getcwd (0, 0);
  if (t == NULL)
    error (1, errno, "getcwd failed");
  printf ("%s\n", t);
  free (t);
  return 0;
Running it from the bottom of a hierarchy 20001 levels deep, with
each directory having a 1-letter name, I get this:

    $ z-run /cu/lib/a.out|wc -c

That is why save-cwd.c uses chdir_long (not chdir) to process
a name returned by getcwd.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]