diff options
Diffstat (limited to 'cmds/installd/utils.c')
-rw-r--r-- | cmds/installd/utils.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c new file mode 100644 index 0000000..5db5545 --- /dev/null +++ b/cmds/installd/utils.c @@ -0,0 +1,149 @@ +/* +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "installd.h" + +int create_pkg_path(char path[PKG_PATH_MAX], + const char *prefix, + const char *pkgname, + const char *postfix) +{ + int len; + const char *x; + + len = strlen(pkgname); + if (len > PKG_NAME_MAX) { + return -1; + } + if ((len + strlen(prefix) + strlen(postfix)) >= PKG_PATH_MAX) { + return -1; + } + + x = pkgname; + while (*x) { + if (isalnum(*x) || (*x == '_')) { + /* alphanumeric or underscore are fine */ + } else if (*x == '.') { + if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) { + /* periods must not be first, last, or doubled */ + LOGE("invalid package name '%s'\n", pkgname); + return -1; + } + } else { + /* anything not A-Z, a-z, 0-9, _, or . is invalid */ + LOGE("invalid package name '%s'\n", pkgname); + return -1; + } + x++; + } + + sprintf(path, "%s%s%s", prefix, pkgname, postfix); + return 0; +} + +static int _delete_dir_contents(DIR *d, const char *ignore) +{ + 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; + + /* skip the ignore name if provided */ + if (ignore && !strcmp(name, ignore)) 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) { + result = -1; + continue; + } + subdir = fdopendir(subfd); + if (subdir == NULL) { + close(subfd); + result = -1; + continue; + } + if (_delete_dir_contents(subdir, 0)) { + result = -1; + } + closedir(subdir); + if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { + result = -1; + } + } else { + if (unlinkat(dfd, name, 0) < 0) { + result = -1; + } + } + } + + return result; +} + +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) { + return -errno; + } + res = _delete_dir_contents(d, ignore); + closedir(d); + if (also_delete_dir) { + if (rmdir(pathname)) { + res = -1; + } + } + return res; +} + +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) { + return -1; + } + d = fdopendir(fd); + if (d == NULL) { + close(fd); + return -1; + } + res = _delete_dir_contents(d, 0); + closedir(d); + return res; +} |