diff options
Diffstat (limited to 'android/ext4_resize.cpp')
-rw-r--r-- | android/ext4_resize.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/android/ext4_resize.cpp b/android/ext4_resize.cpp new file mode 100644 index 0000000000..cbeb206be9 --- /dev/null +++ b/android/ext4_resize.cpp @@ -0,0 +1,164 @@ +// Copyright (C) 2015 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef _WIN32 +#include "android/base/system/Win32Utils.h" +#include "android/utils/win32_cmdline_quote.h" +#include <windows.h> + +using android::base::Win32Utils; +#else +#include <sys/wait.h> +#endif + +#include "android/base/String.h" +#include "android/ext4_resize.h" +#include "android/utils/path.h" +#include "base/system/System.h" +#include "main-common.h" + +using android::base::String; +using android::base::System; + +// Convenience function for formatting and printing system call/library +// function errors that show up regardless of host platform. Equivalent +// to printing the stringified error code from errno or GetLastError() +// (for windows). +void explainSystemErrors (const char * msg) { +#ifdef _WIN32 + char *pstr = NULL; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + GetLastError(), + 0, + (LPTSTR) &pstr, + 2, + NULL); + fprintf(stderr, "ERROR: %s - %s\n", msg, pstr); + LocalFree(pstr); +#else + fprintf(stderr, "ERROR: %s - %s\n", msg, strerror(errno)); +#endif +} + +int resizeExt4Partition (const char * partitionPath, int64_t newByteSize) { + // sanity checks + if (partitionPath == NULL || !checkExt4PartitionSize(newByteSize)) { + return -1; + } + + // format common arguments once + String executable = System::get()->findBundledExecutable("resize2fs"); + if(executable.empty()) { + fprintf(stderr, "ERROR: couldn't get path to resize2fs binary\n"); + return -1; + } + + char size_in_MB[50]; + int copied = snprintf(size_in_MB, sizeof(size_in_MB), + "%uM", convertBytesToMB(newByteSize)); + size_in_MB[sizeof(size_in_MB) - 1] = '\0'; + if (copied < 0 || copied >= sizeof(size_in_MB)) { + fprintf(stderr, "ERROR: failed to format size in resize2fs command\n"); + return -1; + } + + +#ifdef _WIN32 + STARTUPINFO startup; + PROCESS_INFORMATION pinfo; + DWORD exitCode; + + ZeroMemory(&startup, sizeof(startup)); + ZeroMemory(&pinfo, sizeof(pinfo)); + startup.cb = sizeof(startup); + + char args[PATH_MAX * 2 + 1]; + copied = snprintf(args, sizeof(args), "resize2fs.exe -f %s %s", + Win32Utils::quoteCommandLine(partitionPath).c_str(), + size_in_MB); + args[sizeof(args) - 1] = '\0'; + if (copied < 0 || copied >= sizeof(args)) { + fprintf(stderr, "ERROR: failed to format resize2fs command\n"); + return -1; + } + + BOOL success = CreateProcess( + Win32Utils::quoteCommandLine(executable.c_str()).c_str(), /* program path */ + args, /* command line args */ + NULL, /* process handle is not inheritable */ + NULL, /* thread handle is not inheritable */ + FALSE, /* no, don't inherit any handles */ + CREATE_NO_WINDOW, /* the new process doesn't have a console */ + NULL, /* use parent's environment block */ + NULL, /* use parent's starting directory */ + &startup, /* startup info, i.e. std handles */ + &pinfo); + if (!success) { + explainSystemErrors("failed to create process while resizing partition"); + return -2; + } + + WaitForSingleObject(pinfo.hProcess, INFINITE); + if (!GetExitCodeProcess(pinfo.hProcess, &exitCode)) { + explainSystemErrors("couldn't get exit code from resizing partition process"); + CloseHandle(pinfo.hProcess); + CloseHandle(pinfo.hThread); + return -2; + } + CloseHandle(pinfo.hProcess); + CloseHandle(pinfo.hThread); + +#else + int32_t exitCode = 0; + pid_t pid; + pid_t child = fork(); + + if (child < 0) { + explainSystemErrors("couldn't create a child process to resize the partition"); + return -2; + }else if (child == 0) { + execlp(executable.c_str(), executable.c_str(), "-f", partitionPath, + size_in_MB, NULL); + exit(-1); + } + + while ((pid = waitpid(-1, &exitCode, 0)) != child) { + if (pid == -1) { + explainSystemErrors("resizing partition waitpid failed"); + return -2; + } + } +#endif + if(exitCode != 0) { + fprintf(stderr, "ERROR: resizing partition failed with exit code %d\n", + exitCode); + return exitCode; + } + return 0; +} + +bool checkExt4PartitionSize (int64_t byteSize) { + uint64_t maxSizeMB = 16 * 1024 * 1024; // (16 TiB) * (1024 GiB / TiB) * (1024 MiB / GiB) + uint64_t minSizeMB = 128; + uint64_t sizeMB = convertBytesToMB(byteSize); + + //compiler converts signed to unsigned + return (sizeMB >= minSizeMB) && (sizeMB <= maxSizeMB); +} |