Update files.cpp in libutils

This commit is contained in:
topjohnwu 2020-04-02 02:17:45 -07:00
parent dbfde74c1e
commit 9820296e92
4 changed files with 132 additions and 158 deletions

View File

@ -107,7 +107,7 @@ void RootFSInit::setup_rootfs() {
if (access("/overlay.d", F_OK) == 0) { if (access("/overlay.d", F_OK) == 0) {
LOGD("Merge overlay.d\n"); LOGD("Merge overlay.d\n");
load_overlay_rc("/overlay.d"); load_overlay_rc("/overlay.d");
mv_f("/overlay.d", "/"); mv_path("/overlay.d", "/");
} }
// Patch init.rc // Patch init.rc
@ -120,10 +120,7 @@ void RootFSInit::setup_rootfs() {
// Create hardlink mirror of /sbin to /root // Create hardlink mirror of /sbin to /root
mkdir("/root", 0750); mkdir("/root", 0750);
clone_attr("/sbin", "/root"); clone_attr("/sbin", "/root");
int rootdir = xopen("/root", O_RDONLY | O_CLOEXEC); link_path("/sbin", "/root");
int sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
link_dir(sbin, rootdir);
close(sbin);
// Dump magiskinit as magisk // Dump magiskinit as magisk
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755); int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);

View File

