00001 /* 00002 getcwd 00003 AUP2, Sec. 3.6.4 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 #include "defs.h" 00022 #include <dirent.h> 00023 00024 /*[push_pathlist]*/ 00025 struct pathlist_node { 00026 struct pathlist_node *c_next; 00027 char c_name[1]; /* flexible array */ 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 /*[free_pathlist]*/ 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 /*[get_pathlist]*/ 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 /*[SAME_INODE]*/ 00077 #define SAME_INODE(s1, s2) ((s1).st_dev == (s2).st_dev &&\ 00078 (s1).st_ino == (s2).st_ino) 00079 /*[getcwdx]*/ 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 /* change to parent and detect root */ 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 /* read directory looking for child */ 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 /*[main1]*/ 00133 int main(void) 00134 { 00135 char *path; 00136 00137 /*[]*/ 00138 { 00139 /*[push_pathlist-example]*/ 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 /*[main2]*/ 00152 } 00153 /*[main2]*/ 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 /* old function -- not used anymore */ 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; /* +1 for slash */ 00178 ec_null( *p = realloc(*p, *alloc) ) 00179 plen = strlen(*p); 00180 if (plen > 1) /* move slash only with name */ 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