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 /* try to make a directory. returns 0 on success, -1 on failure
269 * (error code in errno) */
270 APosixStatus
path_mkdir(const char * path,int mode)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
path_mkdir_recursive(char * path,unsigned len,int mode)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
path_mkdir_if_needed(const char * path,int mode)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
path_get_size(const char * path,uint64_t * psize)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
path_is_absolute(const char * path)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
path_empty_file(const char * path)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
path_copy_file(const char * dest,const char * source)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
path_delete_file(const char * path)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*
path_load_file(const char * fn,size_t * pSize)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