[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;
#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.