1 /* 2 * Copyright (C) 2017 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 "CacheItem.h" 18 19 #include <inttypes.h> 20 #include <stdint.h> 21 #include <sys/xattr.h> 22 23 #include <android-base/logging.h> 24 #include <android-base/stringprintf.h> 25 26 #include "utils.h" 27 28 using android::base::StringPrintf; 29 30 namespace android { 31 namespace installd { 32 33 CacheItem::CacheItem(FTSENT* p) { 34 level = p->fts_level; 35 directory = S_ISDIR(p->fts_statp->st_mode); 36 size = p->fts_statp->st_blocks * 512; 37 modified = p->fts_statp->st_mtime; 38 39 mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer); 40 if (mParent) { 41 group = mParent->group; 42 tombstone = mParent->tombstone; 43 mName = p->fts_name; 44 mName.insert(0, "/"); 45 } else { 46 group = false; 47 tombstone = false; 48 mName = p->fts_path; 49 } 50 } 51 52 CacheItem::~CacheItem() { 53 } 54 55 std::string CacheItem::toString() { 56 return StringPrintf("%s size=%" PRId64 " mod=%ld", buildPath().c_str(), size, modified); 57 } 58 59 std::string CacheItem::buildPath() { 60 std::string res = mName; 61 CacheItem* parent = mParent; 62 while (parent) { 63 res.insert(0, parent->mName); 64 parent = parent->mParent; 65 } 66 return res; 67 } 68 69 int CacheItem::purge() { 70 int res = 0; 71 auto path = buildPath(); 72 if (directory) { 73 FTS *fts; 74 FTSENT *p; 75 char *argv[] = { (char*) path.c_str(), nullptr }; 76 if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { 77 PLOG(WARNING) << "Failed to fts_open " << path; 78 return -1; 79 } 80 while ((p = fts_read(fts)) != nullptr) { 81 switch (p->fts_info) { 82 case FTS_D: 83 if (p->fts_level == 0) { 84 p->fts_number = tombstone; 85 } else { 86 p->fts_number = p->fts_parent->fts_number 87 | (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0); 88 } 89 break; 90 case FTS_F: 91 if (p->fts_parent->fts_number) { 92 if (truncate(p->fts_path, 0) != 0) { 93 PLOG(WARNING) << "Failed to truncate " << p->fts_path; 94 res = -1; 95 } 96 } else { 97 if (unlink(p->fts_path) != 0) { 98 PLOG(WARNING) << "Failed to unlink " << p->fts_path; 99 res = -1; 100 } 101 } 102 break; 103 case FTS_DEFAULT: 104 case FTS_SL: 105 case FTS_SLNONE: 106 if (unlink(p->fts_path) != 0) { 107 PLOG(WARNING) << "Failed to unlink " << p->fts_path; 108 res = -1; 109 } 110 break; 111 case FTS_DP: 112 if (rmdir(p->fts_path) != 0) { 113 PLOG(WARNING) << "Failed to rmdir " << p->fts_path; 114 res = -1; 115 } 116 break; 117 } 118 } 119 } else { 120 if (tombstone) { 121 if (truncate(path.c_str(), 0) != 0) { 122 PLOG(WARNING) << "Failed to truncate " << path; 123 res = -1; 124 } 125 } else { 126 if (unlink(path.c_str()) != 0) { 127 PLOG(WARNING) << "Failed to unlink " << path; 128 res = -1; 129 } 130 } 131 } 132 return res; 133 } 134 135 } // namespace installd 136 } // namespace android 137