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 "FileDeviceUtils.h" 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <errno.h> 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <fcntl.h> 25 #include <linux/fs.h> 26 #include <linux/fiemap.h> 27 #include <mntent.h> 28 29 #include <android-base/file.h> 30 #include <android-base/logging.h> 31 #include <android-base/unique_fd.h> 32 33 namespace { 34 35 std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count); 36 37 } 38 39 namespace android { 40 namespace vold { 41 42 // Given a file path, look for the corresponding block device in /proc/mount 43 std::string BlockDeviceForPath(const std::string &path) 44 { 45 std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent); 46 if (!mnts) { 47 PLOG(ERROR) << "Unable to open /proc/mounts"; 48 return ""; 49 } 50 std::string result; 51 size_t best_length = 0; 52 struct mntent *mnt; // getmntent returns a thread local, so it's safe. 53 while ((mnt = getmntent(mnts.get())) != nullptr) { 54 auto l = strlen(mnt->mnt_dir); 55 if (l > best_length && 56 path.size() > l && 57 path[l] == '/' && 58 path.compare(0, l, mnt->mnt_dir) == 0) { 59 result = mnt->mnt_fsname; 60 best_length = l; 61 } 62 } 63 if (result.empty()) { 64 LOG(ERROR) <<"Didn't find a mountpoint to match path " << path; 65 return ""; 66 } 67 LOG(DEBUG) << "For path " << path << " block device is " << result; 68 return result; 69 } 70 71 std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count) 72 { 73 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open( 74 path.c_str(), O_RDONLY | O_CLOEXEC, 0))); 75 if (fd == -1) { 76 if (errno == ENOENT) { 77 PLOG(DEBUG) << "Unable to open " << path; 78 } else { 79 PLOG(ERROR) << "Unable to open " << path; 80 } 81 return nullptr; 82 } 83 auto fiemap = alloc_fiemap(extent_count); 84 if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) { 85 PLOG(ERROR) << "Unable to FIEMAP " << path; 86 return nullptr; 87 } 88 auto mapped = fiemap->fm_mapped_extents; 89 if (mapped < 1 || mapped > extent_count) { 90 LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count 91 << " in " << path; 92 return nullptr; 93 } 94 return fiemap; 95 } 96 97 } // namespace vold 98 } // namespace android 99 100 namespace { 101 102 std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count) 103 { 104 size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]); 105 std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap); 106 memset(res.get(), 0, allocsize); 107 res->fm_start = 0; 108 res->fm_length = UINT64_MAX; 109 res->fm_flags = 0; 110 res->fm_extent_count = extent_count; 111 res->fm_mapped_extents = 0; 112 return res; 113 } 114 115 } 116