00001
00002
00003
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
00023
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
00041
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(".", ¤t) < 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;
00082
00083 if ((d= opendir(dotdot)) == nil) { recover(p); return nil; }
00084
00085
00086
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
00112 if (entry->d_ino != current.st_ino) continue;
00113
00114
00115 case 1:
00116
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;
00140 if (*p == 0) *--p = '/';
00141 if (p > path) strcpy(path, p);
00142 return path;
00143 }