Home | History | Annotate | Download | only in vold
      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