• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2007-2009 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/utils/path.h"
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 
20 #ifdef _WIN32
21 #include <process.h>
22 #include <shlobj.h>
23 #include <tlhelp32.h>
24 #include <io.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <stdint.h>
28 #include <limits.h>
29 #include <winbase.h>
30 #else
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <time.h>
34 #include <signal.h>
35 #endif
36 
37 #include "android/utils/debug.h"
38 #define  D(...)  VERBOSE_PRINT(init,__VA_ARGS__)
39 
40 #ifndef CHECKED
41 #  ifdef _WIN32
42 #    define   CHECKED(ret, call)    (ret) = (call)
43 #  else
44 #    define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
45 #  endif
46 #endif
47 
48 /** PATH HANDLING ROUTINES
49  **
50  **  path_parent() can be used to return the n-level parent of a given directory
51  **  this understands . and .. when encountered in the input path
52  **/
53 
54 static __inline__ int
ispathsep(int c)55 ispathsep(int  c)
56 {
57 #ifdef _WIN32
58     return (c == '/' || c == '\\');
59 #else
60     return (c == '/');
61 #endif
62 }
63 
64 char*
path_parent(const char * path,int levels)65 path_parent( const char*  path, int  levels )
66 {
67     const char*  end = path + strlen(path);
68     char*        result;
69 
70     while (levels > 0) {
71         const char*  base;
72 
73         /* trim any trailing path separator */
74         while (end > path && ispathsep(end[-1]))
75             end--;
76 
77         base = end;
78         while (base > path && !ispathsep(base[-1]))
79             base--;
80 
81         if (base <= path) /* we can't go that far */
82             return NULL;
83 
84         if (end == base+1 && base[0] == '.')
85             goto Next;
86 
87         if (end == base+2 && base[0] == '.' && base[1] == '.') {
88             levels += 1;
89             goto Next;
90         }
91 
92         levels -= 1;
93 
94     Next:
95         end = base - 1;
96     }
97     result = malloc( end-path+1 );
98     if (result != NULL) {
99         memcpy( result, path, end-path );
100         result[end-path] = 0;
101     }
102     return result;
103 }
104 
105 static char*
substring_dup(const char * start,const char * end)106 substring_dup( const char*  start, const char*  end )
107 {
108     int    len    = end - start;
109     char*  result = android_alloc(len+1);
110     memcpy(result, start, len);
111     result[len] = 0;
112     return result;
113 }
114 
115 int
path_split(const char * path,char ** pdirname,char ** pbasename)116 path_split( const char*  path, char* *pdirname, char* *pbasename )
117 {
118     const char*  end = path + strlen(path);
119     const char*  last;
120     char*        basename;
121 
122     /* prepare for errors */
123     if (pdirname)
124         *pdirname = NULL;
125     if (pbasename)
126         *pbasename = NULL;
127 
128     /* handle empty path case */
129     if (end == path) {
130         return -1;
131     }
132 
133     /* strip trailing path separators */
134     while (end > path && ispathsep(end[-1]))
135         end -= 1;
136 
137     /* handle "/" and degenerate cases like "////" */
138     if (end == path) {
139         return -1;
140     }
141 
142     /* find last separator */
143     last = end;
144     while (last > path && !ispathsep(last[-1]))
145         last -= 1;
146 
147     /* handle cases where there is no path separator */
148     if (last == path) {
149         if (pdirname)
150             *pdirname  = ASTRDUP(".");
151         if (pbasename)
152             *pbasename = substring_dup(path,end);
153         return 0;
154     }
155 
156     /* handle "/foo" */
157     if (last == path+1) {
158         if (pdirname)
159             *pdirname  = ASTRDUP("/");
160         if (pbasename)
161             *pbasename = substring_dup(path+1,end);
162         return 0;
163     }
164 
165     /* compute basename */
166     basename = substring_dup(last,end);
167     if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) {
168         AFREE(basename);
169         return -1;
170     }
171 
172     if (pbasename)
173         *pbasename = basename;
174     else {
175         AFREE(basename);
176     }
177 
178     /* compute dirname */
179     if (pdirname != NULL)
180         *pdirname = substring_dup(path,last-1);
181 
182     return 0;
183 }
184 
185 char*
path_basename(const char * path)186 path_basename( const char*  path )
187 {
188     char*  basename;
189 
190     if (path_split(path, NULL, &basename) < 0)
191         return NULL;
192 
193     return basename;
194 }
195 
196 char*
path_dirname(const char * path)197 path_dirname( const char*  path )
198 {
199     char*  dirname;
200 
201     if (path_split(path, &dirname, NULL) < 0)
202         return NULL;
203 
204     return dirname;
205 }
206 
207 
208 
209 
210 
211 /** MISC FILE AND DIRECTORY HANDLING
212  **/
213 
214 ABool
path_exists(const char * path)215 path_exists( const char*  path )
216 {
217     int  ret;
218     CHECKED(ret, access(path, F_OK));
219     return (ret == 0) || (errno != ENOENT);
220 }
221 
222 /* checks that a path points to a regular file */
223 ABool
path_is_regular(const char * path)224 path_is_regular( const char*  path )
225 {
226     int          ret;
227     struct stat  st;
228 
229     CHECKED(ret, stat(path, &st));
230     if (ret < 0)
231         return 0;
232 
233     return S_ISREG(st.st_mode);
234 }
235 
236 
237 /* checks that a path points to a directory */
238 ABool
path_is_dir(const char * path)239 path_is_dir( const char*  path )
240 {
241     int          ret;
242     struct stat  st;
243 
244     CHECKED(ret, stat(path, &st));
245     if (ret < 0)
246         return 0;
247 
248     return S_ISDIR(st.st_mode);
249 }
250 
251 /* checks that one can read/write a given (regular) file */
252 ABool
path_can_read(const char * path)253 path_can_read( const char*  path )
254 {
255     int  ret;
256     CHECKED(ret, access(path, R_OK));
257     return (ret == 0);
258 }
259 
260 ABool
path_can_write(const char * path)261 path_can_write( const char*  path )
262 {
263     int  ret;
264     CHECKED(ret, access(path, R_OK));
265     return (ret == 0);
266 }
267 
268 /* try to make a directory. returns 0 on success, -1 on failure
269  * (error code in errno) */
270 APosixStatus
path_mkdir(const char * path,int mode)271 path_mkdir( const char*  path, int  mode )
272 {
273 #ifdef _WIN32
274     (void)mode;
275     return _mkdir(path);
276 #else
277     int  ret;
278     CHECKED(ret, mkdir(path, mode));
279     return ret;
280 #endif
281 }
282 
283 static APosixStatus
path_mkdir_recursive(char * path,unsigned len,int mode)284 path_mkdir_recursive( char*  path, unsigned  len, int  mode )
285 {
286     char      old_c;
287     int       ret;
288     unsigned  len2;
289 
290     /* get rid of trailing separators */
291     while (len > 0 && ispathsep(path[len-1]))
292         len -= 1;
293 
294     if (len == 0) {
295         errno = ENOENT;
296         return -1;
297     }
298 
299     /* check that the parent exists, 'len2' is the length of
300      * the parent part of the path */
301     len2 = len-1;
302     while (len2 > 0 && !ispathsep(path[len2-1]))
303         len2 -= 1;
304 
305     if (len2 > 0) {
306         old_c      = path[len2];
307         path[len2] = 0;
308         ret        = 0;
309         if ( !path_exists(path) ) {
310             /* the parent doesn't exist, so try to create it */
311             ret = path_mkdir_recursive( path, len2, mode );
312         }
313         path[len2] = old_c;
314 
315         if (ret < 0)
316             return ret;
317     }
318 
319     /* at this point, we now the parent exists */
320     old_c     = path[len];
321     path[len] = 0;
322     ret       = path_mkdir( path, mode );
323     path[len] = old_c;
324 
325     return ret;
326 }
327 
328 /* ensure that a given directory exists, create it if not,
329    0 on success, -1 on failure (error code in errno) */
330 APosixStatus
path_mkdir_if_needed(const char * path,int mode)331 path_mkdir_if_needed( const char*  path, int  mode )
332 {
333     int  ret = 0;
334 
335     if (!path_exists(path)) {
336         ret = path_mkdir(path, mode);
337 
338         if (ret < 0 && errno == ENOENT) {
339             char      temp[MAX_PATH];
340             unsigned  len = (unsigned)strlen(path);
341 
342             if (len > sizeof(temp)-1) {
343                 errno = EINVAL;
344                 return -1;
345             }
346             memcpy( temp, path, len );
347             temp[len] = 0;
348 
349             return path_mkdir_recursive(temp, len, mode);
350         }
351     }
352     return ret;
353 }
354 
355 /* return the size of a given file in '*psize'. returns 0 on
356  * success, -1 on failure (error code in errno) */
357 APosixStatus
path_get_size(const char * path,uint64_t * psize)358 path_get_size( const char*  path, uint64_t  *psize )
359 {
360 #ifdef _WIN32
361     /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
362     /* do not use OpenFile() because it has strange search behaviour that could */
363     /* result in getting the size of a different file */
364     LARGE_INTEGER  size;
365     HANDLE  file = CreateFile( /* lpFilename */        path,
366                                /* dwDesiredAccess */   GENERIC_READ,
367                                /* dwSharedMode */     FILE_SHARE_READ|FILE_SHARE_WRITE,
368                                /* lpSecurityAttributes */  NULL,
369                                /* dwCreationDisposition */ OPEN_EXISTING,
370                                /* dwFlagsAndAttributes */  0,
371                                /* hTemplateFile */      NULL );
372     if (file == INVALID_HANDLE_VALUE) {
373         /* ok, just to play fair */
374         errno = ENOENT;
375         return -1;
376     }
377     if (!GetFileSizeEx(file, &size)) {
378         /* maybe we tried to get the size of a pipe or something like that ? */
379         *psize = 0;
380     }
381     else {
382         *psize = (uint64_t) size.QuadPart;
383     }
384     CloseHandle(file);
385     return 0;
386 #else
387     int    ret;
388     struct stat  st;
389 
390     CHECKED(ret, stat(path, &st));
391     if (ret == 0) {
392         *psize = (uint64_t) st.st_size;
393     }
394     return ret;
395 #endif
396 }
397 
398 
399 ABool
path_is_absolute(const char * path)400 path_is_absolute( const char*  path )
401 {
402 #ifdef _WIN32
403     if (path == NULL)
404         return 0;
405 
406     if (path[0] == '/' || path[0] == '\\')
407         return 1;
408 
409     /* 'C:' is always considered to be absolute
410      * even if used with a relative path like C:foo which
411      * is different from C:\foo
412      */
413     if (path[0] != 0 && path[1] == ':')
414         return 1;
415 
416     return 0;
417 #else
418     return (path != NULL && path[0] == '/');
419 #endif
420 }
421 
422 
423 /** OTHER FILE UTILITIES
424  **
425  **  path_empty_file() creates an empty file at a given path location.
426  **  if the file already exists, it is truncated without warning
427  **
428  **  path_copy_file() copies one file into another.
429  **
430  **  both functions return 0 on success, and -1 on error
431  **/
432 
433 APosixStatus
path_empty_file(const char * path)434 path_empty_file( const char*  path )
435 {
436 #ifdef _WIN32
437     int  fd = _creat( path, S_IWRITE );
438 #else
439     /* on Unix, only allow the owner to read/write, since the file *
440      * may contain some personal data we don't want to see exposed */
441     int  fd = creat(path, S_IRUSR | S_IWUSR);
442 #endif
443     if (fd >= 0) {
444         close(fd);
445         return 0;
446     }
447     return -1;
448 }
449 
450 APosixStatus
path_copy_file(const char * dest,const char * source)451 path_copy_file( const char*  dest, const char*  source )
452 {
453     int  fd, fs, result = -1;
454 
455     /* if the destination doesn't exist, create it */
456     if ( access(source, F_OK)  < 0 ||
457          path_empty_file(dest) < 0) {
458         return -1;
459     }
460 
461     if ( access(source, R_OK) < 0 ) {
462         D("%s: source file is un-readable: %s\n",
463           __FUNCTION__, source);
464         return -1;
465     }
466 
467 #ifdef _WIN32
468     fd = _open(dest, _O_RDWR | _O_BINARY);
469     fs = _open(source, _O_RDONLY |  _O_BINARY);
470 #else
471     fd = creat(dest, S_IRUSR | S_IWUSR);
472     fs = open(source, S_IREAD);
473 #endif
474     if (fs >= 0 && fd >= 0) {
475         char buf[4096];
476         ssize_t total = 0;
477         ssize_t n;
478         result = 0; /* success */
479         while ((n = read(fs, buf, 4096)) > 0) {
480             if (write(fd, buf, n) != n) {
481                 /* write failed. Make it return -1 so that an
482                  * empty file be created. */
483                 D("Failed to copy '%s' to '%s': %s (%d)",
484                        source, dest, strerror(errno), errno);
485                 result = -1;
486                 break;
487             }
488             total += n;
489         }
490     }
491 
492     if (fs >= 0) {
493         close(fs);
494     }
495     if (fd >= 0) {
496         close(fd);
497     }
498     return result;
499 }
500 
501 
502 APosixStatus
path_delete_file(const char * path)503 path_delete_file( const char*  path )
504 {
505 #ifdef _WIN32
506     int  ret = _unlink( path );
507     if (ret == -1 && errno == EACCES) {
508         /* a first call to _unlink will fail if the file is set read-only */
509         /* we can however try to change its mode first and call unlink    */
510         /* again...                                                       */
511         ret = _chmod( path, _S_IREAD | _S_IWRITE );
512         if (ret == 0)
513             ret = _unlink( path );
514     }
515     return ret;
516 #else
517     return  unlink(path);
518 #endif
519 }
520 
521 
522 void*
path_load_file(const char * fn,size_t * pSize)523 path_load_file(const char *fn, size_t  *pSize)
524 {
525     char*  data;
526     int    sz;
527     int    fd;
528 
529     if (pSize)
530         *pSize = 0;
531 
532     data   = NULL;
533 
534     fd = open(fn, O_BINARY | O_RDONLY);
535     if(fd < 0) return NULL;
536 
537     do {
538         sz = lseek(fd, 0, SEEK_END);
539         if(sz < 0) break;
540 
541         if (pSize)
542             *pSize = (size_t) sz;
543 
544         if (lseek(fd, 0, SEEK_SET) != 0)
545             break;
546 
547         data = (char*) malloc(sz + 1);
548         if(data == NULL) break;
549 
550         if (read(fd, data, sz) != sz)
551             break;
552 
553         close(fd);
554         data[sz] = 0;
555 
556         return data;
557     } while (0);
558 
559     close(fd);
560 
561     if(data != NULL)
562         free(data);
563 
564     return NULL;
565 }
566 
567