_getcwd.c

Go to the documentation of this file.
00001 /*      getcwd() - get the name of the current working directory.
00002  *                                                      Author: Kees J. Bot
00003  *                                                              30 Apr 1989
00004  */
00005 #define nil 0
00006 #define chdir _chdir
00007 #define closedir _closedir
00008 #define getcwd _getcwd
00009 #define opendir _opendir
00010 #define readdir _readdir
00011 #define rewinddir _rewinddir
00012 #define stat _stat
00013 #include <sys/types.h>
00014 #include <sys/stat.h>
00015 #include <errno.h>
00016 #include <unistd.h>
00017 #include <dirent.h>
00018 #include <limits.h>
00019 #include <string.h>
00020 
00021 static int addpath(const char *path, char **ap, const char *entry)
00022 /* Add the name of a directory entry at the front of the path being built.
00023  * Note that the result always starts with a slash.
00024  */
00025 {
00026         const char *e= entry;
00027         char *p= *ap;
00028 
00029         while (*e != 0) e++;
00030 
00031         while (e > entry && p > path) *--p = *--e;
00032 
00033         if (p == path) return -1;
00034         *--p = '/';
00035         *ap= p;
00036         return 0;
00037 }
00038 
00039 static int recover(char *p)
00040 /* Undo all those chdir("..")'s that have been recorded by addpath.  This
00041  * has to be done entry by entry, because the whole pathname may be too long.
00042  */
00043 {
00044         int e= errno, slash;
00045         char *p0;
00046 
00047         while (*p != 0) {
00048                 p0= ++p;
00049 
00050                 do p++; while (*p != 0 && *p != '/');
00051                 slash= *p; *p= 0;
00052 
00053                 if (chdir(p0) < 0) return -1;
00054                 *p= slash;
00055         }
00056         errno= e;
00057         return 0;
00058 }
00059 
00060 char *getcwd(char *path, size_t size)
00061 {
00062         struct stat above, current, tmp;
00063         struct dirent *entry;
00064         DIR *d;
00065         char *p, *up, *dotdot;
00066         int cycle;
00067 
00068         if (path == nil || size <= 1) { errno= EINVAL; return nil; }
00069 
00070         p= path + size;
00071         *--p = 0;
00072 
00073         if (stat(".", &current) < 0) return nil;
00074 
00075         while (1) {
00076                 dotdot= "..";
00077                 if (stat(dotdot, &above) < 0) { recover(p); return nil; }
00078 
00079                 if (above.st_dev == current.st_dev
00080                                         && above.st_ino == current.st_ino)
00081                         break;  /* Root dir found */
00082 
00083                 if ((d= opendir(dotdot)) == nil) { recover(p); return nil; }
00084 
00085                 /* Cycle is 0 for a simple inode nr search, or 1 for a search
00086                  * for inode *and* device nr.
00087                  */
00088                 cycle= above.st_dev == current.st_dev ? 0 : 1;
00089 
00090                 do {
00091                         char name[3 + NAME_MAX + 1];
00092 
00093                         tmp.st_ino= 0;
00094                         if ((entry= readdir(d)) == nil) {
00095                                 switch (++cycle) {
00096                                 case 1:
00097                                         rewinddir(d);
00098                                         continue;
00099                                 case 2:
00100                                         closedir(d);
00101                                         errno= ENOENT;
00102                                         recover(p);
00103                                         return nil;
00104                                 }
00105                         }
00106                         if (strcmp(entry->d_name, ".") == 0) continue;
00107                         if (strcmp(entry->d_name, "..") == 0) continue;
00108 
00109                         switch (cycle) {
00110                         case 0:
00111                                 /* Simple test on inode nr. */
00112                                 if (entry->d_ino != current.st_ino) continue;
00113                                 /*FALL THROUGH*/
00114 
00115                         case 1:
00116                                 /* Current is mounted. */
00117                                 strcpy(name, "../");
00118                                 strcpy(name+3, entry->d_name);
00119                                 if (stat(name, &tmp) < 0) continue;
00120                                 break;
00121                         }
00122                 } while (tmp.st_ino != current.st_ino
00123                                         || tmp.st_dev != current.st_dev);
00124 
00125                 up= p;
00126                 if (addpath(path, &up, entry->d_name) < 0) {
00127                         closedir(d);
00128                         errno = ERANGE;
00129                         recover(p);
00130                         return nil;
00131                 }
00132                 closedir(d);
00133 
00134                 if (chdir(dotdot) < 0) { recover(p); return nil; }
00135                 p= up;
00136 
00137                 current= above;
00138         }
00139         if (recover(p) < 0) return nil; /* Undo all those chdir("..")'s. */
00140         if (*p == 0) *--p = '/';        /* Cwd is "/" if nothing added */
00141         if (p > path) strcpy(path, p);  /* Move string to start of path. */
00142         return path;
00143 }

Generated on Fri Apr 14 22:57:27 2006 for minix by  doxygen 1.4.6