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) /* 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* 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 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* 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* 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 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 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 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 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 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 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 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 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 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 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 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* 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 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 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 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* 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* 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