@ -18,42 +18,44 @@ ssize_t fd_path(int fd, char *path, size_t size) {
} }
int fd_pathat(int dirfd, const char *name, char *path, size_t size) { int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
ssize_t len = fd_path(dirfd, path, size); if (fd_path(dirfd, path, size) < 0)
if (len < 0)
return -1; return -1;
auto len = strlen(path);
path[len] = '/'; path[len] = '/';
strlcpy(&path[len + 1], name, size - len - 1); strlcpy(path + len + 1, name, size - len - 1);
return 0; return 0;
} }
int mkdirs(const char *pathname, mode_t mode) { int mkdirs(string path, mode_t mode) {
char *path = strdup(pathname), *p;
errno = 0; errno = 0;
for (p = path + 1; *p; ++p) { for (char *p = path.data() + 1; *p; ++p) {
if (*p == '/') { if (*p == '/') {
*p = '\0'; *p = '\0';
if (mkdir(path, mode) == -1) { if (mkdir(path.data(), mode) == -1) {
if (errno != EEXIST) if (errno != EEXIST)
return -1; return -1;
} }
*p = '/'; *p = '/';
} }
} }
if (mkdir(path, mode) == -1) { if (mkdir(path.data(), mode) == -1) {
if (errno != EEXIST) if (errno != EEXIST)
return -1; return -1;
} }
free(path);
return 0; return 0;
} }
static void post_order_walk(int dirfd, function<int(int, dirent *)> &&fn) { #define SKIP_DOTS {\
if (entry->d_name == "."sv || entry->d_name == ".."sv) \
continue;\
}
static void post_order_walk(int dirfd, const function<int(int, dirent *)> &&fn) {
auto dir = xopen_dir(dirfd); auto dir = xopen_dir(dirfd);
if (!dir) return; if (!dir) return;
for (dirent *entry; (entry = xreaddir(dir.get()));) { for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv) SKIP_DOTS
continue;
if (entry->d_type == DT_DIR) if (entry->d_type == DT_DIR)
post_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), std::move(fn)); post_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), std::move(fn));
fn(dirfd, entry); fn(dirfd, entry);
@ -77,158 +79,127 @@ void frm_rf(int dirfd) {
post_order_walk(dirfd, remove_at); post_order_walk(dirfd, remove_at);
} }
/* This will only on the same file system */ void mv_path(const char *src, const char *dest) {
void mv_f(const char *source, const char *destination) { file_attr a;
struct stat st; getattr(src, &a);
xlstat(source, &st); if (S_ISDIR(a.st.st_mode)) {
int src, dest; xmkdirs(dest, 0);
struct file_attr a; setattr(dest, &a);
mv_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
if (S_ISDIR(st.st_mode)) {
xmkdirs(destination, st.st_mode & 0777);
src = xopen(source, O_RDONLY | O_CLOEXEC);
dest = xopen(destination, O_RDONLY | O_CLOEXEC);
fclone_attr(src, dest);
mv_dir(src, dest);
close(src);
close(dest);
} else{ } else{
getattr(source, &a); xrename(src, dest);
xrename(source, destination);
setattr(destination, &a);
} }
rmdir(source); rmdir(src);
} }
/* This will only on the same file system */
void mv_dir(int src, int dest) { void mv_dir(int src, int dest) {
struct dirent *entry; auto dir = xopen_dir(src);
DIR *dir; run_finally f([&]{ close(dest); });
int newsrc, newdest; for (dirent *entry; (entry = xreaddir(dir.get()));) {
struct file_attr a; SKIP_DOTS
dir = xfdopendir(src);
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
getattrat(src, entry->d_name, &a);
switch (entry->d_type) { switch (entry->d_type) {
case DT_DIR: case DT_DIR:
xmkdirat(dest, entry->d_name, a.st.st_mode & 0777); if (faccessat(dest, entry->d_name, F_OK, 0) == 0) {
newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC); // Destination folder exists, needs recursive move
newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); int newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
fsetattr(newdest, &a); int newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
mv_dir(newsrc, newdest); mv_dir(newsrc, newdest);
close(newsrc); unlinkat(src, entry->d_name, AT_REMOVEDIR);
close(newdest); break;
unlinkat(src, entry->d_name, AT_REMOVEDIR); }
break; // Else fall through
case DT_LNK: case DT_LNK:
case DT_REG: case DT_REG:
renameat(src, entry->d_name, dest, entry->d_name); renameat(src, entry->d_name, dest, entry->d_name);
setattrat(dest, entry->d_name, &a);
break; break;
} }
} }
} }
void cp_afc(const char *source, const char *destination) { void cp_afc(const char *src, const char *dest) {
int src, dest; file_attr a;
struct file_attr a; getattr(src, &a);
getattr(source, &a);
if (S_ISDIR(a.st.st_mode)) { if (S_ISDIR(a.st.st_mode)) {
xmkdirs(destination, a.st.st_mode & 0777); xmkdirs(dest, 0);
src = xopen(source, O_RDONLY | O_CLOEXEC); clone_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
dest = xopen(destination, O_RDONLY | O_CLOEXEC);
clone_dir(src, dest);
close(src);
close(dest);
} else{ } else{
unlink(destination); unlink(dest);
if (S_ISREG(a.st.st_mode)) { if (S_ISREG(a.st.st_mode)) {
src = xopen(source, O_RDONLY); int sfd = xopen(src, O_RDONLY | O_CLOEXEC);
dest = xopen(destination, O_WRONLY | O_CREAT | O_TRUNC); int dfd = xopen(dest, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC);
xsendfile(dest, src, nullptr, a.st.st_size); xsendfile(dfd, sfd, nullptr, a.st.st_size);
close(src); close(sfd);
close(dest); close(dfd);
} else if (S_ISLNK(a.st.st_mode)) { } else if (S_ISLNK(a.st.st_mode)) {
char buf[PATH_MAX]; char buf[4096];
xreadlink(source, buf, sizeof(buf)); xreadlink(src, buf, sizeof(buf));
xsymlink(buf, destination); xsymlink(buf, dest);
} }
} }
setattr(destination, &a); setattr(dest, &a);
} }
void clone_dir(int src, int dest, bool overwrite) { void clone_dir(int src, int dest) {
struct dirent *entry; auto dir = xopen_dir(src);
DIR *dir; run_finally f([&]{ close(dest); });
int srcfd, destfd, newsrc, newdest; for (dirent *entry; (entry = xreaddir(dir.get()));) {
char buf[PATH_MAX]; SKIP_DOTS
struct file_attr a; file_attr a;
dir = xfdopendir(src);
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (struct stat st; !overwrite &&
fstatat(dest, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) == 0)
continue;
getattrat(src, entry->d_name, &a); getattrat(src, entry->d_name, &a);
switch (entry->d_type) { switch (entry->d_type) {
case DT_DIR: case DT_DIR: {
xmkdirat(dest, entry->d_name, a.st.st_mode & 0777); xmkdirat(dest, entry->d_name, 0);
setattrat(dest, entry->d_name, &a); setattrat(dest, entry->d_name, &a);
newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC); int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); int dst = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
clone_dir(newsrc, newdest, overwrite); clone_dir(sfd, dst);
close(newsrc); break;
close(newdest); }
break; case DT_REG: {
case DT_REG: int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
destfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC); int dfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC);
srcfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC); xsendfile(dfd, sfd, nullptr, a.st.st_size);
xsendfile(destfd, srcfd, nullptr, a.st.st_size); fsetattr(dfd, &a);
fsetattr(destfd, &a); close(dfd);
close(destfd); close(sfd);
close(srcfd); break;
break; }
case DT_LNK: case DT_LNK: {
xreadlinkat(src, entry->d_name, buf, sizeof(buf)); char buf[4096];
xsymlinkat(buf, dest, entry->d_name); xreadlinkat(src, entry->d_name, buf, sizeof(buf));
setattrat(dest, entry->d_name, &a); xsymlinkat(buf, dest, entry->d_name);
break; setattrat(dest, entry->d_name, &a);
break;
}
} }
} }
} }
void link_path(const char *src, const char *dest) {
link_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
}
void link_dir(int src, int dest) { void link_dir(int src, int dest) {
struct dirent *entry; auto dir = xopen_dir(src);
DIR *dir; run_finally f([&]{ close(dest); });
int newsrc, newdest; for (dirent *entry; (entry = xreaddir(dir.get()));) {
struct file_attr a; SKIP_DOTS
dir = xfdopendir(src);
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
file_attr a;
getattrat(src, entry->d_name, &a); getattrat(src, entry->d_name, &a);
xmkdirat(dest, entry->d_name, a.st.st_mode & 0777); xmkdirat(dest, entry->d_name, 0);
setattrat(dest, entry->d_name, &a); setattrat(dest, entry->d_name, &a);
newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC); int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); int dfd = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
link_dir(newsrc, newdest); link_dir(sfd, dfd);
close(newsrc);
close(newdest);
} else { } else {
xlinkat(src, entry->d_name, dest, entry->d_name, 0); xlinkat(src, entry->d_name, dest, entry->d_name, 0);
} }
} }
} }
int getattr(const char *path, struct file_attr *a) { int getattr(const char *path, file_attr *a) {
if (xlstat(path, &a->st) == -1) if (xlstat(path, &a->st) == -1)
return -1; return -1;
char *con; char *con;
@ -239,13 +210,13 @@ int getattr(const char *path, struct file_attr *a) {
return 0; return 0;
} }
int getattrat(int dirfd, const char *name, struct file_attr *a) { int getattrat(int dirfd, const char *name, file_attr *a) {
char path[4096]; char path[4096];
fd_pathat(dirfd, name, path, sizeof(path)); fd_pathat(dirfd, name, path, sizeof(path));
return getattr(path, a); return getattr(path, a);
} }
int fgetattr(int fd, struct file_attr *a) { int fgetattr(int fd, file_attr *a) {
if (xfstat(fd, &a->st) < 0) if (xfstat(fd, &a->st) < 0)
return -1; return -1;
char *con; char *con;
@ -256,7 +227,7 @@ int fgetattr(int fd, struct file_attr *a) {
return 0; return 0;
} }
int setattr(const char *path, struct file_attr *a) { int setattr(const char *path, file_attr *a) {
if (chmod(path, a->st.st_mode & 0777) < 0) if (chmod(path, a->st.st_mode & 0777) < 0)
return -1; return -1;
if (chown(path, a->st.st_uid, a->st.st_gid) < 0) if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
@ -266,13 +237,13 @@ int setattr(const char *path, struct file_attr *a) {
return 0; return 0;
} }
int setattrat(int dirfd, const char *name, struct file_attr *a) { int setattrat(int dirfd, const char *name, file_attr *a) {
char path[4096]; char path[4096];
fd_pathat(dirfd, name, path, sizeof(path)); fd_pathat(dirfd, name, path, sizeof(path));
return setattr(path, a); return setattr(path, a);
} }
int fsetattr(int fd, struct file_attr *a) { int fsetattr(int fd, file_attr *a) {
if (fchmod(fd, a->st.st_mode & 0777) < 0) if (fchmod(fd, a->st.st_mode & 0777) < 0)
return -1; return -1;
if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0) if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0)
@ -282,16 +253,16 @@ int fsetattr(int fd, struct file_attr *a) {
return 0; return 0;
} }
void clone_attr(const char *source, const char *target) { void clone_attr(const char *src, const char *dest) {
struct file_attr a; file_attr a;
getattr(source, &a); getattr(src, &a);
setattr(target, &a); setattr(dest, &a);
} }
void fclone_attr(int sourcefd, int targetfd) { void fclone_attr(int src, int dest) {
struct file_attr a; file_attr a;
fgetattr(sourcefd, &a); fgetattr(src, &a);
fsetattr(targetfd, &a); fsetattr(dest, &a);
} }
void *__mmap(const char *filename, size_t *size, bool rw) { void *__mmap(const char *filename, size_t *size, bool rw) {
@ -337,7 +308,7 @@ void write_zero(int fd, size_t size) {
} }
} }
void file_readline(bool trim, const char *file, const std::function<bool(std::string_view)> &fn) { void file_readline(bool trim, const char *file, const function<bool(string_view)> &fn) {
FILE *fp = xfopen(file, "re"); FILE *fp = xfopen(file, "re");
if (fp == nullptr) if (fp == nullptr)
return; return;
@ -361,7 +332,7 @@ void file_readline(bool trim, const char *file, const std::function<bool(std::st
free(buf); free(buf);
} }
void parse_prop_file(const char *file, const function<bool (string_view, string_view)> &fn) { void parse_prop_file(const char *file, const function<bool(string_view, string_view)> &&fn) {
file_readline(true, file, [&](string_view line_view) -> bool { file_readline(true, file, [&](string_view line_view) -> bool {
char *line = (char *) line_view.data(); char *line = (char *) line_view.data();
if (line[0] == '#') if (line[0] == '#')
@ -374,7 +345,7 @@ void parse_prop_file(const char *file, const function<bool (string_view, string_
}); });
} }
void parse_mnt(const char *file, const function<bool (mntent*)> &fn) { void parse_mnt(const char *file, const function<bool(mntent*)> &fn) {
auto fp = sFILE(setmntent(file, "re"), endmntent); auto fp = sFILE(setmntent(file, "re"), endmntent);
if (fp) { if (fp) {
mntent mentry{}; mntent mentry{};

View File

@ -41,20 +41,21 @@ struct raw_file {
ssize_t fd_path(int fd, char *path, size_t size); ssize_t fd_path(int fd, char *path, size_t size);
int fd_pathat(int dirfd, const char *name, char *path, size_t size); int fd_pathat(int dirfd, const char *name, char *path, size_t size);
int mkdirs(const char *pathname, mode_t mode); int mkdirs(std::string path, mode_t mode);
void rm_rf(const char *path); void rm_rf(const char *path);
void mv_f(const char *source, const char *destination); void mv_path(const char *src, const char *dest);
void mv_dir(int src, int dest); void mv_dir(int src, int dest);
void cp_afc(const char *source, const char *destination); void cp_afc(const char *src, const char *dest);
void link_path(const char *src, const char *dest);
void link_dir(int src, int dest); void link_dir(int src, int dest);
int getattr(const char *path, struct file_attr *a); int getattr(const char *path, file_attr *a);
int getattrat(int dirfd, const char *name, struct file_attr *a); int getattrat(int dirfd, const char *name, file_attr *a);
int fgetattr(int fd, struct file_attr *a); int fgetattr(int fd, file_attr *a);
int setattr(const char *path, struct file_attr *a); int setattr(const char *path, file_attr *a);
int setattrat(int dirfd, const char *name, struct file_attr *a); int setattrat(int dirfd, const char *name, file_attr *a);
int fsetattr(int fd, struct file_attr *a); int fsetattr(int fd, file_attr *a);
void fclone_attr(int sourcefd, int targetfd); void fclone_attr(int src, int dest);
void clone_attr(const char *source, const char *target); void clone_attr(const char *src, const char *dest);
void fd_full_read(int fd, void **buf, size_t *size); void fd_full_read(int fd, void **buf, size_t *size);
void full_read(const char *filename, void **buf, size_t *size); void full_read(const char *filename, void **buf, size_t *size);
void write_zero(int fd, size_t size); void write_zero(int fd, size_t size);
@ -64,10 +65,10 @@ static inline void file_readline(const char *file,
file_readline(false, file, fn); file_readline(false, file, fn);
} }
void parse_prop_file(const char *file, void parse_prop_file(const char *file,
const std::function<bool(std::string_view, std::string_view)> &fn); const std::function<bool(std::string_view, std::string_view)> &&fn);
void *__mmap(const char *filename, size_t *size, bool rw); void *__mmap(const char *filename, size_t *size, bool rw);
void frm_rf(int dirfd); void frm_rf(int dirfd);
void clone_dir(int src, int dest, bool overwrite = true); void clone_dir(int src, int dest);
void parse_mnt(const char *file, const std::function<bool(mntent*)> &fn); void parse_mnt(const char *file, const std::function<bool(mntent*)> &fn);
void backup_folder(const char *dir, std::vector<raw_file> &files); void backup_folder(const char *dir, std::vector<raw_file> &files);
void restore_folder(const char *dir, std::vector<raw_file> &files); void restore_folder(const char *dir, std::vector<raw_file> &files);

View File

@ -18,6 +18,7 @@
#define setmntent __setmntent #define setmntent __setmntent
#define endmntent __endmntent #define endmntent __endmntent
#define hasmntopt __hasmntopt #define hasmntopt __hasmntopt
#define faccessat __faccessat
ssize_t __getline(char **lineptr, size_t *n, FILE *stream); ssize_t __getline(char **lineptr, size_t *n, FILE *stream);
ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream); ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
@ -58,3 +59,7 @@ static inline int __linkat(int olddirfd, const char *oldpath,
static inline int __inotify_init1(int flags) { static inline int __inotify_init1(int flags) {
return syscall(__NR_inotify_init1, flags); return syscall(__NR_inotify_init1, flags);
} }
static inline int __faccessat(int dirfd, const char *pathname, int mode, int flags) {
return syscall(__NR_faccessat, dirfd, pathname, mode, flags);
}