Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
15f15510
Commit
15f15510
authored
Apr 24, 2020
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rewrite skel_node mounting and construction logic
Close #2725
parent
2468f5a6
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
116 additions
and
97 deletions
+116
-97
module.cpp
native/jni/core/module.cpp
+116
-97
No files found.
native/jni/core/module.cpp
View file @
15f15510
...
...
@@ -17,13 +17,13 @@ using namespace std;
#define VLOGI(tag, from, to) LOGI("%-8s: %s\n", tag, to)
#endif
#define TYPE_
INTER (1 << 0)
/* intermediate node
*/
#define TYPE_
MIRROR (1 << 1)
/* mount from mirror
*/
#define TYPE_
MIRROR (1 << 0)
/* mount from mirror
*/
#define TYPE_
INTER (1 << 1)
/* intermediate node
*/
#define TYPE_SKEL (1 << 2)
/* replace with tmpfs */
#define TYPE_MODULE (1 << 3)
/* mount from module */
#define TYPE_ROOT (1 << 4)
/* partition root */
#define TYPE_CUSTOM (1 << 5)
/* custom node type overrides all */
#define TYPE_DIR (TYPE_INTER|TYPE_
MIRROR|TYPE_
SKEL|TYPE_ROOT)
#define TYPE_DIR (TYPE_INTER|TYPE_SKEL|TYPE_ROOT)
vector
<
string
>
module_list
;
...
...
@@ -86,14 +86,14 @@ protected:
/* Use top bit of _file_type for node exist status */
bool
exist
()
{
return
static_cast
<
bool
>
(
_file_type
&
(
1
<<
7
));
}
void
set_exist
(
)
{
_file_type
|=
(
1
<<
7
);
}
void
set_exist
(
bool
b
)
{
if
(
b
)
_file_type
|=
(
1
<<
7
);
else
_file_type
&=
~
(
1
<<
7
);
}
uint8_t
file_type
()
{
return
static_cast
<
uint8_t
>
(
_file_type
&
~
(
1
<<
7
));
}
private
:
friend
void
merge_node
(
node_entry
*
a
,
node_entry
*
b
);
friend
class
dir_node
;
bool
need_
clone
(
);
bool
need_
skel_upgrade
(
node_entry
*
child
);
// Node properties
string
_name
;
...
...
@@ -113,7 +113,11 @@ public:
typedef
map
<
string_view
,
node_entry
*>
map_type
;
typedef
map_type
::
iterator
map_iter
;
~
dir_node
()
override
;
~
dir_node
()
override
{
for
(
auto
&
it
:
children
)
delete
it
.
second
;
children
.
clear
();
}
// Return false to indicate need to upgrade to module
bool
collect_files
(
const
char
*
module
,
int
dfd
);
...
...
@@ -191,13 +195,6 @@ protected:
template
<
class
T
>
dir_node
(
const
char
*
name
,
T
*
self
)
:
dir_node
(
name
,
DT_DIR
,
self
)
{}
private
:
// Root node lookup cache
root_node
*
_root
;
// dir nodes host children
map_type
children
;
template
<
class
T
=
node_entry
>
T
*
iter_to_node
(
const
map_iter
&
it
)
{
return
reinterpret_cast
<
T
*>
(
it
==
children
.
end
()
?
nullptr
:
it
->
second
);
...
...
@@ -226,6 +223,12 @@ private:
return
node
;
});
}
// dir nodes host children
map_type
children
;
// Root node lookup cache
root_node
*
_root
;
};
class
root_node
:
public
dir_node
{
...
...
@@ -243,22 +246,6 @@ private:
friend
class
module_node
;
};
void
node_entry
::
create_and_mount
(
const
string
&
src
)
{
const
string
&
dest
=
node_path
();
if
(
is_lnk
())
{
VLOGI
(
"cp_link"
,
src
.
data
(),
dest
.
data
());
cp_afc
(
src
.
data
(),
dest
.
data
());
}
else
{
if
(
is_dir
())
xmkdir
(
dest
.
data
(),
0
);
else
if
(
is_reg
())
close
(
xopen
(
dest
.
data
(),
O_RDONLY
|
O_CREAT
|
O_CLOEXEC
,
0
));
else
return
;
bind_mount
(
src
.
data
(),
dest
.
data
());
}
}
class
module_node
:
public
node_entry
{
public
:
module_node
(
const
char
*
module
,
dirent
*
entry
)
...
...
@@ -270,45 +257,23 @@ public:
module_node
(
inter_node
*
node
)
:
module_node
(
node
,
node
->
module
)
{}
void
mount
()
override
{
string
src
=
module_mnt
+
module
+
parent
()
->
root
()
->
prefix
+
node_path
();
if
(
exist
())
clone_attr
(
mirror_path
().
data
(),
src
.
data
());
if
(
isa
<
skel_node
>
(
parent
()))
create_and_mount
(
src
);
else
if
(
is_dir
()
||
is_reg
())
bind_mount
(
src
.
data
(),
node_path
().
data
());
}
void
mount
()
override
;
private
:
const
char
*
module
;
};
class
mirror_node
:
public
dir_node
{
class
mirror_node
:
public
node_entry
{
public
:
mirror_node
(
dirent
*
entry
)
:
dir_node
(
entry
->
d_name
,
entry
->
d_type
,
this
)
{}
mirror_node
(
dirent
*
entry
)
:
node_entry
(
entry
->
d_name
,
entry
->
d_type
,
this
)
{}
void
mount
()
override
{
create_and_mount
(
mirror_path
());
dir_node
::
mount
();
}
};
class
skel_node
:
public
dir_node
{
public
:
skel_node
(
node_entry
*
node
)
:
dir_node
(
node
,
this
)
{}
void
mount
()
override
{
string
src
=
mirror_path
();
const
string
&
dest
=
node_path
();
file_attr
a
;
getattr
(
src
.
data
(),
&
a
);
mkdir
(
dest
.
data
(),
0
);
xmount
(
"tmpfs"
,
dest
.
data
(),
"tmpfs"
,
0
,
nullptr
);
VLOGI
(
"mnt_tmp"
,
"tmpfs"
,
dest
.
data
());
setattr
(
dest
.
data
(),
&
a
);
dir_node
::
mount
();
}
skel_node
(
node_entry
*
node
);
void
mount
()
override
;
};
// Poor man's dynamic cast without RTTI
...
...
@@ -347,11 +312,9 @@ const string &node_entry::node_path() {
return
_node_path
;
}
dir_node
::~
dir_node
()
{
for
(
auto
&
it
:
children
)
delete
it
.
second
;
children
.
clear
();
}
/*************************
* Node Tree Construction
*************************/
template
<
typename
Func
>
dir_node
::
map_iter
dir_node
::
insert
(
dir_node
::
map_iter
it
,
uint8_t
type
,
Func
fn
,
bool
allow_same
)
{
...
...
@@ -395,66 +358,71 @@ node_entry* dir_node::extract(string_view name) {
return
nullptr
;
}
bool
node_entry
::
need_clone
()
{
/* We need to upgrade parent to skeleton if:
skel_node
::
skel_node
(
node_entry
*
node
)
:
dir_node
(
node
,
this
)
{
string
mirror
=
mirror_path
();
if
(
auto
dir
=
open_dir
(
mirror
.
data
());
dir
)
{
set_exist
(
true
);
for
(
dirent
*
entry
;
(
entry
=
xreaddir
(
dir
.
get
()));)
{
// Insert mirror nodes
emplace
<
mirror_node
>
(
entry
->
d_name
,
entry
);
}
}
else
{
// It is actually possible that mirror does not exist (nested mount points)
// Set self to non exist so this node will be ignored at mount
set_exist
(
false
);
return
;
}
for
(
auto
it
=
children
.
begin
();
it
!=
children
.
end
();
++
it
)
{
// Need to upgrade all inter_node children to skel_node
if
(
isa
<
inter_node
>
(
it
->
second
))
it
=
upgrade
<
skel_node
>
(
it
);
}
}
bool
node_entry
::
need_skel_upgrade
(
node_entry
*
child
)
{
/* We need to upgrade to skeleton if:
* - Target does not exist
* - Source or target is a symlink */
bool
clon
e
=
false
;
bool
upgrad
e
=
false
;
struct
stat
st
;
if
(
lstat
(
node_path
().
data
(),
&
st
)
!=
0
)
{
clon
e
=
true
;
if
(
lstat
(
child
->
node_path
().
data
(),
&
st
)
!=
0
)
{
upgrad
e
=
true
;
}
else
{
set_exist
();
// cache exist result
if
(
is_lnk
()
||
S_ISLNK
(
st
.
st_mode
))
clon
e
=
true
;
child
->
set_exist
(
true
);
if
(
child
->
is_lnk
()
||
S_ISLNK
(
st
.
st_mode
))
upgrad
e
=
true
;
}
return
clon
e
;
return
upgrad
e
;
}
bool
dir_node
::
prepare
()
{
bool
upgrade
_skel
=
false
;
bool
to
_skel
=
false
;
for
(
auto
it
=
children
.
begin
();
it
!=
children
.
end
();)
{
auto
child
=
it
->
second
;
if
(
child
->
need_clone
())
{
if
(
need_skel_upgrade
(
it
->
second
))
{
if
(
node_type
>
type_id
<
skel_node
>
())
{
// Upgrade will fail
goto
delete_node
;
// Upgrade will fail, remove the unsupported child node
delete
it
->
second
;
it
=
children
.
erase
(
it
);
continue
;
}
// Tell parent to upgrade self to skel
upgrade
_skel
=
true
;
to
_skel
=
true
;
// If child is inter_node, upgrade to module
if
(
auto
nit
=
upgrade
<
module_node
,
inter_node
>
(
it
);
nit
!=
children
.
end
())
{
it
=
nit
;
goto
next_node
;
}
}
if
(
auto
dn
=
dyn_cast
<
dir_node
>
(
child
);
dn
&&
dn
->
is_dir
()
&&
!
dn
->
prepare
())
{
string
mirror
=
dn
->
mirror_path
();
if
(
access
(
mirror
.
data
(),
F_OK
)
!=
0
)
{
// It is actually possible that mirror does not exist
goto
delete_node
;
}
// Upgrade child to skeleton (shall always success)
if
(
auto
dn
=
dyn_cast
<
dir_node
>
(
it
->
second
);
dn
&&
dn
->
is_dir
()
&&
!
dn
->
prepare
())
{
// Upgrade child to skeleton
it
=
upgrade
<
skel_node
>
(
it
);
auto
skel
=
iter_to_node
<
skel_node
>
(
it
);
auto
dir
=
xopen_dir
(
mirror
.
data
());
for
(
dirent
*
entry
;
(
entry
=
xreaddir
(
dir
.
get
()));)
{
// Insert mirror nodes
skel
->
emplace
<
mirror_node
>
(
entry
->
d_name
,
entry
);
}
}
next_node
:
++
it
;
continue
;
delete_node
:
// Remove the unsupported child node
delete
it
->
second
;
it
=
children
.
erase
(
it
);
continue
;
}
return
!
upgrade
_skel
;
return
!
to
_skel
;
}
bool
dir_node
::
collect_files
(
const
char
*
module
,
int
dfd
)
{
...
...
@@ -482,6 +450,57 @@ bool dir_node::collect_files(const char *module, int dfd) {
return
true
;
}
/************************
* Mount Implementations
************************/
void
node_entry
::
create_and_mount
(
const
string
&
src
)
{
const
string
&
dest
=
node_path
();
if
(
is_lnk
())
{
VLOGI
(
"cp_link"
,
src
.
data
(),
dest
.
data
());
cp_afc
(
src
.
data
(),
dest
.
data
());
}
else
{
if
(
is_dir
())
xmkdir
(
dest
.
data
(),
0
);
else
if
(
is_reg
())
close
(
xopen
(
dest
.
data
(),
O_RDONLY
|
O_CREAT
|
O_CLOEXEC
,
0
));
else
return
;
bind_mount
(
src
.
data
(),
dest
.
data
());
}
}
void
module_node
::
mount
()
{
string
src
=
module_mnt
+
module
+
parent
()
->
root
()
->
prefix
+
node_path
();
if
(
exist
())
clone_attr
(
mirror_path
().
data
(),
src
.
data
());
if
(
isa
<
skel_node
>
(
parent
()))
create_and_mount
(
src
);
else
if
(
is_dir
()
||
is_reg
())
bind_mount
(
src
.
data
(),
node_path
().
data
());
}
void
skel_node
::
mount
()
{
if
(
!
exist
())
return
;
string
src
=
mirror_path
();
const
string
&
dest
=
node_path
();
file_attr
a
;
getattr
(
src
.
data
(),
&
a
);
mkdir
(
dest
.
data
(),
0
);
if
(
!
isa
<
skel_node
>
(
parent
()))
{
// We don't need another layer of tmpfs if parent is skel
xmount
(
"tmpfs"
,
dest
.
data
(),
"tmpfs"
,
0
,
nullptr
);
VLOGI
(
"mnt_tmp"
,
"tmpfs"
,
dest
.
data
());
}
setattr
(
dest
.
data
(),
&
a
);
dir_node
::
mount
();
}
/****************
* Magisk Stuffs
****************/
class
magisk_node
:
public
node_entry
{
public
:
magisk_node
(
const
char
*
name
)
:
node_entry
(
name
,
DT_REG
,
this
)
{}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment