GRASS Programmer's Manual 6.4.1(2011)
|
00001 00028 #include <stdio.h> 00029 #include <stdlib.h> 00030 #include <assert.h> 00031 #include <unistd.h> 00032 #include <string.h> 00033 #ifndef __MINGW32__ 00034 #include <pwd.h> 00035 #endif 00036 #include <sys/types.h> 00037 #include <sys/stat.h> 00038 #include <errno.h> 00039 #include <grass/gis.h> 00040 00041 00042 /************************************************************************** 00043 * _make_toplevel(): make user's toplevel config directory if it doesn't 00044 * already exist. Adjust perms to 1700. Returns the toplevel directory 00045 * path [caller must G_free ()] on success, or NULL on failure 00046 *************************************************************************/ 00047 00048 #ifndef __MINGW32__ /* TODO */ 00049 static char *_make_toplevel(void) 00050 { 00051 size_t len; 00052 int status; 00053 00054 #ifdef __MINGW32__ 00055 char *defaulthomedir = "c:"; 00056 char *homedir = getenv("HOME"); 00057 #else 00058 uid_t me; 00059 struct passwd *my_passwd; 00060 #endif 00061 struct stat buf; 00062 char *path; 00063 00064 errno = 0; 00065 00066 /* Query whatever database to get user's home dir */ 00067 #ifdef __MINGW32__ 00068 if (NULL == homedir) { 00069 homedir = defaulthomedir; 00070 } 00071 00072 len = strlen(homedir) + 8; /* + "/.grass\0" */ 00073 if (NULL == (path = G_calloc(1, len))) { 00074 return NULL; 00075 } 00076 sprintf(path, "%s%s", homedir, "/.grass"); 00077 #else 00078 me = getuid(); 00079 my_passwd = getpwuid(me); 00080 if (my_passwd == NULL) 00081 return NULL; 00082 00083 len = strlen(my_passwd->pw_dir) + 8; /* + "/.grass\0" */ 00084 if (NULL == (path = G_calloc(1, len))) 00085 return NULL; 00086 00087 sprintf(path, "%s%s", my_passwd->pw_dir, "/.grass"); 00088 #endif 00089 00090 status = G_lstat(path, &buf); 00091 00092 /* If errno == ENOENT, the directory doesn't exist */ 00093 if (status != 0) { 00094 if (errno == ENOENT) { 00095 status = G_mkdir(path); 00096 00097 if (status != 0) { /* mkdir failed */ 00098 G_free(path); 00099 return NULL; 00100 } 00101 00102 /* override umask settings, if possible */ 00103 chmod(path, S_IRWXU); 00104 00105 /* otherwise mkdir succeeded, we're done here */ 00106 return path; 00107 } 00108 00109 /* other errors should not be defined ??? give up */ 00110 G_free(path); 00111 return NULL; 00112 } 00113 /* implicit else */ 00114 00115 /* Examine the stat "buf" */ 00116 /* It better be a directory */ 00117 if (!S_ISDIR(buf.st_mode)) { /* File, link, something else */ 00118 errno = ENOTDIR; /* element is not a directory, but should be */ 00119 G_free(path); 00120 return NULL; 00121 } 00122 00123 /* No read/write/execute ??? */ 00124 if (!((S_IRUSR & buf.st_mode) && 00125 (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode) 00126 ) 00127 ) { 00128 errno = EACCES; /* Permissions error */ 00129 G_free(path); 00130 return NULL; 00131 } 00132 00133 /* We'll assume that if the user grants greater permissions 00134 * than we would, that they know what they're doing 00135 * -- so we're done here... 00136 */ 00137 00138 return path; 00139 } 00140 00141 00142 /************************************************************************** 00143 * _elem_count_split: Does a couple things: 00144 * 1) Counts the number of elements in "elems" 00145 * 2) Replaces occurrences of '/' with '\0' 00146 * 3) Checks that no element begins with a '.' 00147 * 4) Checks there are no '//' 00148 * 00149 * Therefore, THE STRING THAT IS PASSED IN IS MODIFIED 00150 * Returns 0 if there are no elements, or an element 00151 * beginning with a '.' or containing a '//' is found. 00152 *************************************************************************/ 00153 static int _elem_count_split(char *elems) 00154 { 00155 int i; 00156 size_t len; 00157 char *begin, *end; 00158 00159 /* Some basic assertions */ 00160 assert(elems != NULL); 00161 assert((len = strlen(elems)) > 0); 00162 assert(*elems != '/'); 00163 00164 begin = elems; 00165 for (i = 0; begin != NULL && len > begin - elems; i++) { 00166 /* check '.' condition */ 00167 if (*begin == '.') 00168 return 0; 00169 end = strchr(begin, '/'); 00170 /* check '//' condition */ 00171 if (end != NULL && end == begin) 00172 return 0; 00173 /* okay, change '/' into '\0' */ 00174 begin = end; 00175 if (begin != NULL) { 00176 *begin = '\0'; /* begin points at '/', change it */ 00177 begin++; /* increment begin to next char */ 00178 } 00179 } 00180 00181 /* That's it */ 00182 return i; 00183 } 00184 00185 00186 /************************************************************************** 00187 * _make_sublevels(): creates subelements as necessary from the passed 00188 * "elems" string. It returns the full path if successful or NULL 00189 * if it fails. "elems" must not be NULL, zero length, or have any 00190 * elements that begin with a '.' or any occurrences of '//'. 00191 *************************************************************************/ 00192 static char *_make_sublevels(const char *elems) 00193 { 00194 int i, status; 00195 char *cp, *path, *top, *ptr; 00196 struct stat buf; 00197 00198 /* Get top level path */ 00199 if (NULL == (top = _make_toplevel())) 00200 return NULL; 00201 00202 /* Make a copy of elems */ 00203 if (NULL == (cp = G_store(elems))) { 00204 G_free(top); 00205 return NULL; 00206 } 00207 00208 /* Do element count, sanity checking and "splitting" */ 00209 if ((i = _elem_count_split(cp)) < 1) { 00210 G_free(cp); 00211 G_free(top); 00212 return NULL; 00213 } 00214 00215 /* Allocate our path to be large enough */ 00216 if ((path = G_calloc(1, strlen(top) + strlen(elems) + 2)) == NULL) { 00217 G_free(top); 00218 G_free(cp); 00219 return NULL; 00220 } 00221 00222 /* Now loop along adding directories if they don't exist 00223 * make sure the thing is a directory as well. 00224 * If there was a trailing '/' in the original "elem", it doesn't 00225 * make it into the returned path. 00226 */ 00227 for (; i > 0; i--) { 00228 sprintf(path, "%s/%s", top, cp); 00229 errno = 0; 00230 status = G_lstat(path, &buf); 00231 if (status != 0) { 00232 /* the element doesn't exist */ 00233 status = G_mkdir(path); 00234 if (status != 0) { 00235 /* Some kind of problem... */ 00236 G_free(top); 00237 G_free(cp); 00238 return NULL; 00239 } 00240 /* override umask settings, if possible */ 00241 chmod(path, S_IRWXU); 00242 } 00243 else { 00244 /* Examine the stat "buf" */ 00245 /* It better be a directory */ 00246 if (!S_ISDIR(buf.st_mode)) { /* File, link, something else */ 00247 errno = ENOTDIR; /* element is not a directory, but should be */ 00248 G_free(path); 00249 return NULL; 00250 } 00251 00252 /* No read/write/execute ??? */ 00253 if (!((S_IRUSR & buf.st_mode) && 00254 (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode) 00255 ) 00256 ) { 00257 errno = EACCES; /* Permissions error */ 00258 G_free(path); 00259 return NULL; 00260 } 00261 00262 /* okay continue ... */ 00263 } 00264 00265 ptr = strchr(cp, '\0'); 00266 *ptr = '/'; 00267 } 00268 00269 /* All done, free memory */ 00270 G_free(top); 00271 G_free(cp); 00272 00273 return path; 00274 } 00275 00276 00291 char *G_rc_path(const char *element, const char *item) 00292 { 00293 size_t len; 00294 char *path, *ptr; 00295 00296 assert(!(element == NULL && item == NULL)); 00297 00298 /* Simple item in top-level */ 00299 if (element == NULL) { 00300 path = _make_toplevel(); 00301 } 00302 else if (item == NULL) { 00303 return _make_sublevels(element); 00304 } 00305 else { 00306 path = _make_sublevels(element); 00307 } 00308 00309 00310 assert(*item != '.'); 00311 assert(path != NULL); 00312 ptr = strchr(item, '/'); /* should not have slashes */ 00313 assert(ptr == NULL); 00314 len = strlen(path) + strlen(item) + 2; 00315 if ((ptr = G_realloc(path, len)) == NULL) { 00316 G_free(path); 00317 return NULL; 00318 } 00319 path = ptr; 00320 ptr = strchr(path, '\0'); 00321 sprintf(ptr, "/%s", item); 00322 00323 return path; 00324 } /* G_rc_path */ 00325 00326 00327 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */ 00328 #endif