• 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 ABool
path_can_exec(const char * path)269 path_can_exec( const char* path )
270 {
271     int  ret;
272     CHECKED(ret, access(path, X_OK));
273     return (ret == 0);
274 }
275 
276 /* try to make a directory. returns 0 on success, -1 on failure
277  * (error code in errno) */
278 APosixStatus
path_mkdir(const char * path,int mode)279 path_mkdir( const char*  path, int  mode )
280 {
281 #ifdef _WIN32
282     (void)mode;
283     return _mkdir(path);
284 #else
285     int  ret;
286     CHECKED(ret, mkdir(path, mode));
287     return ret;
288 #endif
289 }
290 
291 static APosixStatus
path_mkdir_recursive(char * path,unsigned len,int mode)292 path_mkdir_recursive( char*  path, unsigned  len, int  mode )
293 {
294     char      old_c;
295     int       ret;
296     unsigned  len2;
297 
298     /* get rid of trailing separators */
299     while (len > 0 && ispathsep(path[len-1]))
300         len -= 1;
301 
302     if (len == 0) {
303         errno = ENOENT;
304         return -1;
305     }
306 
307     /* check that the parent exists, 'len2' is the length of
308      * the parent part of the path */
309     len2 = len-1;
310     while (len2 > 0 && !ispathsep(path[len2-1]))
311         len2 -= 1;
312 
313     if (len2 > 0) {
314         old_c      = path[len2];
315         path[len2] = 0;
316         ret        = 0;
317         if ( !path_exists(path) ) {
318             /* the parent doesn't exist, so try to create it */
319             ret = path_mkdir_recursive( path, len2, mode );
320         }
321         path[len2] = old_c;
322 
323         if (ret < 0)
324             return ret;
325     }
326 
327     /* at this point, we now the parent exists */
328     old_c     = path[len];
329     path[len] = 0;
330     ret       = path_mkdir( path, mode );
331     path[len] = old_c;
332 
333     return ret;
334 }
335 
336 /* ensure that a given directory exists, create it if not,
337    0 on success, -1 on failure (error code in errno) */
338 APosixStatus
path_mkdir_if_needed(const char * path,int mode)339 path_mkdir_if_needed( const char*  path, int  mode )
340 {
341     int  ret = 0;
342 
343     if (!path_exists(path)) {
344         ret = path_mkdir(path, mode);
345 
346         if (ret < 0 && errno == ENOENT) {
347             char      temp[MAX_PATH];
348             unsigned  len = (unsigned)strlen(path);
349 
350             if (len > sizeof(temp)-1) {
351                 errno = EINVAL;
352                 return -1;
353             }
354             memcpy( temp, path, len );
355             temp[len] = 0;
356 
357             return path_mkdir_recursive(temp, len, mode);
358         }
359     }
360     return ret;
361 }
362 
363 /* return the size of a given file in '*psize'. returns 0 on
364  * success, -1 on failure (error code in errno) */
365 APosixStatus
path_get_size(const char * path,uint64_t * psize)366 path_get_size( const char*  path, uint64_t  *psize )
367 {
368 #ifdef _WIN32
369     /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
370     /* do not use OpenFile() because it has strange search behaviour that could */
371     /* result in getting the size of a different file */
372     LARGE_INTEGER  size;
373     HANDLE  file = CreateFile( /* lpFilename */        path,
374                                /* dwDesiredAccess */   GENERIC_READ,
375                                /* dwSharedMode */     FILE_SHARE_READ|FILE_SHARE_WRITE,
376                                /* lpSecurityAttributes */  NULL,
377                                /* dwCreationDisposition */ OPEN_EXISTING,
378                                /* dwFlagsAndAttributes */  0,
379                                /* hTemplateFile */      NULL );
380     if (file == INVALID_HANDLE_VALUE) {
381         /* ok, just to play fair */
382         errno = ENOENT;
383         return -1;
384     }
385     if (!GetFileSizeEx(file, &size)) {
386         /* maybe we tried to get the size of a pipe or something like that ? */
387         *psize = 0;
388     }
389     else {
390         *psize = (uint64_t) size.QuadPart;
391     }
392     CloseHandle(file);
393     return 0;
394 #else
395     int    ret;
396     struct stat  st;
397 
398     CHECKED(ret, stat(path, &st));
399     if (ret == 0) {
400         *psize = (uint64_t) st.st_size;
401     }
402     return ret;
403 #endif
404 }
405 
406 
407 ABool
path_is_absolute(const char * path)408 path_is_absolute( const char*  path )
409 {
410 #ifdef _WIN32
411     if (path == NULL)
412         return 0;
413 
414     if (path[0] == '/' || path[0] == '\\')
415         return 1;
416 
417     /* 'C:' is always considered to be absolute
418      * even if used with a relative path like C:foo which
419      * is different from C:\foo
420      */
421     if (path[0] != 0 && path[1] == ':')
422         return 1;
423 
424     return 0;
425 #else
426     return (path != NULL && path[0] == '/');
427 #endif
428 }
429 
430 char*
path_get_absolute(const char * path)431 path_get_absolute( const char* path )
432 {
433     if (path_is_absolute(path)) {
434         return ASTRDUP(path);
435     }
436 
437 #ifdef _WIN32
438     {
439         char* result;
440         int   pathLen    = strlen(path);
441         int   currentLen = GetCurrentDirectory(0, NULL);
442 
443         if (currentLen <= 0) {
444             /* Could not get size of working directory. something is
445              * really fishy here, return a simple copy */
446             return ASTRDUP(path);
447         }
448         result = malloc(currentLen + pathLen + 2);
449 
450         GetCurrentDirectory(currentLen+1, result);
451         if (currentLen == 0 || result[currentLen-1] != '\\') {
452             result[currentLen++] = '\\';
453         }
454         memcpy(result + currentLen, path, pathLen+1);
455 
456         return result;
457     }
458 #else
459     {
460         int   pathLen    = strlen(path);
461         char  currentDir[PATH_MAX];
462         int   currentLen;
463         char* result;
464 
465         if (getcwd(currentDir, sizeof(currentDir)) == NULL) {
466             /* Could not get the current working directory. something is really
467             * fishy here, so don't do anything and return a copy */
468             return ASTRDUP(path);
469         }
470 
471         /* Make a new path with <current-path>/<path> */
472         currentLen = strlen(currentDir);
473         result     = malloc(currentLen + pathLen + 2);
474 
475         memcpy(result, currentDir, currentLen);
476         if (currentLen == 0 || result[currentLen-1] != '/') {
477             result[currentLen++] = '/';
478         }
479         memcpy(result + currentLen, path, pathLen+1);
480 
481         return result;
482     }
483 #endif
484 }
485 
486 /** OTHER FILE UTILITIES
487  **
488  **  path_empty_file() creates an empty file at a given path location.
489  **  if the file already exists, it is truncated without warning
490  **
491  **  path_copy_file() copies one file into another.
492  **
493  **  both functions return 0 on success, and -1 on error
494  **/
495 
496 APosixStatus
path_empty_file(const char * path)497 path_empty_file( const char*  path )
498 {
499 #ifdef _WIN32
500     int  fd = _creat( path, S_IWRITE );
501 #else
502     /* on Unix, only allow the owner to read/write, since the file *
503      * may contain some personal data we don't want to see exposed */
504     int  fd = creat(path, S_IRUSR | S_IWUSR);
505 #endif
506     if (fd >= 0) {
507         close(fd);
508         return 0;
509     }
510     return -1;
511 }
512 
513 APosixStatus
path_copy_file(const char * dest,const char * source)514 path_copy_file( const char*  dest, const char*  source )
515 {
516     int  fd, fs, result = -1;
517 
518     /* if the destination doesn't exist, create it */
519     if ( access(source, F_OK)  < 0 ||
520          path_empty_file(dest) < 0) {
521         return -1;
522     }
523 
524     if ( access(source, R_OK) < 0 ) {
525         D("%s: source file is un-readable: %s\n",
526           __FUNCTION__, source);
527         return -1;
528     }
529 
530 #ifdef _WIN32
531     fd = _open(dest, _O_RDWR | _O_BINARY);
532     fs = _open(source, _O_RDONLY |  _O_BINARY);
533 #else
534     fd = creat(dest, S_IRUSR | S_IWUSR);
535     fs = open(source, S_IREAD);
536 #endif
537     if (fs >= 0 && fd >= 0) {
538         char buf[4096];
539         ssize_t total = 0;
540         ssize_t n;
541         result = 0; /* success */
542         while ((n = read(fs, buf, 4096)) > 0) {
543             if (write(fd, buf, n) != n) {
544                 /* write failed. Make it return -1 so that an
545                  * empty file be created. */
546                 D("Failed to copy '%s' to '%s': %s (%d)",
547                        source, dest, strerror(errno), errno);
548                 result = -1;
549                 break;
550             }
551             total += n;
552         }
553     }
554 
555     if (fs >= 0) {
556         close(fs);
557     }
558     if (fd >= 0) {
559         close(fd);
560     }
561     return result;
562 }
563 
564 
565 APosixStatus
path_delete_file(const char * path)566 path_delete_file( const char*  path )
567 {
568 #ifdef _WIN32
569     int  ret = _unlink( path );
570     if (ret == -1 && errno == EACCES) {
571         /* a first call to _unlink will fail if the file is set read-only */
572         /* we can however try to change its mode first and call unlink    */
573         /* again...                                                       */
574         ret = _chmod( path, _S_IREAD | _S_IWRITE );
575         if (ret == 0)
576             ret = _unlink( path );
577     }
578     return ret;
579 #else
580     return  unlink(path);
581 #endif
582 }
583 
584 
585 void*
path_load_file(const char * fn,size_t * pSize)586 path_load_file(const char *fn, size_t  *pSize)
587 {
588     char*  data;
589     int    sz;
590     int    fd;
591 
592     if (pSize)
593         *pSize = 0;
594 
595     data   = NULL;
596 
597     fd = open(fn, O_BINARY | O_RDONLY);
598     if(fd < 0) return NULL;
599 
600     do {
601         sz = lseek(fd, 0, SEEK_END);
602         if(sz < 0) break;
603 
604         if (pSize)
605             *pSize = (size_t) sz;
606 
607         if (lseek(fd, 0, SEEK_SET) != 0)
608             break;
609 
610         data = (char*) malloc(sz + 1);
611         if(data == NULL) break;
612 
613         if (read(fd, data, sz) != sz)
614             break;
615 
616         close(fd);
617         data[sz] = 0;
618 
619         return data;
620     } while (0);
621 
622     close(fd);
623 
624     if(data != NULL)
625         free(data);
626 
627     return NULL;
628 }
629 
630 #ifdef _WIN32
631 #  define DIR_SEP  ';'
632 #else
633 #  define DIR_SEP  ':'
634 #endif
635 
636 char*
path_search_exec(const char * filename)637 path_search_exec( const char* filename )
638 {
639     const char* sysPath = getenv("PATH");
640     char        temp[PATH_MAX];
641     int         count;
642     int         slen;
643     const char* p;
644 
645     /* If the file contains a directory separator, don't search */
646 #ifdef _WIN32
647     if (strchr(filename, '/') != NULL || strchr(filename, '\\') != NULL) {
648 #else
649     if (strchr(filename, '/') != NULL) {
650 #endif
651         if (path_exists(filename)) {
652             return strdup(filename);
653         } else {
654             return NULL;
655         }
656     }
657 
658     /* If system path is empty, don't search */
659     if (sysPath == NULL || sysPath[0] == '\0') {
660         return NULL;
661     }
662 
663     /* Count the number of non-empty items in the system path
664      * Items are separated by DIR_SEP, and two successive separators
665      * correspond to an empty item that will be ignored.
666      * Also compute the required string storage length. */
667     count   = 0;
668     slen    = 0;
669     p       = sysPath;
670 
671     while (*p) {
672         char* p2 = strchr(p, DIR_SEP);
673         int   len;
674         if (p2 == NULL) {
675             len = strlen(p);
676         } else {
677             len = p2 - p;
678         }
679 
680         do {
681             if (len <= 0)
682                 break;
683 
684             snprintf(temp, sizeof(temp), "%.*s/%s", len, p, filename);
685 
686             if (path_exists(temp) && path_can_exec(temp)) {
687                 return strdup(temp);
688             }
689 
690         } while (0);
691 
692         p += len;
693         if (*p == DIR_SEP)
694             p++;
695     }
696 
697     /* Nothing, really */
698     return NULL;
699 }
700