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