blob: 79db972a6432f53e0bc74ceeb3859a2f22a997ab [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2008, The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8** http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17#include "installd.h"
18
Dianne Hackborn197a0c82012-07-12 14:46:04 -070019#define CACHE_NOISY(x) //x
20
Kenny Root86c95842011-03-31 13:16:12 -070021int create_pkg_path_in_dir(char path[PKG_PATH_MAX],
22 const dir_rec_t* dir,
23 const char* pkgname,
24 const char* postfix)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025{
Kenny Root86c95842011-03-31 13:16:12 -070026 const size_t postfix_len = strlen(postfix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
Kenny Root86c95842011-03-31 13:16:12 -070028 const size_t pkgname_len = strlen(pkgname);
29 if (pkgname_len > PKG_NAME_MAX) {
30 return -1;
31 }
32
33 if (is_valid_package_name(pkgname) < 0) {
34 return -1;
35 }
36
37 if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) {
38 return -1;
39 }
40
41 char *dst = path;
42 size_t dst_size = PKG_PATH_MAX;
43
44 if (append_and_increment(&dst, dir->path, &dst_size) < 0
45 || append_and_increment(&dst, pkgname, &dst_size) < 0
46 || append_and_increment(&dst, postfix, &dst_size) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000047 ALOGE("Error building APK path");
Kenny Root86c95842011-03-31 13:16:12 -070048 return -1;
49 }
50
51 return 0;
52}
53
54/**
55 * Create the package path name for a given package name with a postfix for
56 * a certain persona. Returns 0 on success, and -1 on failure.
57 */
58int create_pkg_path(char path[PKG_PATH_MAX],
59 const char *pkgname,
60 const char *postfix,
61 uid_t persona)
62{
63 size_t uid_len;
64 char* persona_prefix;
65 if (persona == 0) {
66 persona_prefix = PRIMARY_USER_PREFIX;
67 uid_len = 0;
68 } else {
69 persona_prefix = SECONDARY_USER_PREFIX;
70 uid_len = snprintf(NULL, 0, "%d", persona);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 }
Kenny Root86c95842011-03-31 13:16:12 -070072
73 const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/;
74 char prefix[prefix_len + 1];
75
76 char *dst = prefix;
77 size_t dst_size = sizeof(prefix);
78
79 if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
80 || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000081 ALOGE("Error building prefix for APK path");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 return -1;
83 }
84
Kenny Root86c95842011-03-31 13:16:12 -070085 if (persona != 0) {
86 int ret = snprintf(dst, dst_size, "%d/", persona);
87 if (ret < 0 || (size_t) ret != uid_len + 1) {
Steve Block8564c8d2012-01-05 23:22:43 +000088 ALOGW("Error appending UID to APK path");
Kenny Root86c95842011-03-31 13:16:12 -070089 return -1;
90 }
91 }
92
93 dir_rec_t dir;
94 dir.path = prefix;
95 dir.len = prefix_len;
96
97 return create_pkg_path_in_dir(path, &dir, pkgname, postfix);
98}
99
100/**
Amith Yamasani0b285492011-04-14 17:35:23 -0700101 * Create the path name for user data for a certain persona.
102 * Returns 0 on success, and -1 on failure.
103 */
104int create_persona_path(char path[PKG_PATH_MAX],
105 uid_t persona)
106{
107 size_t uid_len;
108 char* persona_prefix;
109 if (persona == 0) {
110 persona_prefix = PRIMARY_USER_PREFIX;
111 uid_len = 0;
112 } else {
113 persona_prefix = SECONDARY_USER_PREFIX;
Kenny Rootad757e92011-11-29 15:54:55 -0800114 uid_len = snprintf(NULL, 0, "%d/", persona);
Amith Yamasani0b285492011-04-14 17:35:23 -0700115 }
116
117 char *dst = path;
118 size_t dst_size = PKG_PATH_MAX;
119
120 if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
121 || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000122 ALOGE("Error building prefix for user path");
Amith Yamasani0b285492011-04-14 17:35:23 -0700123 return -1;
124 }
125
126 if (persona != 0) {
127 if (dst_size < uid_len + 1) {
Steve Block3762c312012-01-06 19:20:56 +0000128 ALOGE("Error building user path");
Amith Yamasani0b285492011-04-14 17:35:23 -0700129 return -1;
130 }
Kenny Rootad757e92011-11-29 15:54:55 -0800131 int ret = snprintf(dst, dst_size, "%d/", persona);
Amith Yamasani0b285492011-04-14 17:35:23 -0700132 if (ret < 0 || (size_t) ret != uid_len) {
Steve Block3762c312012-01-06 19:20:56 +0000133 ALOGE("Error appending persona id to path");
Amith Yamasani0b285492011-04-14 17:35:23 -0700134 return -1;
135 }
136 }
137 return 0;
138}
139
Kenny Rootad757e92011-11-29 15:54:55 -0800140int create_move_path(char path[PKG_PATH_MAX],
141 const char* pkgname,
142 const char* leaf,
143 uid_t persona)
144{
145 if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
146 >= PKG_PATH_MAX) {
147 return -1;
148 }
149
150 sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
151 return 0;
152}
153
Amith Yamasani0b285492011-04-14 17:35:23 -0700154/**
Kenny Root86c95842011-03-31 13:16:12 -0700155 * Checks whether the package name is valid. Returns -1 on error and
156 * 0 on success.
157 */
158int is_valid_package_name(const char* pkgname) {
159 const char *x = pkgname;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800160 int alpha = -1;
Kenny Root86c95842011-03-31 13:16:12 -0700161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 while (*x) {
163 if (isalnum(*x) || (*x == '_')) {
164 /* alphanumeric or underscore are fine */
165 } else if (*x == '.') {
166 if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) {
167 /* periods must not be first, last, or doubled */
Steve Block3762c312012-01-06 19:20:56 +0000168 ALOGE("invalid package name '%s'\n", pkgname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 return -1;
170 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800171 } else if (*x == '-') {
172 /* Suffix -X is fine to let versioning of packages.
173 But whatever follows should be alphanumeric.*/
174 alpha = 1;
Kenny Root86c95842011-03-31 13:16:12 -0700175 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 /* anything not A-Z, a-z, 0-9, _, or . is invalid */
Steve Block3762c312012-01-06 19:20:56 +0000177 ALOGE("invalid package name '%s'\n", pkgname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 return -1;
179 }
Kenny Root86c95842011-03-31 13:16:12 -0700180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 x++;
182 }
Kenny Root86c95842011-03-31 13:16:12 -0700183
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800184 if (alpha == 1) {
185 // Skip current character
186 x++;
187 while (*x) {
188 if (!isalnum(*x)) {
Steve Block3762c312012-01-06 19:20:56 +0000189 ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800190 return -1;
191 }
192 x++;
193 }
194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 return 0;
197}
198
199static int _delete_dir_contents(DIR *d, const char *ignore)
200{
201 int result = 0;
202 struct dirent *de;
203 int dfd;
204
205 dfd = dirfd(d);
206
207 if (dfd < 0) return -1;
208
209 while ((de = readdir(d))) {
210 const char *name = de->d_name;
211
212 /* skip the ignore name if provided */
213 if (ignore && !strcmp(name, ignore)) continue;
214
215 if (de->d_type == DT_DIR) {
216 int r, subfd;
217 DIR *subdir;
218
219 /* always skip "." and ".." */
220 if (name[0] == '.') {
221 if (name[1] == 0) continue;
222 if ((name[1] == '.') && (name[2] == 0)) continue;
223 }
224
225 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
226 if (subfd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000227 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 result = -1;
229 continue;
230 }
231 subdir = fdopendir(subfd);
232 if (subdir == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000233 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 close(subfd);
235 result = -1;
236 continue;
237 }
238 if (_delete_dir_contents(subdir, 0)) {
239 result = -1;
240 }
241 closedir(subdir);
242 if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000243 ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 result = -1;
245 }
246 } else {
247 if (unlinkat(dfd, name, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000248 ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 result = -1;
250 }
251 }
252 }
253
254 return result;
255}
256
257int delete_dir_contents(const char *pathname,
258 int also_delete_dir,
259 const char *ignore)
260{
261 int res = 0;
262 DIR *d;
263
264 d = opendir(pathname);
265 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000266 ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 return -errno;
268 }
269 res = _delete_dir_contents(d, ignore);
270 closedir(d);
271 if (also_delete_dir) {
272 if (rmdir(pathname)) {
Steve Block3762c312012-01-06 19:20:56 +0000273 ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 res = -1;
275 }
276 }
277 return res;
278}
279
280int delete_dir_contents_fd(int dfd, const char *name)
281{
282 int fd, res;
283 DIR *d;
284
285 fd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
286 if (fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000287 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 return -1;
289 }
290 d = fdopendir(fd);
291 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000292 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 close(fd);
294 return -1;
295 }
296 res = _delete_dir_contents(d, 0);
297 closedir(d);
298 return res;
299}
Kenny Root86c95842011-03-31 13:16:12 -0700300
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700301int lookup_media_dir(char basepath[PATH_MAX], const char *dir)
302{
303 DIR *d;
304 struct dirent *de;
305 struct stat s;
306 char* dirpos = basepath + strlen(basepath);
307
308 if ((*(dirpos-1)) != '/') {
309 *dirpos = '/';
310 dirpos++;
311 }
312
313 CACHE_NOISY(ALOGI("Looking up %s in %s\n", dir, basepath));
314 // Verify the path won't extend beyond our buffer, to avoid
315 // repeated checking later.
316 if ((dirpos-basepath+strlen(dir)) >= (PATH_MAX-1)) {
317 ALOGW("Path exceeds limit: %s%s", basepath, dir);
318 return -1;
319 }
320
321 // First, can we find this directory with the case that is given?
322 strcpy(dirpos, dir);
323 if (stat(basepath, &s) >= 0) {
324 CACHE_NOISY(ALOGI("Found direct: %s\n", basepath));
325 return 0;
326 }
327
328 // Not found with that case... search through all entries to find
329 // one that matches regardless of case.
330 *dirpos = 0;
331
332 d = opendir(basepath);
333 if (d == NULL) {
334 return -1;
335 }
336
337 while ((de = readdir(d))) {
338 if (strcasecmp(de->d_name, dir) == 0) {
339 strcpy(dirpos, de->d_name);
340 closedir(d);
341 CACHE_NOISY(ALOGI("Found search: %s\n", basepath));
342 return 0;
343 }
344 }
345
346 ALOGW("Couldn't find %s in %s", dir, basepath);
347 closedir(d);
348 return -1;
349}
350
351int64_t data_disk_free()
352{
353 struct statfs sfs;
354 if (statfs(android_data_dir.path, &sfs) == 0) {
355 return sfs.f_bavail * sfs.f_bsize;
356 } else {
357 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
358 return -1;
359 }
360}
361
362cache_t* start_cache_collection()
363{
364 cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t));
365 return cache;
366}
367
368#define CACHE_BLOCK_SIZE (512*1024)
369
370static void* _cache_malloc(cache_t* cache, size_t len)
371{
372 len = (len+3)&~3;
373 if (len > (CACHE_BLOCK_SIZE/2)) {
374 // It doesn't make sense to try to put this allocation into one
375 // of our blocks, because it is so big. Instead, make a new dedicated
376 // block for it.
377 int8_t* res = (int8_t*)malloc(len+sizeof(void*));
378 if (res == NULL) {
379 return NULL;
380 }
381 CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %d", res, len));
382 // Link it into our list of blocks, not disrupting the current one.
383 if (cache->memBlocks == NULL) {
384 *(void**)res = NULL;
385 cache->memBlocks = res;
386 } else {
387 *(void**)res = *(void**)cache->memBlocks;
388 *(void**)cache->memBlocks = res;
389 }
390 return res + sizeof(void*);
391 }
392 int8_t* res = cache->curMemBlockAvail;
393 int8_t* nextPos = res + len;
394 if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) {
395 int8_t* newBlock = malloc(CACHE_BLOCK_SIZE);
396 if (newBlock == NULL) {
397 return NULL;
398 }
399 CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock));
400 *(void**)newBlock = cache->memBlocks;
401 cache->memBlocks = newBlock;
402 res = cache->curMemBlockAvail = newBlock + sizeof(void*);
403 cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE;
404 nextPos = res + len;
405 }
406 CACHE_NOISY(ALOGI("cache_malloc: ret %p size %d, block=%p, nextPos=%p",
407 res, len, cache->memBlocks, nextPos));
408 cache->curMemBlockAvail = nextPos;
409 return res;
410}
411
412static void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len)
413{
414 // This isn't really a realloc, but it is good enough for our purposes here.
415 void* alloc = _cache_malloc(cache, len);
416 if (alloc != NULL && cur != NULL) {
417 memcpy(alloc, cur, origLen < len ? origLen : len);
418 }
419 return alloc;
420}
421
422static void _inc_num_cache_collected(cache_t* cache)
423{
424 cache->numCollected++;
425 if ((cache->numCollected%20000) == 0) {
426 ALOGI("Collected cache so far: %d directories, %d files",
427 cache->numDirs, cache->numFiles);
428 }
429}
430
431static cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name)
432{
433 size_t nameLen = strlen(name);
434 cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1);
435 if (dir != NULL) {
436 dir->parent = parent;
437 dir->childCount = 0;
438 dir->hiddenCount = 0;
439 dir->deleted = 0;
440 strcpy(dir->name, name);
441 if (cache->numDirs >= cache->availDirs) {
442 size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2;
443 cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs,
444 cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*));
445 if (newDirs == NULL) {
446 ALOGE("Failure growing cache dirs array for %s\n", name);
447 return NULL;
448 }
449 cache->availDirs = newAvail;
450 cache->dirs = newDirs;
451 }
452 cache->dirs[cache->numDirs] = dir;
453 cache->numDirs++;
454 if (parent != NULL) {
455 parent->childCount++;
456 }
457 _inc_num_cache_collected(cache);
458 } else {
459 ALOGE("Failure allocating cache_dir_t for %s\n", name);
460 }
461 return dir;
462}
463
464static cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime,
465 const char *name)
466{
467 size_t nameLen = strlen(name);
468 cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1);
469 if (file != NULL) {
470 file->dir = dir;
471 file->modTime = modTime;
472 strcpy(file->name, name);
473 if (cache->numFiles >= cache->availFiles) {
474 size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2;
475 cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files,
476 cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*));
477 if (newFiles == NULL) {
478 ALOGE("Failure growing cache file array for %s\n", name);
479 return NULL;
480 }
481 cache->availFiles = newAvail;
482 cache->files = newFiles;
483 }
484 CACHE_NOISY(ALOGI("Setting file %p at position %d in array %p", file,
485 cache->numFiles, cache->files));
486 cache->files[cache->numFiles] = file;
487 cache->numFiles++;
488 dir->childCount++;
489 _inc_num_cache_collected(cache);
490 } else {
491 ALOGE("Failure allocating cache_file_t for %s\n", name);
492 }
493 return file;
494}
495
496static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName,
497 DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen)
498{
499 struct dirent *de;
500 cache_dir_t* cacheDir = NULL;
501 int dfd;
502
503 CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s",
504 parentDir, dirName, dir, pathBase));
505
506 dfd = dirfd(dir);
507
508 if (dfd < 0) return 0;
509
510 // Sub-directories always get added to the data structure, so if they
511 // are empty we will know about them to delete them later.
512 cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
513
514 while ((de = readdir(dir))) {
515 const char *name = de->d_name;
516
517 if (de->d_type == DT_DIR) {
518 int subfd;
519 DIR *subdir;
520
521 /* always skip "." and ".." */
522 if (name[0] == '.') {
523 if (name[1] == 0) continue;
524 if ((name[1] == '.') && (name[2] == 0)) continue;
525 }
526
527 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
528 if (subfd < 0) {
529 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
530 continue;
531 }
532 subdir = fdopendir(subfd);
533 if (subdir == NULL) {
534 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
535 close(subfd);
536 continue;
537 }
538 if (cacheDir == NULL) {
539 cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
540 }
541 if (cacheDir != NULL) {
542 // Update pathBase for the new path... this may change dirName
543 // if that is also pointing to the path, but we are done with it
544 // now.
545 size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
546 CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase));
547 if (finallen < pathAvailLen) {
548 _add_cache_files(cache, cacheDir, name, subdir, pathBase,
549 pathPos+finallen, pathAvailLen-finallen);
550 } else {
551 // Whoops, the final path is too long! We'll just delete
552 // this directory.
553 ALOGW("Cache dir %s truncated in path %s; deleting dir\n",
554 name, pathBase);
555 _delete_dir_contents(subdir, NULL);
556 if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
557 ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
558 }
559 }
560 }
561 closedir(subdir);
562 } else if (de->d_type == DT_REG) {
563 // Skip files that start with '.'; they will be deleted if
564 // their entire directory is deleted. This allows for metadata
565 // like ".nomedia" to remain in the directory until the entire
566 // directory is deleted.
567 if (cacheDir == NULL) {
568 cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
569 }
570 if (name[0] == '.') {
571 cacheDir->hiddenCount++;
572 continue;
573 }
574 if (cacheDir != NULL) {
575 // Build final full path for file... this may change dirName
576 // if that is also pointing to the path, but we are done with it
577 // now.
578 size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
579 CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase));
580 if (finallen < pathAvailLen) {
581 struct stat s;
582 if (stat(pathBase, &s) >= 0) {
583 _add_cache_file_t(cache, cacheDir, s.st_mtime, name);
584 } else {
585 ALOGW("Unable to stat cache file %s; deleting\n", pathBase);
586 if (unlink(pathBase) < 0) {
587 ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno));
588 }
589 }
590 } else {
591 // Whoops, the final path is too long! We'll just delete
592 // this file.
593 ALOGW("Cache file %s truncated in path %s; deleting\n",
594 name, pathBase);
595 if (unlinkat(dfd, name, 0) < 0) {
596 *pathPos = 0;
597 ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase,
598 strerror(errno));
599 }
600 }
601 }
602 } else {
603 cacheDir->hiddenCount++;
604 }
605 }
606 return 0;
607}
608
609void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir)
610{
611 DIR *d;
612 struct dirent *de;
613 char dirname[PATH_MAX];
614
615 CACHE_NOISY(ALOGI("add_cache_files: base=%s cachedir=%s\n", basepath, cachedir));
616
617 d = opendir(basepath);
618 if (d == NULL) {
619 return;
620 }
621
622 while ((de = readdir(d))) {
623 if (de->d_type == DT_DIR) {
624 DIR* subdir;
625 const char *name = de->d_name;
626 char* pathpos;
627
628 /* always skip "." and ".." */
629 if (name[0] == '.') {
630 if (name[1] == 0) continue;
631 if ((name[1] == '.') && (name[2] == 0)) continue;
632 }
633
634 strcpy(dirname, basepath);
635 pathpos = dirname + strlen(dirname);
636 if ((*(pathpos-1)) != '/') {
637 *pathpos = '/';
638 pathpos++;
639 *pathpos = 0;
640 }
641 if (cachedir != NULL) {
642 snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s/%s", name, cachedir);
643 } else {
644 snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s", name);
645 }
646 CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname));
647 subdir = opendir(dirname);
648 if (subdir != NULL) {
649 size_t dirnameLen = strlen(dirname);
650 _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen,
651 PATH_MAX - dirnameLen);
652 closedir(subdir);
653 }
654 }
655 }
656
657 closedir(d);
658}
659
660static char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir)
661{
662 char *pos = path;
663 if (dir->parent != NULL) {
664 pos = create_dir_path(path, dir->parent);
665 }
666 // Note that we don't need to worry about going beyond the buffer,
667 // since when we were constructing the cache entries our maximum
668 // buffer size for full paths was PATH_MAX.
669 strcpy(pos, dir->name);
670 pos += strlen(pos);
671 *pos = '/';
672 pos++;
673 *pos = 0;
674 return pos;
675}
676
677static void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir)
678{
679 if (dir->parent != NULL) {
680 create_dir_path(path, dir);
681 ALOGI("DEL DIR %s\n", path);
682 if (dir->hiddenCount <= 0) {
683 if (rmdir(path)) {
684 ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno));
685 return;
686 }
687 } else {
688 // The directory contains hidden files so we need to delete
689 // them along with the directory itself.
690 if (delete_dir_contents(path, 1, NULL)) {
691 return;
692 }
693 }
694 dir->parent->childCount--;
695 dir->deleted = 1;
696 if (dir->parent->childCount <= 0) {
697 delete_cache_dir(path, dir->parent);
698 }
699 } else if (dir->hiddenCount > 0) {
700 // This is a root directory, but it has hidden files. Get rid of
701 // all of those files, but not the directory itself.
702 create_dir_path(path, dir);
703 ALOGI("DEL CONTENTS %s\n", path);
704 delete_dir_contents(path, 0, NULL);
705 }
706}
707
708static int cache_modtime_sort(const void *lhsP, const void *rhsP)
709{
710 const cache_file_t *lhs = *(const cache_file_t**)lhsP;
711 const cache_file_t *rhs = *(const cache_file_t**)rhsP;
712 return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0);
713}
714
715void clear_cache_files(cache_t* cache, int64_t free_size)
716{
717 size_t i;
718 int skip = 0;
719 char path[PATH_MAX];
720
721 ALOGI("Collected cache files: %d directories, %d files",
722 cache->numDirs, cache->numFiles);
723
724 CACHE_NOISY(ALOGI("Sorting files..."));
725 qsort(cache->files, cache->numFiles, sizeof(cache_file_t*),
726 cache_modtime_sort);
727
728 CACHE_NOISY(ALOGI("Cleaning empty directories..."));
729 for (i=cache->numDirs; i>0; i--) {
730 cache_dir_t* dir = cache->dirs[i-1];
731 if (dir->childCount <= 0 && !dir->deleted) {
732 delete_cache_dir(path, dir);
733 }
734 }
735
736 CACHE_NOISY(ALOGI("Trimming files..."));
737 for (i=0; i<cache->numFiles; i++) {
738 skip++;
739 if (skip > 10) {
740 if (data_disk_free() > free_size) {
741 return;
742 }
743 skip = 0;
744 }
745 cache_file_t* file = cache->files[i];
746 strcpy(create_dir_path(path, file->dir), file->name);
747 ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path);
748 if (unlink(path) < 0) {
749 ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno));
750 }
751 file->dir->childCount--;
752 if (file->dir->childCount <= 0) {
753 delete_cache_dir(path, file->dir);
754 }
755 }
756}
757
758void finish_cache_collection(cache_t* cache)
759{
760 size_t i;
761
762 CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles));
763 CACHE_NOISY(
764 for (i=0; i<cache->numDirs; i++) {
765 cache_dir_t* dir = cache->dirs[i];
766 ALOGI("dir #%d: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
767 })
768 CACHE_NOISY(
769 for (i=0; i<cache->numFiles; i++) {
770 cache_file_t* file = cache->files[i];
771 ALOGI("file #%d: %p %s time=%d dir=%p\n", i, file, file->name,
772 (int)file->modTime, file->dir);
773 })
774 void* block = cache->memBlocks;
775 while (block != NULL) {
776 void* nextBlock = *(void**)block;
777 CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block));
778 free(block);
779 block = nextBlock;
780 }
781 free(cache);
782}
783
Kenny Root86c95842011-03-31 13:16:12 -0700784/**
785 * Checks whether a path points to a system app (.apk file). Returns 0
786 * if it is a system app or -1 if it is not.
787 */
788int validate_system_app_path(const char* path) {
789 size_t i;
790
791 for (i = 0; i < android_system_dirs.count; i++) {
792 const size_t dir_len = android_system_dirs.dirs[i].len;
793 if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
794 if (path[dir_len] == '.' || strchr(path + dir_len, '/') != NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000795 ALOGE("invalid system apk path '%s' (trickery)\n", path);
Kenny Root86c95842011-03-31 13:16:12 -0700796 return -1;
797 }
798 return 0;
799 }
800 }
801
802 return -1;
803}
804
805/**
806 * Get the contents of a environment variable that contains a path. Caller
807 * owns the string that is inserted into the directory record. Returns
808 * 0 on success and -1 on error.
809 */
810int get_path_from_env(dir_rec_t* rec, const char* var) {
811 const char* path = getenv(var);
812 int ret = get_path_from_string(rec, path);
813 if (ret < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000814 ALOGW("Problem finding value for environment variable %s\n", var);
Kenny Root86c95842011-03-31 13:16:12 -0700815 }
816 return ret;
817}
818
819/**
820 * Puts the string into the record as a directory. Appends '/' to the end
821 * of all paths. Caller owns the string that is inserted into the directory
822 * record. A null value will result in an error.
823 *
824 * Returns 0 on success and -1 on error.
825 */
826int get_path_from_string(dir_rec_t* rec, const char* path) {
827 if (path == NULL) {
828 return -1;
829 } else {
830 const size_t path_len = strlen(path);
831 if (path_len <= 0) {
832 return -1;
833 }
834
835 // Make sure path is absolute.
836 if (path[0] != '/') {
837 return -1;
838 }
839
840 if (path[path_len - 1] == '/') {
841 // Path ends with a forward slash. Make our own copy.
842
843 rec->path = strdup(path);
844 if (rec->path == NULL) {
845 return -1;
846 }
847
848 rec->len = path_len;
849 } else {
850 // Path does not end with a slash. Generate a new string.
851 char *dst;
852
853 // Add space for slash and terminating null.
854 size_t dst_size = path_len + 2;
855
856 rec->path = malloc(dst_size);
857 if (rec->path == NULL) {
858 return -1;
859 }
860
861 dst = rec->path;
862
863 if (append_and_increment(&dst, path, &dst_size) < 0
864 || append_and_increment(&dst, "/", &dst_size)) {
Steve Block3762c312012-01-06 19:20:56 +0000865 ALOGE("Error canonicalizing path");
Kenny Root86c95842011-03-31 13:16:12 -0700866 return -1;
867 }
868
869 rec->len = dst - rec->path;
870 }
871 }
872 return 0;
873}
874
875int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
876 dst->len = src->len + strlen(suffix);
877 const size_t dstSize = dst->len + 1;
878 dst->path = (char*) malloc(dstSize);
879
880 if (dst->path == NULL
881 || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
882 != (ssize_t) dst->len) {
Steve Block3762c312012-01-06 19:20:56 +0000883 ALOGE("Could not allocate memory to hold appended path; aborting\n");
Kenny Root86c95842011-03-31 13:16:12 -0700884 return -1;
885 }
886
887 return 0;
888}
889
890/**
891 * Check whether path points to a valid path for an APK file. An ASEC
892 * directory is allowed to have one level of subdirectory names. Returns -1
893 * when an invalid path is encountered and 0 when a valid path is encountered.
894 */
895int validate_apk_path(const char *path)
896{
897 int allowsubdir = 0;
898 char *subdir = NULL;
899 size_t dir_len;
900 size_t path_len;
901
902 if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
903 dir_len = android_app_dir.len;
904 } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
905 dir_len = android_app_private_dir.len;
906 } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
907 dir_len = android_asec_dir.len;
908 allowsubdir = 1;
909 } else {
Steve Block3762c312012-01-06 19:20:56 +0000910 ALOGE("invalid apk path '%s' (bad prefix)\n", path);
Kenny Root86c95842011-03-31 13:16:12 -0700911 return -1;
912 }
913
914 path_len = strlen(path);
915
916 /*
917 * Only allow the path to have a subdirectory if it's been marked as being allowed.
918 */
919 if ((subdir = strchr(path + dir_len, '/')) != NULL) {
920 ++subdir;
921 if (!allowsubdir
922 || (path_len > (size_t) (subdir - path) && (strchr(subdir, '/') != NULL))) {
Steve Block3762c312012-01-06 19:20:56 +0000923 ALOGE("invalid apk path '%s' (subdir?)\n", path);
Kenny Root86c95842011-03-31 13:16:12 -0700924 return -1;
925 }
926 }
927
928 /*
929 * Directories can't have a period directly after the directory markers
930 * to prevent ".."
931 */
932 if (path[dir_len] == '.'
933 || (subdir != NULL && ((*subdir == '.') || (strchr(subdir, '/') != NULL)))) {
Steve Block3762c312012-01-06 19:20:56 +0000934 ALOGE("invalid apk path '%s' (trickery)\n", path);
Kenny Root86c95842011-03-31 13:16:12 -0700935 return -1;
936 }
937
938 return 0;
939}
940
941int append_and_increment(char** dst, const char* src, size_t* dst_size) {
942 ssize_t ret = strlcpy(*dst, src, *dst_size);
943 if (ret < 0 || (size_t) ret >= *dst_size) {
944 return -1;
945 }
946 *dst += ret;
947 *dst_size -= ret;
948 return 0;
949}
Amith Yamasani0b285492011-04-14 17:35:23 -0700950
951char *build_string2(char *s1, char *s2) {
952 if (s1 == NULL || s2 == NULL) return NULL;
953
954 int len_s1 = strlen(s1);
955 int len_s2 = strlen(s2);
956 int len = len_s1 + len_s2 + 1;
957 char *result = malloc(len);
958 if (result == NULL) return NULL;
959
960 strcpy(result, s1);
961 strcpy(result + len_s1, s2);
962
963 return result;
964}
965
966char *build_string3(char *s1, char *s2, char *s3) {
967 if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
968
969 int len_s1 = strlen(s1);
970 int len_s2 = strlen(s2);
971 int len_s3 = strlen(s3);
972 int len = len_s1 + len_s2 + len_s3 + 1;
973 char *result = malloc(len);
974 if (result == NULL) return NULL;
975
976 strcpy(result, s1);
977 strcpy(result + len_s1, s2);
978 strcpy(result + len_s1 + len_s2, s3);
979
980 return result;
981}