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