| /* |
| ** 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; |
| } |