Back to index

glibc  2.9
getcwd.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 /* Wants:
00020    AC_STDC_HEADERS
00021    AC_DIR_HEADER
00022    AC_UNISTD_H
00023    AC_MEMORY_H
00024    AC_CONST
00025    AC_ALLOCA
00026  */
00027 
00028 /* AIX requires this to be the first thing in the file.  */
00029 #if defined _AIX && !defined __GNUC__
00030  #pragma alloca
00031 #endif
00032 
00033 #ifdef HAVE_CONFIG_H
00034 # include "config.h"
00035 #endif
00036 
00037 #include <errno.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 
00041 #ifdef STDC_HEADERS
00042 # include <stddef.h>
00043 #endif
00044 
00045 #if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
00046 extern int errno;
00047 #endif
00048 #ifndef __set_errno
00049 # define __set_errno(val) errno = (val)
00050 #endif
00051 
00052 #ifndef       NULL
00053 # define NULL 0
00054 #endif
00055 
00056 #if defined USGr3 && !defined DIRENT
00057 # define DIRENT
00058 #endif /* USGr3 */
00059 #if defined Xenix && !defined SYSNDIR
00060 # define SYSNDIR
00061 #endif /* Xenix */
00062 
00063 #if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__
00064 # include <dirent.h>
00065 # ifndef __GNU_LIBRARY__
00066 #  define D_NAMLEN(d) strlen((d)->d_name)
00067 # else
00068 #  define HAVE_D_NAMLEN
00069 #  define D_NAMLEN(d) ((d)->d_namlen)
00070 # endif
00071 #else /* not POSIX or DIRENT */
00072 # define dirent             direct
00073 # define D_NAMLEN(d) ((d)->d_namlen)
00074 # define HAVE_D_NAMLEN
00075 # if defined USG && !defined sgi
00076 #  if defined SYSNDIR
00077 #   include <sys/ndir.h>
00078 #  else /* Not SYSNDIR */
00079 #   include "ndir.h"
00080 #  endif /* SYSNDIR */
00081 # else /* not USG */
00082 #  include <sys/dir.h>
00083 # endif /* USG */
00084 #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
00085 
00086 #if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
00087 # include <unistd.h>
00088 #endif
00089 
00090 #if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
00091 # include <stdlib.h>
00092 # include <string.h>
00093 # define ANSI_STRING
00094 #else  /* No standard headers.  */
00095 
00096 # ifdef       USG
00097 
00098 #  include <string.h>
00099 #  ifdef NEED_MEMORY_H
00100 #   include <memory.h>
00101 #  endif
00102 #  define     ANSI_STRING
00103 
00104 # else /* Not USG.  */
00105 
00106 #  ifdef NeXT
00107 
00108 #   include <string.h>
00109 
00110 #  else       /* Not NeXT.  */
00111 
00112 #   include <strings.h>
00113 
00114 #   ifndef bcmp
00115 extern int bcmp ();
00116 #   endif
00117 #   ifndef bzero
00118 extern void bzero ();
00119 #   endif
00120 #   ifndef bcopy
00121 extern void bcopy ();
00122 #   endif
00123 
00124 #  endif /* NeXT. */
00125 
00126 # endif       /* USG.  */
00127 
00128 extern char *malloc (), *realloc ();
00129 extern void free ();
00130 
00131 #endif /* Standard headers.  */
00132 
00133 #ifndef       ANSI_STRING
00134 # define memcpy(d, s, n)    bcopy((s), (d), (n))
00135 # define memmove memcpy
00136 #endif /* Not ANSI_STRING.  */
00137 
00138 #ifndef MAX
00139 # define MAX(a, b) ((a) < (b) ? (b) : (a))
00140 #endif
00141 
00142 #ifdef _LIBC
00143 # ifndef mempcpy
00144 #  define mempcpy __mempcpy
00145 # endif
00146 # define HAVE_MEMPCPY       1
00147 #endif
00148 
00149 #if !defined __alloca && !defined __GNU_LIBRARY__
00150 
00151 # ifdef       __GNUC__
00152 #  undef alloca
00153 #  define alloca(n)  __builtin_alloca (n)
00154 # else /* Not GCC.  */
00155 #  if  defined sparc || defined HAVE_ALLOCA_H
00156 #   include <alloca.h>
00157 #  else       /* Not sparc or HAVE_ALLOCA_H.  */
00158 #   ifndef _AIX
00159 extern char *alloca ();
00160 #   endif /* Not _AIX.  */
00161 #  endif /* sparc or HAVE_ALLOCA_H.  */
00162 # endif       /* GCC.  */
00163 
00164 # define __alloca    alloca
00165 
00166 #endif
00167 
00168 #if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
00169 # include <limits.h>
00170 #else
00171 # include <sys/param.h>
00172 #endif
00173 
00174 #ifndef PATH_MAX
00175 # ifdef       MAXPATHLEN
00176 #  define PATH_MAX MAXPATHLEN
00177 # else
00178 #  define PATH_MAX 1024
00179 # endif
00180 #endif
00181 
00182 #if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
00183 # undef       size_t
00184 # define size_t      unsigned int
00185 #endif
00186 
00187 #if !__STDC__ && !defined const
00188 # define const
00189 #endif
00190 
00191 #ifndef __GNU_LIBRARY__
00192 # define __lstat     stat
00193 #endif
00194 
00195 #ifndef _LIBC
00196 # define __getcwd getcwd
00197 #endif
00198 
00199 #ifndef GETCWD_RETURN_TYPE
00200 # define GETCWD_RETURN_TYPE char *
00201 #endif
00202 
00203 /* Get the pathname of the current working directory, and put it in SIZE
00204    bytes of BUF.  Returns NULL if the directory couldn't be determined or
00205    SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
00206    NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
00207    unless SIZE == 0, in which case it is as big as necessary.  */
00208 
00209 GETCWD_RETURN_TYPE
00210 __getcwd (buf, size)
00211      char *buf;
00212      size_t size;
00213 {
00214   static const char dots[]
00215     = "../../../../../../../../../../../../../../../../../../../../../../../\
00216 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
00217 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
00218   const char *dotp = &dots[sizeof (dots)];
00219   const char *dotlist = dots;
00220   size_t dotsize = sizeof (dots) - 1;
00221   dev_t rootdev, thisdev;
00222   ino_t rootino, thisino;
00223   char *path;
00224   register char *pathp;
00225   struct stat st;
00226   int prev_errno = errno;
00227   size_t allocated = size;
00228 
00229   if (size == 0)
00230     {
00231       if (buf != NULL)
00232        {
00233          __set_errno (EINVAL);
00234          return NULL;
00235        }
00236 
00237       allocated = PATH_MAX + 1;
00238     }
00239 
00240   if (buf != NULL)
00241     path = buf;
00242   else
00243     {
00244       path = malloc (allocated);
00245       if (path == NULL)
00246        return NULL;
00247     }
00248 
00249   pathp = path + allocated;
00250   *--pathp = '\0';
00251 
00252   if (__lstat (".", &st) < 0)
00253     goto lose2;
00254   thisdev = st.st_dev;
00255   thisino = st.st_ino;
00256 
00257   if (__lstat ("/", &st) < 0)
00258     goto lose2;
00259   rootdev = st.st_dev;
00260   rootino = st.st_ino;
00261 
00262   while (!(thisdev == rootdev && thisino == rootino))
00263     {
00264       register DIR *dirstream;
00265       struct dirent *d;
00266       dev_t dotdev;
00267       ino_t dotino;
00268       char mount_point;
00269 
00270       /* Look at the parent directory.  */
00271       if (dotp == dotlist)
00272        {
00273          /* My, what a deep directory tree you have, Grandma.  */
00274          char *new;
00275          if (dotlist == dots)
00276            {
00277              new = malloc (dotsize * 2 + 1);
00278              if (new == NULL)
00279               goto lose;
00280 #ifdef HAVE_MEMPCPY
00281              dotp = mempcpy (new, dots, dotsize);
00282 #else
00283              memcpy (new, dots, dotsize);
00284              dotp = &new[dotsize];
00285 #endif
00286            }
00287          else
00288            {
00289              new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
00290              if (new == NULL)
00291               goto lose;
00292              dotp = &new[dotsize];
00293            }
00294 #ifdef HAVE_MEMPCPY
00295          *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
00296          dotsize *= 2;
00297 #else
00298          memcpy ((char *) dotp, new, dotsize);
00299          dotsize *= 2;
00300          new[dotsize] = '\0';
00301 #endif
00302          dotlist = new;
00303        }
00304 
00305       dotp -= 3;
00306 
00307       /* Figure out if this directory is a mount point.  */
00308       if (__lstat (dotp, &st) < 0)
00309        goto lose;
00310       dotdev = st.st_dev;
00311       dotino = st.st_ino;
00312       mount_point = dotdev != thisdev;
00313 
00314       /* Search for the last directory.  */
00315       dirstream = __opendir (dotp);
00316       if (dirstream == NULL)
00317        goto lose;
00318       /* Clear errno to distinguish EOF from error if readdir returns
00319         NULL.  */
00320       __set_errno (0);
00321       while ((d = __readdir (dirstream)) != NULL)
00322        {
00323          if (d->d_name[0] == '.' &&
00324              (d->d_name[1] == '\0' ||
00325               (d->d_name[1] == '.' && d->d_name[2] == '\0')))
00326            continue;
00327          if (mount_point || (ino_t) d->d_ino == thisino)
00328            {
00329              char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
00330 #ifdef HAVE_MEMPCPY
00331              char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
00332              *tmp++ = '/';
00333              strcpy (tmp, d->d_name);
00334 #else
00335              memcpy (name, dotp, dotlist + dotsize - dotp);
00336              name[dotlist + dotsize - dotp] = '/';
00337              strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
00338 #endif
00339              /* We don't fail here if we cannot stat() a directory entry.
00340                This can happen when (network) filesystems fail.  If this
00341                entry is in fact the one we are looking for we will find
00342                out soon as we reach the end of the directory without
00343                having found anything.  */
00344              if (__lstat (name, &st) >= 0
00345                 && st.st_dev == thisdev && st.st_ino == thisino)
00346               break;
00347            }
00348        }
00349       if (d == NULL)
00350        {
00351          int save = errno;
00352          (void) __closedir (dirstream);
00353          if (save == 0)
00354            /* EOF on dirstream, which means that the current directory
00355               has been removed.  */
00356            save = ENOENT;
00357          __set_errno (save);
00358          goto lose;
00359        }
00360       else
00361        {
00362          size_t namlen = _D_EXACT_NAMLEN (d);
00363 
00364          if ((size_t) (pathp - path) <= namlen)
00365            {
00366              if (size != 0)
00367               {
00368                 (void) __closedir (dirstream);
00369                 __set_errno (ERANGE);
00370                 goto lose;
00371               }
00372              else
00373               {
00374                 char *tmp;
00375                 size_t oldsize = allocated;
00376 
00377                 allocated = 2 * MAX (allocated, namlen);
00378                 tmp = realloc (path, allocated);
00379                 if (tmp == NULL)
00380                   {
00381                     (void) __closedir (dirstream);
00382                     __set_errno (ENOMEM);/* closedir might have changed it.*/
00383                     goto lose;
00384                   }
00385 
00386                 /* Move current contents up to the end of the buffer.
00387                    This is guaranteed to be non-overlapping.  */
00388                 pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
00389                               tmp + (pathp - path),
00390                               path + oldsize - pathp);
00391                 path = tmp;
00392               }
00393            }
00394          pathp -= namlen;
00395          (void) memcpy (pathp, d->d_name, namlen);
00396          *--pathp = '/';
00397          (void) __closedir (dirstream);
00398        }
00399 
00400       thisdev = dotdev;
00401       thisino = dotino;
00402     }
00403 
00404   if (pathp == &path[allocated - 1])
00405     *--pathp = '/';
00406 
00407   if (dotlist != dots)
00408     free ((__ptr_t) dotlist);
00409 
00410   memmove (path, pathp, path + allocated - pathp);
00411 
00412   /* Restore errno on successful return.  */
00413   __set_errno (prev_errno);
00414 
00415   return path;
00416 
00417  lose:
00418   if (dotlist != dots)
00419     free ((__ptr_t) dotlist);
00420  lose2:
00421   if (buf == NULL)
00422     free (path);
00423   return NULL;
00424 }
00425 
00426 #if defined _LIBC && !defined __getcwd
00427 weak_alias (__getcwd, getcwd)
00428 #endif