• 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/debug.h"
13 #include "android/utils/eintr_wrapper.h"
14 #include "android/utils/path.h"
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 
22 #ifdef _WIN32
23 #include <process.h>
24 #include <shlobj.h>
25 #include <tlhelp32.h>
26 #include <io.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <stdint.h>
30 #include <limits.h>
31 #include <winbase.h>
32 #else
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include <signal.h>
37 #endif
38 
39 #define  D(...)  VERBOSE_PRINT(init,__VA_ARGS__)
40 
41 /** PATH HANDLING ROUTINES
42  **
43  **  path_parent() can be used to return the n-level parent of a given directory
44  **  this understands . and .. when encountered in the input path
45  **/
46 
47 static __inline__ int
ispathsep(int c)48 ispathsep(int  c)
49 {
50 #ifdef _WIN32
51     return (c == '/' || c == '\\');
52 #else
53     return (c == '/');
54 #endif
55 }
56 
57 char*
path_parent(const char * path,int levels)58 path_parent( const char*  path, int  levels )
59 {
60     const char*  end = path + strlen(path);
61     char*        result;
62 
63     while (levels > 0) {
64         const char*  base;
65 
66         /* trim any trailing path separator */
67         while (end > path && ispathsep(end[-1]))
68             end--;
69 
70         base = end;
71         while (base > path && !ispathsep(base[-1]))
72             base--;
73 
74         if (base <= path) {
75             if (end == base+1 && base[0] == '.' && levels == 1)
76                 return strdup("..");
77           /* we can't go that far */
78             return NULL;
79         }
80 
81         if (end == base+1 && base[0] == '.')
82             goto Next;
83 
84         if (end == base+2 && base[0] == '.' && base[1] == '.') {
85             levels += 1;
86             goto Next;
87         }
88 
89         levels -= 1;
90 
91     Next:
92         end = base - 1;
93     }
94     result = malloc( end-path+1 );
95     if (result != NULL) {
96         memcpy( result, path, end-path );
97         result[end-path] = 0;
98     }
99     return result;
100 }
101 
102 static char*
substring_dup(const char * start,const char * end)103 substring_dup( const char*  start, const char*  end )
104 {
105     int    len    = end - start;
106     char*  result = android_alloc(len+1);
107     memcpy(result, start, len);
108     result[len] = 0;
109     return result;
110 }
111 
112 int
path_split(const char * path,char ** pdirname,char ** pbasename)113 path_split( const char*  path, char* *pdirname, char* *pbasename )
114 {
115     const char*  end = path + strlen(path);
116     const char*  last;
117     char*        basename;
118 
119     /* prepare for errors */
120     if (pdirname)
121         *pdirname = NULL;
122     if (pbasename)
123         *pbasename = NULL;
124 
125     /* handle empty path case */
126     if (end == path) {
127         return -1;
128     }
129 
130     /* strip trailing path separators */
131     while (end > path && ispathsep(end[-1]))
132         end -= 1;
133 
134     /* handle "/" and degenerate cases like "////" */
135     if (end == path) {
136         return -1;
137     }
138 
139     /* find last separator */
140     last = end;
141     while (last > path && !ispathsep(last[-1]))
142         last -= 1;
143 
144     /* handle cases where there is no path separator */
145     if (last == path) {
146         if (pdirname)
147             *pdirname  = ASTRDUP(".");
148         if (pbasename)
149             *pbasename = substring_dup(path,end);
150         return 0;
151     }
152 
153     /* handle "/foo" */
154     if (last == path+1) {
155         if (pdirname)
156             *pdirname  = ASTRDUP("/");
157         if (pbasename)
158             *pbasename = substring_dup(path+1,end);
159         return 0;
160     }
161 
162     /* compute basename */
163     basename = substring_dup(last,end);
164     if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) {
165         AFREE(basename);
166         return -1;
167     }
168 
169     if (pbasename)
170         *pbasename = basename;
171     else {
172         AFREE(basename);
173     }
174 
175     /* compute dirname */
176     if (pdirname != NULL)
177         *pdirname = substring_dup(path,last-1);
178 
179     return 0;
180 }
181 
182 char*
path_basename(const char * path)183 path_basename( const char*  path )
184 {
185     char*  basename;
186 
187     if (path_split(path, NULL, &basename) < 0)
188         return NULL;
189 
190     return basename;
191 }
192 
193 char*
path_dirname(const char * path)194 path_dirname( const char*  path )
195 {
196     char*  dirname;
197 
198     if (path_split(path, &dirname, NULL) < 0)
199         return NULL;
200 
201     return dirname;
202 }
203 
204 
205 
206 
207 
208 /** MISC FILE AND DIRECTORY HANDLING
209  **/
210 
211 ABool
path_exists(const char * path)212 path_exists( const char*  path )
213 {
214     if (!path)
215         return 0;
216 
217     int ret = HANDLE_EINTR(access(path, F_OK));
218     return (ret == 0) || (errno != ENOENT);
219 }
220 
221 /* checks that a path points to a regular file */
222 ABool
path_is_regular(const char * path)223 path_is_regular( const char*  path )
224 {
225     if (path == NULL)
226         return 0;
227 
228     struct stat  st;
229     int ret = HANDLE_EINTR(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     if (!path)
242         return 0;
243 
244     struct stat  st;
245     int ret = HANDLE_EINTR(stat(path, &st));
246     if (ret < 0)
247         return 0;
248 
249     return S_ISDIR(st.st_mode);
250 }
251 
252 /* checks that one can read/write a given (regular) file */
253 ABool
path_can_read(const char * path)254 path_can_read( const char*  path )
255 {
256     if (!path)
257         return 0;
258 
259     return HANDLE_EINTR(access(path, R_OK)) == 0;
260 }
261 
262 ABool
path_can_write(const char * path)263 path_can_write( const char*  path )
264 {
265     if (!path)
266         return 0;
267 
268     return HANDLE_EINTR(access(path, W_OK)) == 0;
269 }
270 
271 ABool
path_can_exec(const char * path)272 path_can_exec( const char* path )
273 {
274     if (!path)
275         return 0;
276 
277     return HANDLE_EINTR(access(path, X_OK)) == 0;
278 }
279 
280 /* try to make a directory. returns 0 on success, -1 on failure
281  * (error code in errno) */
282 APosixStatus
path_mkdir(const char * path,int mode)283 path_mkdir( const char*  path, int  mode )
284 {
285 #ifdef _WIN32
286     (void)mode;
287     return mkdir(path);
288 #else
289     return HANDLE_EINTR(mkdir(path, mode));
290 #endif
291 }
292 
293 static APosixStatus
path_mkdir_recursive(char * path,unsigned len,int mode)294 path_mkdir_recursive( char*  path, unsigned  len, int  mode )
295 {
296     char      old_c;
297     int       ret;
298     unsigned  len2;
299 
300     /* get rid of trailing separators */
301     while (len > 0 && ispathsep(path[len-1]))
302         len -= 1;
303 
304     if (len == 0) {
305         errno = ENOENT;
306         return -1;
307     }
308 
309     /* check that the parent exists, 'len2' is the length of
310      * the parent part of the path */
311     len2 = len-1;
312     while (len2 > 0 && !ispathsep(path[len2-1]))
313         len2 -= 1;
314 
315     if (len2 > 0) {
316         old_c      = path[len2];
317         path[len2] = 0;
318         ret        = 0;
319         if ( !path_exists(path) ) {
320             /* the parent doesn't exist, so try to create it */
321             ret = path_mkdir_recursive( path, len2, mode );
322         }
323         path[len2] = old_c;
324 
325         if (ret < 0)
326             return ret;
327     }
328 
329     /* at this point, we now the parent exists */
330     old_c     = path[len];
331     path[len] = 0;
332     ret       = path_mkdir( path, mode );
333     path[len] = old_c;
334 
335     return ret;
336 }
337 
338 /* ensure that a given directory exists, create it if not,
339    0 on success, -1 on failure (error code in errno) */
340 APosixStatus
path_mkdir_if_needed(const char * path,int mode)341 path_mkdir_if_needed( const char*  path, int  mode )
342 {
343     int  ret = 0;
344 
345     if (!path_exists(path)) {
346         ret = path_mkdir(path, mode);
347 
348         if (ret < 0 && errno == ENOENT) {
349             char      temp[MAX_PATH];
350             unsigned  len = (unsigned)strlen(path);
351 
352             if (len > sizeof(temp)-1) {
353                 errno = EINVAL;
354                 return -1;
355             }
356             memcpy( temp, path, len );
357             temp[len] = 0;
358 
359             return path_mkdir_recursive(temp, len, mode);
360         }
361     }
362     return ret;
363 }
364 
365 /* return the size of a given file in '*psize'. returns 0 on
366  * success, -1 on failure (error code in errno) */
367 APosixStatus
path_get_size(const char * path,uint64_t * psize)368 path_get_size( const char*  path, uint64_t  *psize )
369 {
370 #ifdef _WIN32
371     /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
372     /* do not use OpenFile() because it has strange search behaviour that could */
373     /* result in getting the size of a different file */
374     LARGE_INTEGER  size;
375     HANDLE  file = CreateFile( /* lpFilename */        path,
376                                /* dwDesiredAccess */   GENERIC_READ,
377                                /* dwSharedMode */     FILE_SHARE_READ|FILE_SHARE_WRITE,
378                                /* lpSecurityAttributes */  NULL,
379                                /* dwCreationDisposition */ OPEN_EXISTING,
380                                /* dwFlagsAndAttributes */  0,
381                                /* hTemplateFile */      NULL );
382     if (file == INVALID_HANDLE_VALUE) {
383         /* ok, just to play fair */
384         errno = ENOENT;
385         return -1;
386     }
387     if (!GetFileSizeEx(file, &size)) {
388         /* maybe we tried to get the size of a pipe or something like that ? */
389         *psize = 0;
390     }
391     else {
392         *psize = (uint64_t) size.QuadPart;
393     }
394     CloseHandle(file);
395     return 0;
396 #else
397     struct stat  st;
398     int ret = HANDLE_EINTR(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     const char* p;
642 
643     /* If the file contains a directory separator, don't search */
644 #ifdef _WIN32
645     if (strchr(filename, '/') != NULL || strchr(filename, '\\') != NULL) {
646 #else
647     if (strchr(filename, '/') != NULL) {
648 #endif
649         if (path_exists(filename)) {
650             return strdup(filename);
651         } else {
652             return NULL;
653         }
654     }
655 
656     /* If system path is empty, don't search */
657     if (sysPath == NULL || sysPath[0] == '\0') {
658         return NULL;
659     }
660 
661     /* Count the number of non-empty items in the system path
662      * Items are separated by DIR_SEP, and two successive separators
663      * correspond to an empty item that will be ignored.
664      * Also compute the required string storage length. */
665     p = sysPath;
666 
667     while (*p) {
668         char* p2 = strchr(p, DIR_SEP);
669         int   len;
670         if (p2 == NULL) {
671             len = strlen(p);
672         } else {
673             len = p2 - p;
674         }
675 
676         do {
677             if (len <= 0)
678                 break;
679 
680             snprintf(temp, sizeof(temp), "%.*s/%s", len, p, filename);
681 
682             if (path_exists(temp) && path_can_exec(temp)) {
683                 return strdup(temp);
684             }
685 
686         } while (0);
687 
688         p += len;
689         if (*p == DIR_SEP)
690             p++;
691     }
692 
693     /* Nothing, really */
694     return NULL;
695 }
696