utils.c revision 197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0ac
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
21int 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 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);
71    }
72
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) {
81        ALOGE("Error building prefix for APK path");
82        return -1;
83    }
84
85    if (persona != 0) {
86        int ret = snprintf(dst, dst_size, "%d/", persona);
87        if (ret < 0 || (size_t) ret != uid_len + 1) {
88            ALOGW("Error appending UID to APK path");
89            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/**
101 * 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;
114        uid_len = snprintf(NULL, 0, "%d/", persona);
115    }
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) {
122        ALOGE("Error building prefix for user path");
123        return -1;
124    }
125
126    if (persona != 0) {
127        if (dst_size < uid_len + 1) {
128            ALOGE("Error building user path");
129            return -1;
130        }
131        int ret = snprintf(dst, dst_size, "%d/", persona);
132        if (ret < 0 || (size_t) ret != uid_len) {
133            ALOGE("Error appending persona id to path");
134            return -1;
135        }
136    }
137    return 0;
138}
139
140int 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
154/**
155 * 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;
160    int alpha = -1;
161
162    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 */
168                ALOGE("invalid package name '%s'\n", pkgname);
169                return -1;
170            }
171        } else if (*x == '-') {
172            /* Suffix -X is fine to let versioning of packages.
173               But whatever follows should be alphanumeric.*/
174            alpha = 1;
175        } else {
176                /* anything not A-Z, a-z, 0-9, _, or . is invalid */
177            ALOGE("invalid package name '%s'\n", pkgname);
178            return -1;
179        }
180
181        x++;
182    }
183
184    if (alpha == 1) {
185        // Skip current character
186        x++;
187        while (*x) {
188            if (!isalnum(*x)) {
189                ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
190                return -1;
191            }
192            x++;
193        }
194    }
195
196    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) {
227                ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
228                result = -1;
229                continue;
230            }
231            subdir = fdopendir(subfd);
232            if (subdir == NULL) {
233                ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
234                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) {
243                ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
244                result = -1;
245            }
246        } else {
247            if (unlinkat(dfd, name, 0) < 0) {
248                ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
249                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) {
266        ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
267        return -errno;
268    }
269    res = _delete_dir_contents(d, ignore);
270    closedir(d);
271    if (also_delete_dir) {
272        if (rmdir(pathname)) {
273            ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
274            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) {
287        ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
288        return -1;
289    }
290    d = fdopendir(fd);
291    if (d == NULL) {
292        ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
293        close(fd);
294        return -1;
295    }
296    res = _delete_dir_contents(d, 0);
297    closedir(d);
298    return res;
299}
300
301int 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
784/**
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) {
795                ALOGE("invalid system apk path '%s' (trickery)\n", path);
796                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) {
814        ALOGW("Problem finding value for environment variable %s\n", var);
815    }
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)) {
865                ALOGE("Error canonicalizing path");
866                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) {
883        ALOGE("Could not allocate memory to hold appended path; aborting\n");
884        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 {
910        ALOGE("invalid apk path '%s' (bad prefix)\n", path);
911        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))) {
923            ALOGE("invalid apk path '%s' (subdir?)\n", path);
924            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)))) {
934        ALOGE("invalid apk path '%s' (trickery)\n", path);
935        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}
950
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}
982