00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "defs.h"
00022 #include <dirent.h>
00023
00024
00025 struct pathlist_node {
00026 struct pathlist_node *c_next;
00027 char c_name[1];
00028 };
00029
00030 static bool push_pathlist(struct pathlist_node **head, const char *name)
00031 {
00032 struct pathlist_node *p;
00033
00034 ec_null( p = malloc(sizeof(struct pathlist_node) + strlen(name)) )
00035 strcpy(p->c_name, name);
00036 p->c_next = *head;
00037 *head = p;
00038 return true;
00039
00040 EC_CLEANUP_BGN
00041 return false;
00042 EC_CLEANUP_END
00043 }
00044
00045 static void free_pathlist(struct pathlist_node **head)
00046 {
00047 struct pathlist_node *p, *p_next;
00048
00049 for (p = *head; p != NULL; p = p_next) {
00050 p_next = p->c_next;
00051 free(p);
00052 }
00053 *head = NULL;
00054 }
00055
00056 static char *get_pathlist(struct pathlist_node *head)
00057 {
00058 struct pathlist_node *p;
00059 char *path;
00060 size_t total = 0;
00061
00062 for (p = head; p != NULL; p = p->c_next)
00063 total += strlen(p->c_name) + 1;
00064 ec_null( path = malloc(total + 1) )
00065 path[0] = '\0';
00066 for (p = head; p != NULL; p = p->c_next) {
00067 strcat(path, "/");
00068 strcat(path, p->c_name);
00069 }
00070 return path;
00071
00072 EC_CLEANUP_BGN
00073 return NULL;
00074 EC_CLEANUP_END
00075 }
00076
00077 #define SAME_INODE(s1, s2) ((s1).st_dev == (s2).st_dev &&\
00078 (s1).st_ino == (s2).st_ino)
00079
00080 char *getcwdx(void)
00081 {
00082 struct stat stat_child, stat_parent, stat_entry;
00083 DIR *sp = NULL;
00084 struct dirent *dp;
00085 struct pathlist_node *head = NULL;
00086 int dirfd = -1, rtn;
00087 char *path = NULL;
00088
00089 ec_neg1( dirfd = open(".", O_RDONLY) )
00090 ec_neg1( lstat(".", &stat_child) )
00091 while (true) {
00092 ec_neg1( lstat("..", &stat_parent) )
00093
00094
00095 if (((rtn = chdir("..")) == -1 && errno == ENOENT) ||
00096 SAME_INODE(stat_child, stat_parent)) {
00097 if (head == NULL)
00098 ec_false( push_pathlist(&head, "") )
00099 ec_null( path = get_pathlist(head) )
00100 EC_CLEANUP
00101 }
00102 ec_neg1( rtn )
00103
00104
00105 ec_null( sp = opendir(".") )
00106 while (errno = 0, (dp = readdir(sp)) != NULL) {
00107 ec_neg1( lstat(dp->d_name, &stat_entry) )
00108 if (SAME_INODE(stat_child, stat_entry)) {
00109 ec_false( push_pathlist(&head, dp->d_name) )
00110 break;
00111 }
00112 }
00113 if (dp == NULL) {
00114 if (errno == 0)
00115 errno = ENOENT;
00116 EC_FAIL
00117 }
00118 stat_child = stat_parent;
00119 }
00120
00121 EC_CLEANUP_BGN
00122 if (sp != NULL)
00123 (void)closedir(sp);
00124 if (dirfd != -1) {
00125 (void)fchdir(dirfd);
00126 (void)close(dirfd);
00127 }
00128 free_pathlist(&head);
00129 return path;
00130 EC_CLEANUP_END
00131 }
00132
00133 int main(void)
00134 {
00135 char *path;
00136
00137
00138 {
00139
00140 struct pathlist_node *head = NULL;
00141 char *path;
00142
00143 ec_false( push_pathlist(&head, "grandchild") )
00144 ec_false( push_pathlist(&head, "child") )
00145 ec_false( push_pathlist(&head, "parent") )
00146 ec_null( path = get_pathlist(head) );
00147 free_pathlist(&head);
00148 printf("%s\n", path);
00149 free(path);
00150
00151
00152 }
00153
00154 ec_null( path = getcwdx() )
00155 printf("%s\n", path);
00156 free(path);
00157 exit(EXIT_SUCCESS);
00158
00159 EC_CLEANUP_BGN
00160 exit(EXIT_FAILURE);
00161 EC_CLEANUP_END
00162 }
00163
00164
00165 #if 0
00166 static bool prepend(char **p, size_t *alloc, const char *name)
00167 {
00168 size_t namelen, plen;
00169
00170 if (*p == NULL) {
00171 *alloc = 2;
00172 ec_null( *p = malloc(*alloc) )
00173 strcpy(*p, "/");
00174 return true;
00175 }
00176 namelen = strlen(name);
00177 *alloc += namelen + 1;
00178 ec_null( *p = realloc(*p, *alloc) )
00179 plen = strlen(*p);
00180 if (plen > 1)
00181 memmove(*p + namelen + 1, *p, strlen(*p) + 1);
00182 memcpy(*p + 1, name, namelen);
00183 **p = '/';
00184 return true;
00185
00186 EC_CLEANUP_BGN
00187 return false;
00188 EC_CLEANUP_END
00189 }
00190 #endif