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) /* 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*
substring_dup(const char * start,const char * end)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
path_split(const char * path,char ** pdirname,char ** pbasename)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*
path_basename(const char * path)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*
path_dirname(const char * path)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
path_exists(const char * path)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
path_is_regular(const char * path)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
path_is_dir(const char * path)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
path_can_read(const char * path)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
path_can_write(const char * path)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
path_can_exec(const char * path)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
path_mkdir(const char * path,int mode)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
path_mkdir_recursive(char * path,unsigned len,int mode)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
path_mkdir_if_needed(const char * path,int mode)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
path_get_size(const char * path,uint64_t * psize)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
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 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