From: Paul Eggert Date: Fri, 6 Aug 2004 06:29:11 +0000 (+0000) Subject: New getcwd module, imported from coreutils. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7c232d6b1cfc23376954f517f6d6773aa3f52eda;p=pspp New getcwd module, imported from coreutils. --- diff --git a/lib/getcwd.c b/lib/getcwd.c new file mode 100644 index 0000000000..3d63f04809 --- /dev/null +++ b/lib/getcwd.c @@ -0,0 +1,69 @@ +/* Provide a replacement for the POSIX getcwd function. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* written by Jim Meyering */ + +#include + +#include +#include +#include +#include + +#include "pathmax.h" +#include "same.h" + +/* Guess high, because that makes the test below more conservative. + But this is a kludge, because we should really use + pathconf (".", _PC_NAME_MAX). But it's probably not worth the cost. */ +#define KLUDGE_POSIX_NAME_MAX 255 + +#define MAX_SAFE_LEN (PATH_MAX - 1 - KLUDGE_POSIX_NAME_MAX - 1) + +/* Undefine getcwd here, as near the use as possible, in case any + of the files included above define it to rpl_getcwd. */ +#undef getcwd + +/* Any declaration of getcwd from headers included above has + been changed to a declaration of rpl_getcwd. Declare it here. */ +extern char *getcwd (char *buf, size_t size); + +/* This is a wrapper for getcwd. + Some implementations (at least GNU libc 2.3.1 + linux-2.4.20) return + non-NULL for a working directory name longer than PATH_MAX, yet the + returned string is a strict prefix of the desired directory name. + Upon such a failure, free the offending string, set errno to + ENAMETOOLONG, and return NULL. + + I've heard that this is a Linux kernel bug, and that it has + been fixed between 2.4.21-pre3 and 2.4.21-pre4. */ + +char * +rpl_getcwd (char *buf, size_t size) +{ + char *cwd = getcwd (buf, size); + + if (cwd == NULL) + return NULL; + + if (strlen (cwd) <= MAX_SAFE_LEN || same_name (cwd, ".")) + return cwd; + + free (cwd); + errno = ENAMETOOLONG; + return NULL; +} diff --git a/m4/getcwd-path-max.m4 b/m4/getcwd-path-max.m4 new file mode 100644 index 0000000000..a1e123976b --- /dev/null +++ b/m4/getcwd-path-max.m4 @@ -0,0 +1,150 @@ +#serial 4 +# Check whether getcwd has the bug that it succeeds for a working directory +# longer than PATH_MAX, yet returns a truncated directory name. +# If so, arrange to compile the wrapper function. + +# This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20. +# I've heard that this is due to a Linux kernel bug, and that it has +# been fixed between 2.4.21-pre3 and 2.4.21-pre4. */ + +# Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# From Jim Meyering + +AC_DEFUN([GL_FUNC_GETCWD_PATH_MAX], +[ + AC_CHECK_DECLS([getcwd]) + AC_CACHE_CHECK([whether getcwd properly handles paths longer than PATH_MAX], + gl_cv_func_getcwd_vs_path_max, + [ + # Arrange for deletion of the temporary directory this test creates. + ac_clean_files="$ac_clean_files confdir3" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +#include +#include +#include + +/* Don't get link errors because mkdir is redefined to rpl_mkdir. */ +#undef mkdir + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +#ifndef INT_MAX +# define INT_MAX TYPE_MAXIMUM (int) +#endif + +/* The length of this name must be 8. */ +#define DIR_NAME "confdir3" + +int +main () +{ +#ifndef PATH_MAX + /* The Hurd doesn't define this, so getcwd can't exhibit the bug -- + at least not on a local file system. And if we were to start worrying + about remote file systems, we'd have to enable the wrapper function + all of the time, just to be safe. That's not worth the cost. */ + exit (0); +#elif INT_MAX - 9 <= PATH_MAX + /* The '9', above, comes from strlen (DIR_NAME) + 1. */ + /* FIXME: Assuming there's a system for which this is true, + this should be done in a compile test. */ + exit (0); +#else + char buf[PATH_MAX + 20]; + char *cwd = getcwd (buf, PATH_MAX); + size_t cwd_len; + int fail = 0; + size_t n_chdirs = 0; + + if (cwd == NULL) + exit (1); + + cwd_len = strlen (cwd); + + while (1) + { + char *c; + size_t len; + + cwd_len += 1 + strlen (DIR_NAME); + /* If mkdir or chdir fails, be pessimistic and consider that + as a failure, too. */ + if (mkdir (DIR_NAME, 0700) < 0 || chdir (DIR_NAME) < 0) + { + fail = 1; + break; + } + if ((c = getcwd (buf, PATH_MAX)) == NULL) + { + /* This allows any failure to indicate there is no bug. + FIXME: check errno? */ + break; + } + if ((len = strlen (c)) != cwd_len) + { + fail = 1; + break; + } + ++n_chdirs; + if (PATH_MAX < len) + break; + } + + /* Leaving behind such a deep directory is not polite. + So clean up here, right away, even though the driving + shell script would also clean up. */ + { + size_t i; + + /* Unlink first, in case the chdir failed. */ + unlink (DIR_NAME); + for (i = 0; i <= n_chdirs; i++) + { + if (chdir ("..") < 0) + break; + rmdir (DIR_NAME); + } + } + + exit (fail); +#endif +} + ]])], + [gl_cv_func_getcwd_vs_path_max=yes], + [gl_cv_func_getcwd_vs_path_max=no], + [gl_cv_func_getcwd_vs_path_max=no])]) + + if test $gl_cv_func_getcwd_vs_path_max = no; then + AC_LIBOBJ(getcwd) + AC_DEFINE(getcwd, rpl_getcwd, + [Define to rpl_getcwd if the wrapper function should be used.]) + fi +]) diff --git a/modules/getcwd b/modules/getcwd new file mode 100644 index 0000000000..d5b38a4469 --- /dev/null +++ b/modules/getcwd @@ -0,0 +1,21 @@ +Description: +Return the current working directory. + +Files: +lib/getcwd.c +m4/getcwd-path-max.m4 + +Depends-on: +pathmax +same + +configure.ac: +GL_FUNC_GETCWD_PATH_MAX + +Makefile.am: + +Include: + +Maintainer: +Jim Meyering +