• 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) {
82             if (end == base+1 && base[0] == '.' && levels == 1)
83                 return strdup("..");
84           /* we can't go that far */
85             return NULL;
86         }
87 
88         if (end == base+1 && base[0] == '.')
89             goto Next;
90 
91         if (end == base+2 && base[0] == '.' && base[1] == '.') {
92             levels += 1;
93             goto Next;
94         }
95 
96         levels -= 1;
97 
98     Next:
99         end = base - 1;
100     }
101     result = malloc( end-path+1 );
102     if (result != NULL) {
103         memcpy( result, path, end-path );
104         result[end-path] = 0;
105     }
106     return result;
107 }
108 
109 static char*
substring_dup(const char * start,const char * end)110 substring_dup( const char*  start, const char*  end )
111 {
112     int    len    = end - start;
113     char*  result = android_alloc(len+1);
114     memcpy(result, start, len);
115     result[len] = 0;
116     return result;
117 }
118 
119 int
path_split(const char * path,char ** pdirname,char ** pbasename)120 path_split( const char*  path, char* *pdirname, char* *pbasename )
121 {
122     const char*  end = path + strlen(path);
123     const char*  last;
124     char*        basename;
125 
126     /* prepare for errors */
127     if (pdirname)
128         *pdirname = NULL;
129     if (pbasename)
130         *pbasename = NULL;
131 
132     /* handle empty path case */
133     if (end == path) {
134         return -1;
135     }
136 
137     /* strip trailing path separators */
138     while (end > path && ispathsep(end[-1]))
139         end -= 1;
140 
141     /* handle "/" and degenerate cases like "////" */
142     if (end == path) {
143         return -1;
144     }
145 
146     /* find last separator */
147     last = end;
148     while (last > path && !ispathsep(last[-1]))
149         last -= 1;
150 
151     /* handle cases where there is no path separator */
152     if (last == path) {
153         if (pdirname)
154             *pdirname  = ASTRDUP(".");
155         if (pbasename)
156             *pbasename = substring_dup(path,end);
157         return 0;
158     }
159 
160     /* handle "/foo" */
161     if (last == path+1) {
162         if (pdirname)
163             *pdirname  = ASTRDUP("/");
164         if (pbasename)
165             *pbasename = substring_dup(path+1,end);
166         return 0;
167     }
168 
169     /* compute basename */
170     basename = substring_dup(last,end);
171     if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) {
172         AFREE(basename);
173         return -1;
174     }
175 
176     if (pbasename)
177         *pbasename = basename;
178     else {
179         AFREE(basename);
180     }
181 
182     /* compute dirname */
183     if (pdirname != NULL)
184         *pdirname = substring_dup(path,last-1);
185 
186     return 0;
187 }
188 
189 char*
path_basename(const char * path)190 path_basename( const char*  path )
191 {
192     char*  basename;
193 
194     if (path_split(path, NULL, &basename) < 0)
195         return NULL;
196 
197     return basename;
198 }
199 
200 char*
path_dirname(const char * path)201 path_dirname( const char*  path )
202 {
203     char*  dirname;
204 
205     if (path_split(path, &dirname, NULL) < 0)
206         return NULL;
207 
208     return dirname;
209 }
210 
211 
212 
213 
214 
215 /** MISC FILE AND DIRECTORY HANDLING
216  **/
217 
218 ABool
path_exists(const char * path)219 path_exists( const char*  path )
220 {
221     int  ret;
222     if (path == NULL)
223         return 0;
224     CHECKED(ret, access(path, F_OK));
225     return (ret == 0) || (errno != ENOENT);
226 }
227 
228 /* checks that a path points to a regular file */
229 ABool
path_is_regular(const char * path)230 path_is_regular( const char*  path )
231 {
232     int          ret;
233     struct stat  st;
234 
235     if (path == NULL)
236         return 0;
237     CHECKED(ret, stat(path, &st));
238     if (ret < 0)
239         return 0;
240 
241     return S_ISREG(st.st_mode);
242 }
243 
244 
245 /* checks that a path points to a directory */
246 ABool
path_is_dir(const char * path)247 path_is_dir( const char*  path )
248 {
249     int          ret;
250     struct stat  st;
251 
252     if (path == NULL)
253         return 0;
254     CHECKED(ret, stat(path, &st));
255     if (ret < 0)
256         return 0;
257 
258     return S_ISDIR(st.st_mode);
259 }
260 
261 /* checks that one can read/write a given (regular) file */
262 ABool
path_can_read(const char * path)263 path_can_read( const char*  path )
264 {
265     int  ret;
266     if (path == NULL)
267         return 0;
268     CHECKED(ret, access(path, R_OK));
269     return (ret == 0);
270 }
271 
272 ABool
path_can_write(const char * path)273 path_can_write( const char*  path )
274 {
275     int  ret;
276     if (path == NULL)
277         return 0;
278     CHECKED(ret, access(path, R_OK));
279     return (ret == 0);
280 }
281 
282 ABool
path_can_exec(const char * path)283 path_can_exec( const char* path )
284 {
285     int  ret;
286     if (path == NULL)
287         return 0;
288     CHECKED(ret, access(path, X_OK));
289     return (ret == 0);
290 }
291 
292 /* try to make a directory. returns 0 on success, -1 on failure
293  * (error code in errno) */
294 APosixStatus
path_mkdir(const char * path,int mode)295 path_mkdir( const char*  path, int  mode )
296 {
297 #ifdef _WIN32
298     (void)mode;
299     return _mkdir(path);
300 #else
301     int  ret;
302     CHECKED(ret, mkdir(path, mode));
303     return ret;
304 #endif
305 }
306 
307 static APosixStatus
path_mkdir_recursive(char * path,unsigned len,int mode)308 path_mkdir_recursive( char*  path, unsigned  len, int  mode )
309 {
310     char      old_c;
311     int       ret;
312     unsigned  len2;
313 
314     /* get rid of trailing separators */
315     while (len > 0 && ispathsep(path[len-1]))
316         len -= 1;
317 
318     if (len == 0) {
319         errno = ENOENT;
320         return -1;
321     }
322 
323     /* check that the parent exists, 'len2' is the length of
324      * the parent part of the path */
325     len2 = len-1;
326     while (len2 > 0 && !ispathsep(path[len2-1]))
327         len2 -= 1;
328 
329     if (len2 > 0) {
330         old_c      = path[len2];
331         path[len2] = 0;
332         ret        = 0;
333         if ( !path_exists(path) ) {
334             /* the parent doesn't exist, so try to create it */
335             ret = path_mkdir_recursive( path, len2, mode );
336         }
337         path[len2] = old_c;
338 
339         if (ret < 0)
340             return ret;
341     }
342 
343     /* at this point, we now the parent exists */
344     old_c     = path[len];
345     path[len] = 0;
346     ret       = path_mkdir( path, mode );
347     path[len] = old_c;
348 
349     return ret;
350 }
351 
352 /* ensure that a given directory exists, create it if not,
353    0 on success, -1 on failure (error code in errno) */
354 APosixStatus
path_mkdir_if_needed(const char * path,int mode)355 path_mkdir_if_needed( const char*  path, int  mode )
356 {
357     int  ret = 0;
358 
359     if (!path_exists(path)) {
360         ret = path_mkdir(path, mode);
361 
362         if (ret < 0 && errno == ENOENT) {
363             char      temp[MAX_PATH];
364             unsigned  len = (unsigned)strlen(path);
365 
366             if (len > sizeof(temp)-1) {
367                 errno = EINVAL;
368                 return -1;
369             }
370             memcpy( temp, path, len );
371             temp[len] = 0;
372 
373             return path_mkdir_recursive(temp, len, mode);
374         }
375     }
376     return ret;
377 }
378 
379 /* return the size of a given file in '*psize'. returns 0 on
380  * success, -1 on failure (error code in errno) */
381 APosixStatus
path_get_size(const char * path,uint64_t * psize)382 path_get_size( const char*  path, uint64_t  *psize )
383 {
384 #ifdef _WIN32
385     /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
386     /* do not use OpenFile() because it has strange search behaviour that could */
387     /* result in getting the size of a different file */
388     LARGE_INTEGER  size;
389     HANDLE  file = CreateFile( /* lpFilename */        path,
390                                /* dwDesiredAccess */   GENERIC_READ,
391                                /* dwSharedMode */     FILE_SHARE_READ|FILE_SHARE_WRITE,
392                                /* lpSecurityAttributes */  NULL,
393                                /* dwCreationDisposition */ OPEN_EXISTING,
394                                /* dwFlagsAndAttributes */  0,
395                                /* hTemplateFile */      NULL );
396     if (file == INVALID_HANDLE_VALUE) {
397         /* ok, just to play fair */
398         errno = ENOENT;
399         return -1;
400     }
401     if (!GetFileSizeEx(file, &size)) {
402         /* maybe we tried to get the size of a pipe or something like that ? */
403         *psize = 0;
404     }
405     else {
406         *psize = (uint64_t) size.QuadPart;
407     }
408     CloseHandle(file);
409     return 0;
410 #else
411     int    ret;
412     struct stat  st;
413 
414     CHECKED(ret, stat(path, &st));
415     if (ret == 0) {
416         *psize = (uint64_t) st.st_size;
417     }
418     return ret;
419 #endif
420 }
421 
422 
423 ABool
path_is_absolute(const char * path)424 path_is_absolute( const char*  path )
425 {
426 #ifdef _WIN32
427     if (path == NULL)
428         return 0;
429 
430     if (path[0] == '/' || path[0] == '\\')
431         return 1;
432 
433     /* 'C:' is always considered to be absolute
434      * even if used with a relative path like C:foo which
435      * is different from C:\foo
436      */
437     if (path[0] != 0 && path[1] == ':')
438         return 1;
439 
440     return 0;
441 #else
442     return (path != NULL && path[0] == '/');
443 #endif
444 }
445 
446 char*
path_get_absolute(const char * path)447 path_get_absolute( const char* path )
448 {
449     if (path_is_absolute(path)) {
450         return ASTRDUP(path);
451     }
452 
453 #ifdef _WIN32
454     {
455         char* result;
456         int   pathLen    = strlen(path);
457         int   currentLen = GetCurrentDirectory(0, NULL);
458 
459         if (currentLen <= 0) {
460             /* Could not get size of working directory. something is
461              * really fishy here, return a simple copy */
462             return ASTRDUP(path);
463         }
464         result = malloc(currentLen + pathLen + 2);
465 
466         GetCurrentDirectory(currentLen+1, result);
467         if (currentLen == 0 || result[currentLen-1] != '\\') {
468             result[currentLen++] = '\\';
469         }
470         memcpy(result + currentLen, path, pathLen+1);
471 
472         return result;
473     }
474 #else
475     {
476         int   pathLen    = strlen(path);
477         char  currentDir[PATH_MAX];
478         int   currentLen;
479         char* result;
480 
481         if (getcwd(currentDir, sizeof(currentDir)) == NULL) {
482             /* Could not get the current working directory. something is really
483             * fishy here, so don't do anything and return a copy */
484             return ASTRDUP(path);
485         }
486 
487         /* Make a new path with <current-path>/<path> */
488         currentLen = strlen(currentDir);
489         result     = malloc(currentLen + pathLen + 2);
490 
491         memcpy(result, currentDir, currentLen);
492         if (currentLen == 0 || result[currentLen-1] != '/') {
493             result[currentLen++] = '/';
494         }
495         memcpy(result + currentLen, path, pathLen+1);
496 
497         return result;
498     }
499 #endif
500 }
501 
502 /** OTHER FILE UTILITIES
503  **
504  **  path_empty_file() creates an empty file at a given path location.
505  **  if the file already exists, it is truncated without warning
506  **
507  **  path_copy_file() copies one file into another.
508  **
509  **  both functions return 0 on success, and -1 on error
510  **/
511 
512 APosixStatus
path_empty_file(const char * path)513 path_empty_file( const char*  path )
514 {
515 #ifdef _WIN32
516     int  fd = _creat( path, S_IWRITE );
517 #else
518     /* on Unix, only allow the owner to read/write, since the file *
519      * may contain some personal data we don't want to see exposed */
520     int  fd = creat(path, S_IRUSR | S_IWUSR);
521 #endif
522     if (fd >= 0) {
523         close(fd);
524         return 0;
525     }
526     return -1;
527 }
528 
529 APosixStatus
path_copy_file(const char * dest,const char * source)530 path_copy_file( const char*  dest, const char*  source )
531 {
532     int  fd, fs, result = -1;
533 
534     /* if the destination doesn't exist, create it */
535     if ( access(source, F_OK)  < 0 ||
536          path_empty_file(dest) < 0) {
537         return -1;
538     }
539 
540     if ( access(source, R_OK) < 0 ) {
541         D("%s: source file is un-readable: %s\n",
542           __FUNCTION__, source);
543         return -1;
544     }
545 
546 #ifdef _WIN32
547     fd = _open(dest, _O_RDWR | _O_BINARY);
548     fs = _open(source, _O_RDONLY |  _O_BINARY);
549 #else
550     fd = creat(dest, S_IRUSR | S_IWUSR);
551     fs = open(source, S_IREAD);
552 #endif
553     if (fs >= 0 && fd >= 0) {
554         char buf[4096];
555         ssize_t total = 0;
556         ssize_t n;
557         result = 0; /* success */
558         while ((n = read(fs, buf, 4096)) > 0) {
559             if (write(fd, buf, n) != n) {
560                 /* write failed. Make it return -1 so that an
561                  * empty file be created. */
562                 D("Failed to copy '%s' to '%s': %s (%d)",
563                        source, dest, strerror(errno), errno);
564                 result = -1;
565                 break;
566             }
567             total += n;
568         }
569     }
570 
571     if (fs >= 0) {
572         close(fs);
573     }
574     if (fd >= 0) {
575         close(fd);
576     }
577     return result;
578 }
579 
580 
581 APosixStatus
path_delete_file(const char * path)582 path_delete_file( const char*  path )
583 {
584 #ifdef _WIN32
585     int  ret = _unlink( path );
586     if (ret == -1 && errno == EACCES) {
587         /* a first call to _unlink will fail if the file is set read-only */
588         /* we can however try to change its mode first and call unlink    */
589         /* again...                                                       */
590         ret = _chmod( path, _S_IREAD | _S_IWRITE );
591         if (ret == 0)
592             ret = _unlink( path );
593     }
594     return ret;
595 #else
596     return  unlink(path);
597 #endif
598 }
599 
600 
601 void*
path_load_file(const char * fn,size_t * pSize)602 path_load_file(const char *fn, size_t  *pSize)
603 {
604     char*  data;
605     int    sz;
606     int    fd;
607 
608     if (pSize)
609         *pSize = 0;
610 
611     data   = NULL;
612 
613     fd = open(fn, O_BINARY | O_RDONLY);
614     if(fd < 0) return NULL;
615 
616     do {
617         sz = lseek(fd, 0, SEEK_END);
618         if(sz < 0) break;
619 
620         if (pSize)
621             *pSize = (size_t) sz;
622 
623         if (lseek(fd, 0, SEEK_SET) != 0)
624             break;
625 
626         data = (char*) malloc(sz + 1);
627         if(data == NULL) break;
628 
629         if (read(fd, data, sz) != sz)
630             break;
631 
632         close(fd);
633         data[sz] = 0;
634 
635         return data;
636     } while (0);
637 
638     close(fd);
639 
640     if(data != NULL)
641         free(data);
642 
643     return NULL;
644 }
645 
646 #ifdef _WIN32
647 #  define DIR_SEP  ';'
648 #else
649 #  define DIR_SEP  ':'
650 #endif
651 
652 char*
path_search_exec(const char * filename)653 path_search_exec( const char* filename )
654 {
655     const char* sysPath = getenv("PATH");
656     char        temp[PATH_MAX];
657     int         count;
658     int         slen;
659     const char* p;
660 
661     /* If the file contains a directory separator, don't search */
662 #ifdef _WIN32
663     if (strchr(filename, '/') != NULL || strchr(filename, '\\') != NULL) {
664 #else
665     if (strchr(filename, '/') != NULL) {
666 #endif
667         if (path_exists(filename)) {
668             return strdup(filename);
669         } else {
670             return NULL;
671         }
672     }
673 
674     /* If system path is empty, don't search */
675     if (sysPath == NULL || sysPath[0] == '\0') {
676         return NULL;
677     }
678 
679     /* Count the number of non-empty items in the system path
680      * Items are separated by DIR_SEP, and two successive separators
681      * correspond to an empty item that will be ignored.
682      * Also compute the required string storage length. */
683     count   = 0;
684     slen    = 0;
685     p       = sysPath;
686 
687     while (*p) {
688         char* p2 = strchr(p, DIR_SEP);
689         int   len;
690         if (p2 == NULL) {
691             len = strlen(p);
692         } else {
693             len = p2 - p;
694         }
695 
696         do {
697             if (len <= 0)
698                 break;
699 
700             snprintf(temp, sizeof(temp), "%.*s/%s", len, p, filename);
701 
702             if (path_exists(temp) && path_can_exec(temp)) {
703                 return strdup(temp);
704             }
705 
706         } while (0);
707 
708         p += len;
709         if (*p == DIR_SEP)
710             p++;
711     }
712 
713     /* Nothing, really */
714     return NULL;
715 }
716