From 625dc787c629cd04e30328a9b1cf4a8e7d6210bc Mon Sep 17 00:00:00 2001 From: Oleksiy Avramchenko Date: Wed, 23 May 2018 10:50:46 +0200 Subject: [PATCH 1/2] Add GetBlockDevSize, GetBlockDevSectors helpers Helpers to get a block device size in bytes or 512 byte sectors, using BLKGETSIZE64 and returning value of uint64_t type. This also removes get_blkdev_size(). Test: build, manual, mount exFAT volume Bug: 80202067 Change-Id: Ib07e8ac6ef7ff49de0ed570d1fa202e8b558b80c --- MetadataCrypt.cpp | 12 +---------- Utils.cpp | 44 +++++++++++++++++++++++++++++++++------ Utils.h | 6 ++++++ VoldUtil.cpp | 6 ------ VoldUtil.h | 2 -- cryptfs.cpp | 50 +++++++++++---------------------------------- model/Disk.cpp | 8 ++------ model/ObbVolume.cpp | 19 ++++------------- 8 files changed, 63 insertions(+), 84 deletions(-) diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 842b19b..e5bf819 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -100,20 +100,10 @@ static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuf } static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_sec) { - android::base::unique_fd dev_fd( - TEMP_FAILURE_RETRY(open(real_blkdev.c_str(), O_RDONLY | O_CLOEXEC, 0))); - if (dev_fd == -1) { - PLOG(ERROR) << "Unable to open " << real_blkdev << " to measure size"; - return false; - } - unsigned long res; - // TODO: should use BLKGETSIZE64 - get_blkdev_size(dev_fd.get(), &res); - if (res == 0) { + if (android::vold::GetBlockDev512Sectors(real_blkdev, nr_sec) != android::OK) { PLOG(ERROR) << "Unable to measure size of " << real_blkdev; return false; } - *nr_sec = res; return true; } diff --git a/Utils.cpp b/Utils.cpp index f085c22..736d721 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -476,6 +476,42 @@ status_t NormalizeHex(const std::string& in, std::string& out) { return StrToHex(tmp, out); } +status_t GetBlockDevSize(int fd, uint64_t* size) { + if (ioctl(fd, BLKGETSIZE64, size)) { + return -errno; + } + + return OK; +} + +status_t GetBlockDevSize(const std::string& path, uint64_t* size) { + int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); + status_t res = OK; + + if (fd < 0) { + return -errno; + } + + res = GetBlockDevSize(fd, size); + + close(fd); + + return res; +} + +status_t GetBlockDev512Sectors(const std::string& path, uint64_t* nr_sec) { + uint64_t size; + status_t res = GetBlockDevSize(path, &size); + + if (res != OK) { + return res; + } + + *nr_sec = size / 512; + + return OK; +} + uint64_t GetFreeBytes(const std::string& path) { struct statvfs sb; if (statvfs(path.c_str(), &sb) == 0) { @@ -560,8 +596,7 @@ bool IsFilesystemSupported(const std::string& fsType) { status_t WipeBlockDevice(const std::string& path) { status_t res = -1; const char* c_path = path.c_str(); - unsigned long nr_sec = 0; - unsigned long long range[2]; + uint64_t range[2] = {0, 0}; int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC)); if (fd == -1) { @@ -569,14 +604,11 @@ status_t WipeBlockDevice(const std::string& path) { goto done; } - if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) { + if (GetBlockDevSize(fd, &range[1]) != OK) { PLOG(ERROR) << "Failed to determine size of " << path; goto done; } - range[0] = 0; - range[1] = (unsigned long long)nr_sec * 512; - LOG(INFO) << "About to discard " << range[1] << " on " << path; if (ioctl(fd, BLKDISCARD, &range) == 0) { LOG(INFO) << "Discard success on " << path; diff --git a/Utils.h b/Utils.h index 09ce8fa..40f4d0a 100644 --- a/Utils.h +++ b/Utils.h @@ -76,6 +76,12 @@ status_t ForkExecvp(const std::vector& args, std::vector& args); +/* Gets block device size in bytes */ +status_t GetBlockDevSize(int fd, uint64_t* size); +status_t GetBlockDevSize(const std::string& path, uint64_t* size); +/* Gets block device size in 512 byte sectors */ +status_t GetBlockDev512Sectors(const std::string& path, uint64_t* nr_sec); + status_t ReadRandomBytes(size_t bytes, std::string& out); status_t ReadRandomBytes(size_t bytes, char* buffer); status_t GenerateRandomUuid(std::string& out); diff --git a/VoldUtil.cpp b/VoldUtil.cpp index 26c817c..4b980be 100644 --- a/VoldUtil.cpp +++ b/VoldUtil.cpp @@ -18,9 +18,3 @@ #include struct fstab* fstab_default; - -void get_blkdev_size(int fd, unsigned long* nr_sec) { - if ((ioctl(fd, BLKGETSIZE, nr_sec)) == -1) { - *nr_sec = 0; - } -} diff --git a/VoldUtil.h b/VoldUtil.h index 4311586..782e36d 100644 --- a/VoldUtil.h +++ b/VoldUtil.h @@ -24,6 +24,4 @@ extern struct fstab* fstab_default; #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) -void get_blkdev_size(int fd, unsigned long* nr_sec); - #endif diff --git a/cryptfs.cpp b/cryptfs.cpp index 00e5519..0b52650 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -393,10 +393,10 @@ const char* cryptfs_get_crypto_name() { return get_crypto_type().get_crypto_name(); } -static unsigned int get_fs_size(char* dev) { +static uint64_t get_fs_size(char* dev) { int fd, block_size; struct ext4_super_block sb; - off64_t len; + uint64_t len; if ((fd = open(dev, O_RDONLY | O_CLOEXEC)) < 0) { SLOGE("Cannot open device to get filesystem size "); @@ -421,17 +421,16 @@ static unsigned int get_fs_size(char* dev) { } block_size = 1024 << sb.s_log_block_size; /* compute length in bytes */ - len = (((off64_t)sb.s_blocks_count_hi << 32) + sb.s_blocks_count_lo) * block_size; + len = (((uint64_t)sb.s_blocks_count_hi << 32) + sb.s_blocks_count_lo) * block_size; /* return length in sectors */ - return (unsigned int)(len / 512); + return len / 512; } static int get_crypt_ftr_info(char** metadata_fname, off64_t* off) { static int cached_data = 0; - static off64_t cached_off = 0; + static uint64_t cached_off = 0; static char cached_metadata_fname[PROPERTY_VALUE_MAX] = ""; - int fd; char key_loc[PROPERTY_VALUE_MAX]; char real_blkdev[PROPERTY_VALUE_MAX]; int rc = -1; @@ -440,25 +439,17 @@ static int get_crypt_ftr_info(char** metadata_fname, off64_t* off) { fs_mgr_get_crypt_info(fstab_default, key_loc, real_blkdev, sizeof(key_loc)); if (!strcmp(key_loc, KEY_IN_FOOTER)) { - if ((fd = open(real_blkdev, O_RDWR | O_CLOEXEC)) < 0) { - SLOGE("Cannot open real block device %s\n", real_blkdev); - return -1; - } - - unsigned long nr_sec = 0; - get_blkdev_size(fd, &nr_sec); - if (nr_sec != 0) { + if (android::vold::GetBlockDevSize(real_blkdev, &cached_off) == android::OK) { /* If it's an encrypted Android partition, the last 16 Kbytes contain the * encryption info footer and key, and plenty of bytes to spare for future * growth. */ strlcpy(cached_metadata_fname, real_blkdev, sizeof(cached_metadata_fname)); - cached_off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET; + cached_off -= CRYPT_FOOTER_OFFSET; cached_data = 1; } else { SLOGE("Cannot get size of block device %s\n", real_blkdev); } - close(fd); } else { strlcpy(cached_metadata_fname, key_loc, sizeof(cached_metadata_fname)); cached_off = 0; @@ -1816,17 +1807,8 @@ errout: */ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key, char* out_crypto_blkdev) { - int fd = open(real_blkdev, O_RDONLY | O_CLOEXEC); - if (fd == -1) { - SLOGE("Failed to open %s: %s", real_blkdev, strerror(errno)); - return -1; - } - - unsigned long nr_sec = 0; - get_blkdev_size(fd, &nr_sec); - close(fd); - - if (nr_sec == 0) { + uint64_t nr_sec = 0; + if (android::vold::GetBlockDev512Sectors(real_blkdev, &nr_sec) != android::OK) { SLOGE("Failed to get size of %s: %s", real_blkdev, strerror(errno)); return -1; } @@ -2090,7 +2072,6 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { off64_t previously_encrypted_upto = 0; bool rebootEncryption = false; bool onlyCreateHeader = false; - int fd = -1; if (get_crypt_ftr_and_key(&crypt_ftr) == 0) { if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) { @@ -2134,22 +2115,15 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { fs_mgr_get_crypt_info(fstab_default, 0, real_blkdev, sizeof(real_blkdev)); /* Get the size of the real block device */ - fd = open(real_blkdev, O_RDONLY | O_CLOEXEC); - if (fd == -1) { - SLOGE("Cannot open block device %s\n", real_blkdev); - goto error_unencrypted; - } - unsigned long nr_sec; - get_blkdev_size(fd, &nr_sec); - if (nr_sec == 0) { + uint64_t nr_sec; + if (android::vold::GetBlockDev512Sectors(real_blkdev, &nr_sec) != android::OK) { SLOGE("Cannot get size of block device %s\n", real_blkdev); goto error_unencrypted; } - close(fd); /* If doing inplace encryption, make sure the orig fs doesn't include the crypto footer */ if (!strcmp(key_loc, KEY_IN_FOOTER)) { - unsigned int fs_size_sec, max_fs_size_sec; + uint64_t fs_size_sec, max_fs_size_sec; fs_size_sec = get_fs_size(real_blkdev); if (fs_size_sec == 0) fs_size_sec = get_f2fs_filesystem_size_sec(real_blkdev); diff --git a/model/Disk.cpp b/model/Disk.cpp index 13cb1c7..2b6773d 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -243,12 +243,8 @@ status_t Disk::readMetadata() { mSize = -1; mLabel.clear(); - int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC); - if (fd != -1) { - if (ioctl(fd, BLKGETSIZE64, &mSize)) { - mSize = -1; - } - close(fd); + if (GetBlockDevSize(mDevPath, &mSize) != OK) { + mSize = -1; } unsigned int majorId = major(mDevice); diff --git a/model/ObbVolume.cpp b/model/ObbVolume.cpp index ec3d267..21479c4 100644 --- a/model/ObbVolume.cpp +++ b/model/ObbVolume.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -36,7 +35,6 @@ #include using android::base::StringPrintf; -using android::base::unique_fd; namespace android { namespace vold { @@ -59,19 +57,10 @@ status_t ObbVolume::doCreate() { } if (!mSourceKey.empty()) { - unsigned long nr_sec = 0; - { - unique_fd loop_fd(open(mLoopPath.c_str(), O_RDWR | O_CLOEXEC)); - if (loop_fd.get() == -1) { - PLOG(ERROR) << getId() << " failed to open loop"; - return -1; - } - - get_blkdev_size(loop_fd.get(), &nr_sec); - if (nr_sec == 0) { - PLOG(ERROR) << getId() << " failed to get loop size"; - return -1; - } + uint64_t nr_sec = 0; + if (GetBlockDev512Sectors(mLoopPath, &nr_sec) != OK) { + PLOG(ERROR) << getId() << " failed to get loop size"; + return -1; } char tmp[PATH_MAX]; From 4cff06d45faa4cf62f471f56550006e5f0a2d7db Mon Sep 17 00:00:00 2001 From: Oleksiy Avramchenko Date: Wed, 23 May 2018 18:59:48 +0200 Subject: [PATCH 2/2] Use exFAT for SDXC cards When both VFAT and exFAT are supported VFAT will only be used to format card. Use exFAT for cards larger than 32GB per SDXC standard. Test: build, manual, mount exFAT volume Bug: 80202067 Change-Id: If504f9685256a669c5801a69d69d5a214ad27455 --- model/PublicVolume.cpp | 57 ++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 7420c79..fc1c9e2 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -246,28 +246,53 @@ status_t PublicVolume::doUnmount() { } status_t PublicVolume::doFormat(const std::string& fsType) { - if ((fsType == "vfat" || fsType == "auto") && vfat::IsSupported()) { - if (WipeBlockDevice(mDevPath) != OK) { - LOG(WARNING) << getId() << " failed to wipe"; + bool useVfat = vfat::IsSupported(); + bool useExfat = exfat::IsSupported(); + status_t res = OK; + + // Resolve the target filesystem type + if (fsType == "auto" && useVfat && useExfat) { + uint64_t size = 0; + + res = GetBlockDevSize(mDevPath, &size); + if (res != OK) { + LOG(ERROR) << "Couldn't get device size " << mDevPath; + return res; } - if (vfat::Format(mDevPath, 0)) { - LOG(ERROR) << getId() << " failed to format"; - return -errno; - } - } else if ((fsType == "exfat" || fsType == "auto") && exfat::IsSupported()) { - if (WipeBlockDevice(mDevPath) != OK) { - LOG(WARNING) << getId() << " failed to wipe"; - } - if (exfat::Format(mDevPath)) { - LOG(ERROR) << getId() << " failed to format"; - return -errno; + + // If both vfat & exfat are supported use exfat for SDXC (>~32GiB) cards + if (size > 32896LL * 1024 * 1024) { + useVfat = false; + } else { + useExfat = false; } - } else { + } else if (fsType == "vfat") { + useExfat = false; + } else if (fsType == "exfat") { + useVfat = false; + } + + if (!useVfat && !useExfat) { LOG(ERROR) << "Unsupported filesystem " << fsType; return -EINVAL; } - return OK; + if (WipeBlockDevice(mDevPath) != OK) { + LOG(WARNING) << getId() << " failed to wipe"; + } + + if (useVfat) { + res = vfat::Format(mDevPath, 0); + } else if (useExfat) { + res = exfat::Format(mDevPath); + } + + if (res != OK) { + LOG(ERROR) << getId() << " failed to format"; + res = -errno; + } + + return res; } } // namespace vold