Magic Mount algorithm massive bug fix

This commit is contained in:
topjohnwu 2017-06-12 03:29:01 +08:00
parent 309b99eac0
commit 1777d9f751
2 changed files with 86 additions and 54 deletions

View File

@ -29,11 +29,13 @@ static int debug_log_pid, debug_log_fd;
* Node structure * * Node structure *
******************/ ******************/
// Precedence: MODULE > SKEL > DUMMY // Precedence: MODULE > SKEL > INTER > DUMMY
#define DO_NOTHING 0x0 /* intermediate node */ #define IS_DUMMY 0x01 /* mount from mirror */
#define IS_DUMMY 0x1 /* mount from mirror */ #define IS_INTER 0x02 /* intermediate node */
#define IS_SKEL 0x2 /* mount from skeleton */ #define IS_SKEL 0x04 /* mount from skeleton */
#define IS_MODULE 0x4 /* mount from module */ #define IS_MODULE 0x08 /* mount from module */
#define IS_VENDOR 0x10 /* special vendor placeholder */
struct node_entry { struct node_entry {
const char *module; /* Only used when status & IS_MODULE */ const char *module; /* Only used when status & IS_MODULE */
@ -252,9 +254,7 @@ static struct node_entry *insert_child(struct node_entry *p, struct node_entry *
// Exist duplicate // Exist duplicate
if (c->status > e->status) { if (c->status > e->status) {
// Precedence is higher, replace with new node // Precedence is higher, replace with new node
c->children = e->children; // Preserve all children destroy_subtree(e);
free(e->name);
free(e);
vec_entry(p->children)[_] = c; vec_entry(p->children)[_] = c;
return c; return c;
} else { } else {
@ -289,24 +289,43 @@ static void construct_tree(const char *module, struct node_entry *parent) {
node->name = strdup(entry->d_name); node->name = strdup(entry->d_name);
node->type = entry->d_type; node->type = entry->d_type;
snprintf(buf, PATH_MAX, "%s/%s", parent_path, node->name); snprintf(buf, PATH_MAX, "%s/%s", parent_path, node->name);
// Check if the entry has a correspond target
/*
* Clone the parent in the following condition:
* 1. File in module is a symlink
* 2. Target file do not exist
* 3. Target file is a symlink, but not /system/vendor
*/
int clone = 0;
if (IS_LNK(node) || access(buf, F_OK) == -1) { if (IS_LNK(node) || access(buf, F_OK) == -1) {
clone = 1;
} else if (strcmp(parent->name, "/system") != 0 || strcmp(node->name, "vendor") != 0) {
struct stat s;
xstat(buf, &s);
if (S_ISLNK(s.st_mode))
clone = 1;
}
if (clone) {
// Mark the parent folder as a skeleton // Mark the parent folder as a skeleton
parent->status |= IS_SKEL; parent->status |= IS_SKEL; /* This will not overwrite if parent is module */
node->status |= IS_MODULE; node->status = IS_MODULE;
} else if (IS_DIR(node)) { } else if (IS_DIR(node)) {
// Check if marked as replace // Check if marked as replace
snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf); snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf);
if (access(buf2, F_OK) == 0) { if (access(buf2, F_OK) == 0) {
// Replace everything, mark as leaf // Replace everything, mark as leaf
node->status |= IS_MODULE; node->status = IS_MODULE;
} else {
// This will be an intermediate node
node->status = IS_INTER;
} }
} else if (IS_REG(node)) { } else if (IS_REG(node)) {
// This is a leaf, mark as target // This is a leaf, mark as target
node->status |= IS_MODULE; node->status = IS_MODULE;
} }
node = insert_child(parent, node); node = insert_child(parent, node);
if (IS_DIR(node) && !(node->status & IS_MODULE)) { if (node->status == IS_INTER) {
// Intermediate node, travel deeper // Intermediate node, travel deeper
construct_tree(module, node); construct_tree(module, node);
} }
@ -325,7 +344,8 @@ static void clone_skeleton(struct node_entry *node) {
// Clone the structure // Clone the structure
char *full_path = get_full_path(node); char *full_path = get_full_path(node);
if (!(dir = opendir(full_path))) snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path);
if (!(dir = opendir(buf)))
goto cleanup; goto cleanup;
while ((entry = xreaddir(dir))) { while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
@ -334,7 +354,7 @@ static void clone_skeleton(struct node_entry *node) {
dummy = xcalloc(sizeof(*dummy), 1); dummy = xcalloc(sizeof(*dummy), 1);
dummy->name = strdup(entry->d_name); dummy->name = strdup(entry->d_name);
dummy->type = entry->d_type; dummy->type = entry->d_type;
dummy->status |= IS_DUMMY; dummy->status = IS_DUMMY;
insert_child(node, dummy); insert_child(node, dummy);
} }
closedir(dir); closedir(dir);
@ -342,21 +362,31 @@ static void clone_skeleton(struct node_entry *node) {
snprintf(buf, PATH_MAX, "%s%s", DUMMDIR, full_path); snprintf(buf, PATH_MAX, "%s%s", DUMMDIR, full_path);
mkdir_p(buf, 0755); mkdir_p(buf, 0755);
clone_attr(full_path, buf); clone_attr(full_path, buf);
if (node->status & IS_SKEL)
bind_mount(buf, full_path); bind_mount(buf, full_path);
vec_for_each(node->children, child) { vec_for_each(node->children, child) {
snprintf(buf, PATH_MAX, "%s%s/%s", DUMMDIR, full_path, child->name); snprintf(buf, PATH_MAX, "%s%s/%s", DUMMDIR, full_path, child->name);
// Create the dummy file/directory // Create the dummy file/directory
if (IS_DIR(child)) if (IS_DIR(child))
xmkdir(buf, 0755); mkdir(buf, 0755);
else if (IS_REG(child)) else if (IS_REG(child))
close(open_new(buf)); close(open_new(buf));
// Links will be handled later
if (child->status & IS_MODULE) { if (child->status & IS_VENDOR) {
if (IS_LNK(child)) {
cp_afc(MIRRDIR "/system/vendor", "/system/vendor");
LOGI("cplink: %s -> %s\n", MIRRDIR "/system/vendor", "/system/vendor");
}
// Skip
continue;
} else if (child->status & IS_MODULE) {
// Mount from module file to dummy file // Mount from module file to dummy file
snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, child->module, full_path, child->name); snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, child->module, full_path, child->name);
} else if (child->status & IS_SKEL) { } else if (child->status & (IS_SKEL | IS_INTER)) {
// It's another skeleton, recursive call and end // It's a intermediate folder, recursive clone
clone_skeleton(child); clone_skeleton(child);
continue; continue;
} else if (child->status & IS_DUMMY) { } else if (child->status & IS_DUMMY) {
@ -365,11 +395,8 @@ static void clone_skeleton(struct node_entry *node) {
} }
if (IS_LNK(child)) { if (IS_LNK(child)) {
// Symlink special treatments // Copy symlinks directly
char *temp = xmalloc(PATH_MAX); cp_afc(buf2, buf);
xreadlink(buf2, temp, PATH_MAX);
symlink(temp, buf);
free(temp);
LOGI("cplink: %s -> %s\n", buf2, buf); LOGI("cplink: %s -> %s\n", buf2, buf);
} else { } else {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name); snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
@ -385,15 +412,6 @@ static void magic_mount(struct node_entry *node) {
char *real_path; char *real_path;
struct node_entry *child; struct node_entry *child;
if (strcmp(node->name, "vendor") == 0 && strcmp(node->parent->name, "/system") == 0) {
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, node->module);
snprintf(buf2, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, node->module);
unlink(buf2);
symlink(buf, buf2);
return;
}
if (node->status) {
if (node->status & IS_MODULE) { if (node->status & IS_MODULE) {
// The real deal, mount module item // The real deal, mount module item
real_path = get_full_path(node); real_path = get_full_path(node);
@ -403,13 +421,13 @@ static void magic_mount(struct node_entry *node) {
} else if (node->status & IS_SKEL) { } else if (node->status & IS_SKEL) {
// The node is labeled to be cloned with skeleton, lets do it // The node is labeled to be cloned with skeleton, lets do it
clone_skeleton(node); clone_skeleton(node);
} } else if (node->status & IS_INTER) {
// We should not see dummies, so no need to handle it here
} else {
// It's an intermediate node, travel deeper // It's an intermediate node, travel deeper
vec_for_each(node->children, child) vec_for_each(node->children, child)
magic_mount(child); magic_mount(child);
} }
// The only thing goes here should be vendor placeholder
// There should be no dummies, so don't need to handle it here
} }
/**************** /****************
@ -584,6 +602,7 @@ void post_fs_data(int client) {
// Create the system root entry // Create the system root entry
sys_root = xcalloc(sizeof(*sys_root), 1); sys_root = xcalloc(sizeof(*sys_root), 1);
sys_root->name = strdup("/system"); sys_root->name = strdup("/system");
sys_root->status = IS_INTER;
int has_modules = 0; int has_modules = 0;
@ -629,6 +648,13 @@ void post_fs_data(int client) {
// Construct structure // Construct structure
has_modules = 1; has_modules = 1;
LOGI("%s: constructing magic mount structure\n", module); LOGI("%s: constructing magic mount structure\n", module);
// If /system/vendor exists in module, create a link outside
snprintf(buf2, PATH_MAX, "%s/system/vendor", buf);
if (access(buf2, F_OK) == 0) {
snprintf(buf, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, module);
unlink(buf);
symlink(buf2, buf);
}
construct_tree(module, sys_root); construct_tree(module, sys_root);
} }
} }
@ -679,25 +705,30 @@ void post_fs_data(int client) {
LOGI("link: %s -> %s\n", buf, buf2); LOGI("link: %s -> %s\n", buf, buf2);
} }
// Magic!! // Extract the vendor node out of system tree and swap with placeholder
magic_mount(sys_root);
// Get the vendor node if exists
vec_for_each(sys_root->children, child) { vec_for_each(sys_root->children, child) {
if (strcmp(child->name, "vendor") == 0) { if (strcmp(child->name, "vendor") == 0) {
ven_root = child; ven_root = child;
free(ven_root->name); child = xcalloc(sizeof(*child), 1);
child->type = seperate_vendor ? DT_LNK : DT_DIR;
child->parent = ven_root->parent;
child->name = ven_root->name;
child->status = IS_VENDOR;
vec_entry(sys_root->children)[_] = child;
ven_root->name = strdup("/vendor"); ven_root->name = strdup("/vendor");
ven_root->parent = NULL; ven_root->parent = NULL;
break; break;
} }
} }
if (ven_root)
magic_mount(ven_root); // Magic!!
magic_mount(sys_root);
if (ven_root) magic_mount(ven_root);
} }
// Cleanup memory // Cleanup memory
destroy_subtree(sys_root); destroy_subtree(sys_root);
if (ven_root) destroy_subtree(ven_root);
// Execute module scripts // Execute module scripts
LOGI("* Running module post-fs-data scripts\n"); LOGI("* Running module post-fs-data scripts\n");

View File

@ -311,6 +311,7 @@ int cp_afc(const char *source, const char *target) {
char buffer[PATH_MAX]; char buffer[PATH_MAX];
xreadlink(source, buffer, sizeof(buffer)); xreadlink(source, buffer, sizeof(buffer));
xsymlink(buffer, target); xsymlink(buffer, target);
lchown(target, buf.st_uid, buf.st_gid);
lgetfilecon(source, &con); lgetfilecon(source, &con);
lsetfilecon(target, con); lsetfilecon(target, con);
free(con); free(con);