Bruno Haible <[EMAIL PROTECTED]> 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; #else dirstream = __opendir (dotlist); and the following main program: #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include "error.h" int main() { 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 40003 That is why save-cwd.c uses chdir_long (not chdir) to process a name returned by getcwd.