static int _delete_dir_contents(DIR *d,
                                int (*exclusion_predicate)(const char *name, const int is_dir))
{
    int result = 0;
    struct dirent *de;
    int dfd;

    dfd = dirfd(d);

    if (dfd < 0) return -1;

    while ((de = readdir(d))) {
        const char *name = de->d_name;

            /* check using the exclusion predicate, if provided */
        if (exclusion_predicate && exclusion_predicate(name, (de->d_type == DT_DIR))) {
            continue;
        }

        if (de->d_type == DT_DIR) {
            int r, subfd;
            DIR *subdir;

                /* always skip "." and ".." */
            if (name[0] == '.') {
                if (name[1] == 0) continue;
                if ((name[1] == '.') && (name[2] == 0)) continue;
            }

            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
            if (subfd < 0) {
                ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
                result = -1;
                continue;
            }
            subdir = fdopendir(subfd);
            if (subdir == NULL) {
                ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
                close(subfd);
                result = -1;
                continue;
            }
            if (_delete_dir_contents(subdir, exclusion_predicate)) {
                result = -1;
            }
            closedir(subdir);
            if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
                ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
                result = -1;
            }
        } else {
            if (unlinkat(dfd, name, 0) < 0) {
                ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
                result = -1;
            }
        }
    }

    return result;
}
Пример #2
0
int delete_dir_contents_fd(int dfd, const char *name)
{
    int fd, res;
    DIR *d;

    fd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
    if (fd < 0) {
        ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
        return -1;
    }
    d = fdopendir(fd);
    if (d == NULL) {
        ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
        close(fd);
        return -1;
    }
    res = _delete_dir_contents(d, 0);
    closedir(d);
    return res;
}
Пример #3
0
int delete_dir_contents(const char *pathname,
                        int also_delete_dir,
                        const char *ignore)
{
    int res = 0;
    DIR *d;

    d = opendir(pathname);
    if (d == NULL) {
        ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
        return -errno;
    }
    res = _delete_dir_contents(d, ignore);
    closedir(d);
    if (also_delete_dir) {
        if (rmdir(pathname)) {
            ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
            res = -1;
        }
    }
    return res;
}
Пример #4
0
static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName,
        DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen)
{
    struct dirent *de;
    cache_dir_t* cacheDir = NULL;
    int dfd;

    CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s",
            parentDir, dirName, dir, pathBase));

    dfd = dirfd(dir);

    if (dfd < 0) return 0;

    // Sub-directories always get added to the data structure, so if they
    // are empty we will know about them to delete them later.
    cacheDir = _add_cache_dir_t(cache, parentDir, dirName);

    while ((de = readdir(dir))) {
        const char *name = de->d_name;

        if (de->d_type == DT_DIR) {
            int subfd;
            DIR *subdir;

                /* always skip "." and ".." */
            if (name[0] == '.') {
                if (name[1] == 0) continue;
                if ((name[1] == '.') && (name[2] == 0)) continue;
            }

            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
            if (subfd < 0) {
                ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
                continue;
            }
            subdir = fdopendir(subfd);
            if (subdir == NULL) {
                ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
                close(subfd);
                continue;
            }
            if (cacheDir == NULL) {
                cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
            }
            if (cacheDir != NULL) {
                // Update pathBase for the new path...  this may change dirName
                // if that is also pointing to the path, but we are done with it
                // now.
                size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
                CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase));
                if (finallen < pathAvailLen) {
                    _add_cache_files(cache, cacheDir, name, subdir, pathBase,
                            pathPos+finallen, pathAvailLen-finallen);
                } else {
                    // Whoops, the final path is too long!  We'll just delete
                    // this directory.
                    ALOGW("Cache dir %s truncated in path %s; deleting dir\n",
                            name, pathBase);
                    _delete_dir_contents(subdir, NULL);
                    if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
                        ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
                    }
                }
            }
            closedir(subdir);
        } else if (de->d_type == DT_REG) {
            // Skip files that start with '.'; they will be deleted if
            // their entire directory is deleted.  This allows for metadata
            // like ".nomedia" to remain in the directory until the entire
            // directory is deleted.
            if (cacheDir == NULL) {
                cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
            }
            if (name[0] == '.') {
                cacheDir->hiddenCount++;
                continue;
            }
            if (cacheDir != NULL) {
                // Build final full path for file...  this may change dirName
                // if that is also pointing to the path, but we are done with it
                // now.
                size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
                CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase));
                if (finallen < pathAvailLen) {
                    struct stat s;
                    if (stat(pathBase, &s) >= 0) {
                        _add_cache_file_t(cache, cacheDir, s.st_mtime, name);
                    } else {
                        ALOGW("Unable to stat cache file %s; deleting\n", pathBase);
                        if (unlink(pathBase) < 0) {
                            ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno));
                        }
                    }
                } else {
                    // Whoops, the final path is too long!  We'll just delete
                    // this file.
                    ALOGW("Cache file %s truncated in path %s; deleting\n",
                            name, pathBase);
                    if (unlinkat(dfd, name, 0) < 0) {
                        *pathPos = 0;
                        ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase,
                                strerror(errno));
                    }
                }
            }
        } else {
            cacheDir->hiddenCount++;
        }
    }
    return 0;
}