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 /* try to make a directory. returns 0 on success, -1 on failure 269 * (error code in errno) */ 270 APosixStatus 271 path_mkdir( const char* path, int mode ) 272 { 273 #ifdef _WIN32 274 (void)mode; 275 return _mkdir(path); 276 #else 277 int ret; 278 CHECKED(ret, mkdir(path, mode)); 279 return ret; 280 #endif 281 } 282 283 static APosixStatus 284 path_mkdir_recursive( char* path, unsigned len, int mode ) 285 { 286 char old_c; 287 int ret; 288 unsigned len2; 289 290 /* get rid of trailing separators */ 291 while (len > 0 && ispathsep(path[len-1])) 292 len -= 1; 293 294 if (len == 0) { 295 errno = ENOENT; 296 return -1; 297 } 298 299 /* check that the parent exists, 'len2' is the length of 300 * the parent part of the path */ 301 len2 = len-1; 302 while (len2 > 0 && !ispathsep(path[len2-1])) 303 len2 -= 1; 304 305 if (len2 > 0) { 306 old_c = path[len2]; 307 path[len2] = 0; 308 ret = 0; 309 if ( !path_exists(path) ) { 310 /* the parent doesn't exist, so try to create it */ 311 ret = path_mkdir_recursive( path, len2, mode ); 312 } 313 path[len2] = old_c; 314 315 if (ret < 0) 316 return ret; 317 } 318 319 /* at this point, we now the parent exists */ 320 old_c = path[len]; 321 path[len] = 0; 322 ret = path_mkdir( path, mode ); 323 path[len] = old_c; 324 325 return ret; 326 } 327 328 /* ensure that a given directory exists, create it if not, 329 0 on success, -1 on failure (error code in errno) */ 330 APosixStatus 331 path_mkdir_if_needed( const char* path, int mode ) 332 { 333 int ret = 0; 334 335 if (!path_exists(path)) { 336 ret = path_mkdir(path, mode); 337 338 if (ret < 0 && errno == ENOENT) { 339 char temp[MAX_PATH]; 340 unsigned len = (unsigned)strlen(path); 341 342 if (len > sizeof(temp)-1) { 343 errno = EINVAL; 344 return -1; 345 } 346 memcpy( temp, path, len ); 347 temp[len] = 0; 348 349 return path_mkdir_recursive(temp, len, mode); 350 } 351 } 352 return ret; 353 } 354 355 /* return the size of a given file in '*psize'. returns 0 on 356 * success, -1 on failure (error code in errno) */ 357 APosixStatus 358 path_get_size( const char* path, uint64_t *psize ) 359 { 360 #ifdef _WIN32 361 /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */ 362 /* do not use OpenFile() because it has strange search behaviour that could */ 363 /* result in getting the size of a different file */ 364 LARGE_INTEGER size; 365 HANDLE file = CreateFile( /* lpFilename */ path, 366 /* dwDesiredAccess */ GENERIC_READ, 367 /* dwSharedMode */ FILE_SHARE_READ|FILE_SHARE_WRITE, 368 /* lpSecurityAttributes */ NULL, 369 /* dwCreationDisposition */ OPEN_EXISTING, 370 /* dwFlagsAndAttributes */ 0, 371 /* hTemplateFile */ NULL ); 372 if (file == INVALID_HANDLE_VALUE) { 373 /* ok, just to play fair */ 374 errno = ENOENT; 375 return -1; 376 } 377 if (!GetFileSizeEx(file, &size)) { 378 /* maybe we tried to get the size of a pipe or something like that ? */ 379 *psize = 0; 380 } 381 else { 382 *psize = (uint64_t) size.QuadPart; 383 } 384 CloseHandle(file); 385 return 0; 386 #else 387 int ret; 388 struct stat st; 389 390 CHECKED(ret, stat(path, &st)); 391 if (ret == 0) { 392 *psize = (uint64_t) st.st_size; 393 } 394 return ret; 395 #endif 396 } 397 398 399 ABool 400 path_is_absolute( const char* path ) 401 { 402 #ifdef _WIN32 403 if (path == NULL) 404 return 0; 405 406 if (path[0] == '/' || path[0] == '\\') 407 return 1; 408 409 /* 'C:' is always considered to be absolute 410 * even if used with a relative path like C:foo which 411 * is different from C:\foo 412 */ 413 if (path[0] != 0 && path[1] == ':') 414 return 1; 415 416 return 0; 417 #else 418 return (path != NULL && path[0] == '/'); 419 #endif 420 } 421 422 423 /** OTHER FILE UTILITIES 424 ** 425 ** path_empty_file() creates an empty file at a given path location. 426 ** if the file already exists, it is truncated without warning 427 ** 428 ** path_copy_file() copies one file into another. 429 ** 430 ** both functions return 0 on success, and -1 on error 431 **/ 432 433 APosixStatus 434 path_empty_file( const char* path ) 435 { 436 #ifdef _WIN32 437 int fd = _creat( path, S_IWRITE ); 438 #else 439 /* on Unix, only allow the owner to read/write, since the file * 440 * may contain some personal data we don't want to see exposed */ 441 int fd = creat(path, S_IRUSR | S_IWUSR); 442 #endif 443 if (fd >= 0) { 444 close(fd); 445 return 0; 446 } 447 return -1; 448 } 449 450 APosixStatus 451 path_copy_file( const char* dest, const char* source ) 452 { 453 int fd, fs, result = -1; 454 455 /* if the destination doesn't exist, create it */ 456 if ( access(source, F_OK) < 0 || 457 path_empty_file(dest) < 0) { 458 return -1; 459 } 460 461 if ( access(source, R_OK) < 0 ) { 462 D("%s: source file is un-readable: %s\n", 463 __FUNCTION__, source); 464 return -1; 465 } 466 467 #ifdef _WIN32 468 fd = _open(dest, _O_RDWR | _O_BINARY); 469 fs = _open(source, _O_RDONLY | _O_BINARY); 470 #else 471 fd = creat(dest, S_IRUSR | S_IWUSR); 472 fs = open(source, S_IREAD); 473 #endif 474 if (fs >= 0 && fd >= 0) { 475 char buf[4096]; 476 ssize_t total = 0; 477 ssize_t n; 478 result = 0; /* success */ 479 while ((n = read(fs, buf, 4096)) > 0) { 480 if (write(fd, buf, n) != n) { 481 /* write failed. Make it return -1 so that an 482 * empty file be created. */ 483 D("Failed to copy '%s' to '%s': %s (%d)", 484 source, dest, strerror(errno), errno); 485 result = -1; 486 break; 487 } 488 total += n; 489 } 490 } 491 492 if (fs >= 0) { 493 close(fs); 494 } 495 if (fd >= 0) { 496 close(fd); 497 } 498 return result; 499 } 500 501 502 APosixStatus 503 path_delete_file( const char* path ) 504 { 505 #ifdef _WIN32 506 int ret = _unlink( path ); 507 if (ret == -1 && errno == EACCES) { 508 /* a first call to _unlink will fail if the file is set read-only */ 509 /* we can however try to change its mode first and call unlink */ 510 /* again... */ 511 ret = _chmod( path, _S_IREAD | _S_IWRITE ); 512 if (ret == 0) 513 ret = _unlink( path ); 514 } 515 return ret; 516 #else 517 return unlink(path); 518 #endif 519 } 520 521 522 void* 523 path_load_file(const char *fn, size_t *pSize) 524 { 525 char* data; 526 int sz; 527 int fd; 528 529 if (pSize) 530 *pSize = 0; 531 532 data = NULL; 533 534 fd = open(fn, O_BINARY | O_RDONLY); 535 if(fd < 0) return NULL; 536 537 do { 538 sz = lseek(fd, 0, SEEK_END); 539 if(sz < 0) break; 540 541 if (pSize) 542 *pSize = (size_t) sz; 543 544 if (lseek(fd, 0, SEEK_SET) != 0) 545 break; 546 547 data = (char*) malloc(sz + 1); 548 if(data == NULL) break; 549 550 if (read(fd, data, sz) != sz) 551 break; 552 553 close(fd); 554 data[sz] = 0; 555 556 return data; 557 } while (0); 558 559 close(fd); 560 561 if(data != NULL) 562 free(data); 563 564 return NULL; 565 } 566 567