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
78d7c45b
Commit
78d7c45b
authored
Nov 26, 2019
by
Viktor De Pasquale
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'john/master' into feature/redesign
parents
ac5ecf22
72edbfc4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
239 additions
and
231 deletions
+239
-231
SuHandler.kt
app/src/main/java/com/topjohnwu/magisk/utils/SuHandler.kt
+1
-1
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+83
-47
daemon.cpp
native/jni/core/daemon.cpp
+12
-8
db.cpp
native/jni/core/db.cpp
+1
-1
init.cpp
native/jni/init/init.cpp
+11
-12
bootimg.cpp
native/jni/magiskboot/bootimg.cpp
+6
-5
compress.cpp
native/jni/magiskboot/compress.cpp
+74
-102
compress.h
native/jni/magiskboot/compress.h
+5
-2
ramdisk.cpp
native/jni/magiskboot/ramdisk.cpp
+6
-5
policydb.cpp
native/jni/magiskpolicy/policydb.cpp
+10
-9
rules.cpp
native/jni/magiskpolicy/rules.cpp
+1
-1
cpio.cpp
native/jni/utils/cpio.cpp
+2
-2
files.h
native/jni/utils/files.h
+7
-1
stream.h
native/jni/utils/include/stream.h
+11
-13
stream.cpp
native/jni/utils/stream.cpp
+8
-21
FileProvider.java
shared/src/main/java/com/topjohnwu/magisk/FileProvider.java
+1
-1
No files found.
app/src/main/java/com/topjohnwu/magisk/utils/SuHandler.kt
View file @
78d7c45b
...
@@ -28,7 +28,7 @@ object SuHandler : ProviderCallHandler {
...
@@ -28,7 +28,7 @@ object SuHandler : ProviderCallHandler {
override
fun
call
(
context
:
Context
,
method
:
String
,
arg
:
String
?,
extras
:
Bundle
?):
Bundle
?
{
override
fun
call
(
context
:
Context
,
method
:
String
,
arg
:
String
?,
extras
:
Bundle
?):
Bundle
?
{
invoke
(
context
.
wrap
(),
method
,
extras
)
invoke
(
context
.
wrap
(),
method
,
extras
)
return
null
return
Bundle
.
EMPTY
}
}
operator
fun
invoke
(
context
:
Context
,
action
:
String
?,
data
:
Bundle
?)
{
operator
fun
invoke
(
context
:
Context
,
action
:
String
?,
data
:
Bundle
?)
{
...
...
app/src/main/res/values-pt-rBR/strings.xml
View file @
78d7c45b
This diff is collapsed.
Click to expand it.
native/jni/core/daemon.cpp
View file @
78d7c45b
...
@@ -100,6 +100,18 @@ static void *request_handler(void *args) {
...
@@ -100,6 +100,18 @@ static void *request_handler(void *args) {
static
void
main_daemon
()
{
static
void
main_daemon
()
{
android_logging
();
android_logging
();
int
fd
=
xopen
(
"/dev/null"
,
O_WRONLY
);
xdup2
(
fd
,
STDOUT_FILENO
);
xdup2
(
fd
,
STDERR_FILENO
);
if
(
fd
>
STDERR_FILENO
)
close
(
fd
);
fd
=
xopen
(
"/dev/zero"
,
O_RDONLY
);
xdup2
(
fd
,
STDIN_FILENO
);
if
(
fd
>
STDERR_FILENO
)
close
(
fd
);
close
(
fd
);
setsid
();
setsid
();
setcon
(
"u:r:"
SEPOL_PROC_DOMAIN
":s0"
);
setcon
(
"u:r:"
SEPOL_PROC_DOMAIN
":s0"
);
restore_rootcon
();
restore_rootcon
();
...
@@ -112,14 +124,6 @@ static void main_daemon() {
...
@@ -112,14 +124,6 @@ static void main_daemon() {
},
true
);
},
true
);
}
}
int
fd
=
xopen
(
"/dev/null"
,
O_RDWR
|
O_CLOEXEC
);
xdup2
(
fd
,
STDOUT_FILENO
);
xdup2
(
fd
,
STDERR_FILENO
);
close
(
fd
);
fd
=
xopen
(
"/dev/zero"
,
O_RDWR
|
O_CLOEXEC
);
xdup2
(
fd
,
STDIN_FILENO
);
close
(
fd
);
LOGI
(
SHOW_VER
(
Magisk
)
" daemon started
\n
"
);
LOGI
(
SHOW_VER
(
Magisk
)
" daemon started
\n
"
);
// Get server stat
// Get server stat
...
...
native/jni/core/db.cpp
View file @
78d7c45b
...
@@ -138,7 +138,7 @@ static char *open_and_init_db(sqlite3 *&db) {
...
@@ -138,7 +138,7 @@ static char *open_and_init_db(sqlite3 *&db) {
upgrade
=
true
;
upgrade
=
true
;
}
}
if
(
ver
<
10
)
{
if
(
ver
<
10
)
{
sqlite3_exec
(
db
,
"DROP TABLE logs"
,
nullptr
,
nullptr
,
&
err
);
sqlite3_exec
(
db
,
"DROP TABLE
IF EXISTS
logs"
,
nullptr
,
nullptr
,
&
err
);
err_ret
(
err
);
err_ret
(
err
);
ver
=
10
;
ver
=
10
;
upgrade
=
true
;
upgrade
=
true
;
...
...
native/jni/init/init.cpp
View file @
78d7c45b
...
@@ -38,23 +38,22 @@ static int vprintk(const char *fmt, va_list ap) {
...
@@ -38,23 +38,22 @@ static int vprintk(const char *fmt, va_list ap) {
}
}
void
setup_klog
()
{
void
setup_klog
()
{
// Shut down first 3 fds
// Shut down first 3 fds
int
null
;
int
fd
;
if
(
access
(
"/dev/null"
,
W_OK
)
==
0
)
{
if
(
access
(
"/dev/null"
,
W_OK
)
==
0
)
{
null
=
xopen
(
"/dev/null"
,
O_RDWR
|
O_CLOEXEC
);
fd
=
xopen
(
"/dev/null"
,
O_RDWR
|
O_CLOEXEC
);
}
else
{
}
else
{
mknod
(
"/null"
,
S_IFCHR
|
0666
,
makedev
(
1
,
3
));
mknod
(
"/null"
,
S_IFCHR
|
0666
,
makedev
(
1
,
3
));
null
=
xopen
(
"/null"
,
O_RDWR
|
O_CLOEXEC
);
fd
=
xopen
(
"/null"
,
O_RDWR
|
O_CLOEXEC
);
unlink
(
"/null"
);
unlink
(
"/null"
);
}
}
xdup3
(
null
,
STDIN_FILENO
,
O_CLOEXEC
);
xdup3
(
fd
,
STDIN_FILENO
,
O_CLOEXEC
);
xdup3
(
null
,
STDOUT_FILENO
,
O_CLOEXEC
);
xdup3
(
fd
,
STDOUT_FILENO
,
O_CLOEXEC
);
xdup3
(
null
,
STDERR_FILENO
,
O_CLOEXEC
);
xdup3
(
fd
,
STDERR_FILENO
,
O_CLOEXEC
);
if
(
null
>
STDERR_FILENO
)
if
(
fd
>
STDERR_FILENO
)
close
(
null
);
close
(
fd
);
int
fd
;
if
(
access
(
"/dev/kmsg"
,
W_OK
)
==
0
)
{
if
(
access
(
"/proc/kmsg"
,
W_OK
)
==
0
)
{
fd
=
xopen
(
"/dev/kmsg"
,
O_WRONLY
|
O_CLOEXEC
);
fd
=
xopen
(
"/proc/kmsg"
,
O_WRONLY
|
O_CLOEXEC
);
}
else
{
}
else
{
mknod
(
"/kmsg"
,
S_IFCHR
|
0666
,
makedev
(
1
,
11
));
mknod
(
"/kmsg"
,
S_IFCHR
|
0666
,
makedev
(
1
,
11
));
fd
=
xopen
(
"/kmsg"
,
O_WRONLY
|
O_CLOEXEC
);
fd
=
xopen
(
"/kmsg"
,
O_WRONLY
|
O_CLOEXEC
);
...
...
native/jni/magiskboot/bootimg.cpp
View file @
78d7c45b
...
@@ -22,15 +22,16 @@ uint32_t dyn_img_hdr::j32 = 0;
...
@@ -22,15 +22,16 @@ uint32_t dyn_img_hdr::j32 = 0;
uint64_t
dyn_img_hdr
::
j64
=
0
;
uint64_t
dyn_img_hdr
::
j64
=
0
;
static
void
decompress
(
format_t
type
,
int
fd
,
const
void
*
in
,
size_t
size
)
{
static
void
decompress
(
format_t
type
,
int
fd
,
const
void
*
in
,
size_t
size
)
{
unique_ptr
<
stream
>
ptr
(
get_decoder
(
type
,
open_stream
<
fd_stream
>
(
fd
)
));
auto
ptr
=
get_decoder
(
type
,
make_stream
<
fd_stream
>
(
fd
));
ptr
->
write
(
in
,
size
);
ptr
->
write
(
in
,
size
);
}
}
static
int64
_t
compress
(
format_t
type
,
int
fd
,
const
void
*
in
,
size_t
size
)
{
static
off
_t
compress
(
format_t
type
,
int
fd
,
const
void
*
in
,
size_t
size
)
{
auto
prev
=
lseek
(
fd
,
0
,
SEEK_CUR
);
auto
prev
=
lseek
(
fd
,
0
,
SEEK_CUR
);
unique_ptr
<
stream
>
ptr
(
get_encoder
(
type
,
open_stream
<
fd_stream
>
(
fd
)));
{
ptr
->
write
(
in
,
size
);
auto
strm
=
get_encoder
(
type
,
make_stream
<
fd_stream
>
(
fd
));
ptr
->
close
();
strm
->
write
(
in
,
size
);
}
auto
now
=
lseek
(
fd
,
0
,
SEEK_CUR
);
auto
now
=
lseek
(
fd
,
0
,
SEEK_CUR
);
return
now
-
prev
;
return
now
-
prev
;
}
}
...
...
native/jni/magiskboot/compress.cpp
View file @
78d7c45b
...
@@ -22,7 +22,6 @@
...
@@ -22,7 +22,6 @@
using
namespace
std
;
using
namespace
std
;
#define bwrite filter_stream::write
#define bwrite filter_stream::write
#define bclose filter_stream::close
constexpr
size_t
CHUNK
=
0x40000
;
constexpr
size_t
CHUNK
=
0x40000
;
constexpr
size_t
LZ4_UNCOMPRESSED
=
0x800000
;
constexpr
size_t
LZ4_UNCOMPRESSED
=
0x800000
;
...
@@ -30,56 +29,41 @@ constexpr size_t LZ4_COMPRESSED = LZ4_COMPRESSBOUND(LZ4_UNCOMPRESSED);
...
@@ -30,56 +29,41 @@ constexpr size_t LZ4_COMPRESSED = LZ4_COMPRESSBOUND(LZ4_UNCOMPRESSED);
class
cpr_stream
:
public
filter_stream
{
class
cpr_stream
:
public
filter_stream
{
public
:
public
:
explicit
cpr_stream
(
FILE
*
fp
)
:
filter_stream
(
fp
)
{}
using
filter_stream
::
filter_stream
;
using
stream
::
read
;
int
read
(
void
*
buf
,
size_t
len
)
final
{
return
stream
::
read
(
buf
,
len
);
}
int
close
()
final
{
finish
();
return
bclose
();
}
protected
:
// If finish is overridden, destroy should be called in the destructor
virtual
void
finish
()
{}
void
destroy
()
{
if
(
fp
)
finish
();
}
};
};
class
gz_strm
:
public
cpr_stream
{
class
gz_strm
:
public
cpr_stream
{
public
:
public
:
~
gz_strm
()
override
{
destroy
();
}
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
return
len
?
write
(
buf
,
len
,
Z_NO_FLUSH
)
:
0
;
return
len
?
write
(
buf
,
len
,
Z_NO_FLUSH
)
:
0
;
}
}
protected
:
~
gz_strm
()
override
{
enum
mode_t
{
write
(
nullptr
,
0
,
Z_FINISH
);
DECODE
,
ENCODE
}
mode
;
gz_strm
(
mode_t
mode
,
FILE
*
fp
)
:
cpr_stream
(
fp
),
mode
(
mode
)
{
switch
(
mode
)
{
switch
(
mode
)
{
case
DECODE
:
case
DECODE
:
inflate
Init2
(
&
strm
,
15
|
16
);
inflate
End
(
&
strm
);
break
;
break
;
case
ENCODE
:
case
ENCODE
:
deflate
Init2
(
&
strm
,
9
,
Z_DEFLATED
,
15
|
16
,
8
,
Z_DEFAULT_STRATEGY
);
deflate
End
(
&
strm
);
break
;
break
;
}
}
}
}
void
finish
()
override
{
protected
:
write
(
nullptr
,
0
,
Z_FINISH
);
enum
mode_t
{
DECODE
,
ENCODE
}
mode
;
gz_strm
(
mode_t
mode
,
sFILE
&&
fp
)
:
cpr_stream
(
std
::
move
(
fp
)),
mode
(
mode
)
{
switch
(
mode
)
{
switch
(
mode
)
{
case
DECODE
:
case
DECODE
:
inflate
End
(
&
strm
);
inflate
Init2
(
&
strm
,
15
|
16
);
break
;
break
;
case
ENCODE
:
case
ENCODE
:
deflate
End
(
&
strm
);
deflate
Init2
(
&
strm
,
9
,
Z_DEFLATED
,
15
|
16
,
8
,
Z_DEFAULT_STRATEGY
);
break
;
break
;
}
}
}
}
...
@@ -115,47 +99,45 @@ private:
...
@@ -115,47 +99,45 @@ private:
class
gz_decoder
:
public
gz_strm
{
class
gz_decoder
:
public
gz_strm
{
public
:
public
:
explicit
gz_decoder
(
FILE
*
fp
)
:
gz_strm
(
DECODE
,
fp
)
{};
explicit
gz_decoder
(
sFILE
&&
fp
)
:
gz_strm
(
DECODE
,
std
::
move
(
fp
)
)
{};
};
};
class
gz_encoder
:
public
gz_strm
{
class
gz_encoder
:
public
gz_strm
{
public
:
public
:
explicit
gz_encoder
(
FILE
*
fp
)
:
gz_strm
(
ENCODE
,
fp
)
{};
explicit
gz_encoder
(
sFILE
&&
fp
)
:
gz_strm
(
ENCODE
,
std
::
move
(
fp
)
)
{};
};
};
class
bz_strm
:
public
cpr_stream
{
class
bz_strm
:
public
cpr_stream
{
public
:
public
:
~
bz_strm
()
override
{
destroy
();
}
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
return
len
?
write
(
buf
,
len
,
BZ_RUN
)
:
0
;
return
len
?
write
(
buf
,
len
,
BZ_RUN
)
:
0
;
}
}
protected
:
~
bz_strm
()
override
{
enum
mode_t
{
DECODE
,
ENCODE
}
mode
;
bz_strm
(
mode_t
mode
,
FILE
*
fp
)
:
cpr_stream
(
fp
),
mode
(
mode
)
{
switch
(
mode
)
{
switch
(
mode
)
{
case
DECODE
:
case
DECODE
:
BZ2_bzDecompress
Init
(
&
strm
,
0
,
0
);
BZ2_bzDecompress
End
(
&
strm
);
break
;
break
;
case
ENCODE
:
case
ENCODE
:
BZ2_bzCompressInit
(
&
strm
,
9
,
0
,
0
);
write
(
nullptr
,
0
,
BZ_FINISH
);
BZ2_bzCompressEnd
(
&
strm
);
break
;
break
;
}
}
}
}
void
finish
()
override
{
protected
:
enum
mode_t
{
DECODE
,
ENCODE
}
mode
;
bz_strm
(
mode_t
mode
,
sFILE
&&
fp
)
:
cpr_stream
(
std
::
move
(
fp
)),
mode
(
mode
)
{
switch
(
mode
)
{
switch
(
mode
)
{
case
DECODE
:
case
DECODE
:
BZ2_bzDecompress
End
(
&
strm
);
BZ2_bzDecompress
Init
(
&
strm
,
0
,
0
);
break
;
break
;
case
ENCODE
:
case
ENCODE
:
write
(
nullptr
,
0
,
BZ_FINISH
);
BZ2_bzCompressInit
(
&
strm
,
9
,
0
,
0
);
BZ2_bzCompressEnd
(
&
strm
);
break
;
break
;
}
}
}
}
...
@@ -191,22 +173,25 @@ private:
...
@@ -191,22 +173,25 @@ private:
class
bz_decoder
:
public
bz_strm
{
class
bz_decoder
:
public
bz_strm
{
public
:
public
:
explicit
bz_decoder
(
FILE
*
fp
)
:
bz_strm
(
DECODE
,
fp
)
{};
explicit
bz_decoder
(
sFILE
&&
fp
)
:
bz_strm
(
DECODE
,
std
::
move
(
fp
)
)
{};
};
};
class
bz_encoder
:
public
bz_strm
{
class
bz_encoder
:
public
bz_strm
{
public
:
public
:
explicit
bz_encoder
(
FILE
*
fp
)
:
bz_strm
(
ENCODE
,
fp
)
{};
explicit
bz_encoder
(
sFILE
&&
fp
)
:
bz_strm
(
ENCODE
,
std
::
move
(
fp
)
)
{};
};
};
class
lzma_strm
:
public
cpr_stream
{
class
lzma_strm
:
public
cpr_stream
{
public
:
public
:
~
lzma_strm
()
override
{
destroy
();
}
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
return
len
?
write
(
buf
,
len
,
LZMA_RUN
)
:
0
;
return
len
?
write
(
buf
,
len
,
LZMA_RUN
)
:
0
;
}
}
~
lzma_strm
()
override
{
write
(
nullptr
,
0
,
LZMA_FINISH
);
lzma_end
(
&
strm
);
}
protected
:
protected
:
enum
mode_t
{
enum
mode_t
{
DECODE
,
DECODE
,
...
@@ -214,7 +199,8 @@ protected:
...
@@ -214,7 +199,8 @@ protected:
ENCODE_LZMA
ENCODE_LZMA
}
mode
;
}
mode
;
lzma_strm
(
mode_t
mode
,
FILE
*
fp
)
:
cpr_stream
(
fp
),
mode
(
mode
),
strm
(
LZMA_STREAM_INIT
)
{
lzma_strm
(
mode_t
mode
,
sFILE
&&
fp
)
:
cpr_stream
(
std
::
move
(
fp
)),
mode
(
mode
),
strm
(
LZMA_STREAM_INIT
)
{
lzma_options_lzma
opt
;
lzma_options_lzma
opt
;
// Initialize preset
// Initialize preset
...
@@ -238,11 +224,6 @@ protected:
...
@@ -238,11 +224,6 @@ protected:
}
}
}
}
void
finish
()
override
{
write
(
nullptr
,
0
,
LZMA_FINISH
);
lzma_end
(
&
strm
);
}
private
:
private
:
lzma_stream
strm
;
lzma_stream
strm
;
uint8_t
outbuf
[
CHUNK
];
uint8_t
outbuf
[
CHUNK
];
...
@@ -266,22 +247,22 @@ private:
...
@@ -266,22 +247,22 @@ private:
class
lzma_decoder
:
public
lzma_strm
{
class
lzma_decoder
:
public
lzma_strm
{
public
:
public
:
lzma_decoder
(
FILE
*
fp
)
:
lzma_strm
(
DECODE
,
fp
)
{}
explicit
lzma_decoder
(
sFILE
&&
fp
)
:
lzma_strm
(
DECODE
,
std
::
move
(
fp
)
)
{}
};
};
class
xz_encoder
:
public
lzma_strm
{
class
xz_encoder
:
public
lzma_strm
{
public
:
public
:
xz_encoder
(
FILE
*
fp
)
:
lzma_strm
(
ENCODE_XZ
,
fp
)
{}
explicit
xz_encoder
(
sFILE
&&
fp
)
:
lzma_strm
(
ENCODE_XZ
,
std
::
move
(
fp
)
)
{}
};
};
class
lzma_encoder
:
public
lzma_strm
{
class
lzma_encoder
:
public
lzma_strm
{
public
:
public
:
lzma_encoder
(
FILE
*
fp
)
:
lzma_strm
(
ENCODE_LZMA
,
fp
)
{}
explicit
lzma_encoder
(
sFILE
&&
fp
)
:
lzma_strm
(
ENCODE_LZMA
,
std
::
move
(
fp
)
)
{}
};
};
class
LZ4F_decoder
:
public
cpr_stream
{
class
LZ4F_decoder
:
public
cpr_stream
{
public
:
public
:
explicit
LZ4F_decoder
(
FILE
*
fp
)
:
cpr_stream
(
fp
),
outbuf
(
nullptr
)
{
explicit
LZ4F_decoder
(
sFILE
&&
fp
)
:
cpr_stream
(
std
::
move
(
fp
)
),
outbuf
(
nullptr
)
{
LZ4F_createDecompressionContext
(
&
ctx
,
LZ4F_VERSION
);
LZ4F_createDecompressionContext
(
&
ctx
,
LZ4F_VERSION
);
}
}
...
@@ -336,16 +317,11 @@ private:
...
@@ -336,16 +317,11 @@ private:
class
LZ4F_encoder
:
public
cpr_stream
{
class
LZ4F_encoder
:
public
cpr_stream
{
public
:
public
:
explicit
LZ4F_encoder
(
FILE
*
fp
)
:
cpr_stream
(
fp
),
outbuf
(
nullptr
),
outCapacity
(
0
)
{
explicit
LZ4F_encoder
(
sFILE
&&
fp
)
:
cpr_stream
(
std
::
move
(
fp
)),
outbuf
(
nullptr
),
outCapacity
(
0
)
{
LZ4F_createCompressionContext
(
&
ctx
,
LZ4F_VERSION
);
LZ4F_createCompressionContext
(
&
ctx
,
LZ4F_VERSION
);
}
}
~
LZ4F_encoder
()
override
{
destroy
();
LZ4F_freeCompressionContext
(
ctx
);
delete
[]
outbuf
;
}
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
int
write
(
const
void
*
buf
,
size_t
len
)
override
{
auto
ret
=
len
;
auto
ret
=
len
;
if
(
!
outbuf
)
if
(
!
outbuf
)
...
@@ -368,10 +344,11 @@ public:
...
@@ -368,10 +344,11 @@ public:
return
ret
;
return
ret
;
}
}
protected
:
~
LZ4F_encoder
()
override
{
void
finish
()
override
{
size_t
len
=
LZ4F_compressEnd
(
ctx
,
outbuf
,
outCapacity
,
nullptr
);
size_t
len
=
LZ4F_compressEnd
(
ctx
,
outbuf
,
outCapacity
,
nullptr
);
bwrite
(
outbuf
,
len
);
bwrite
(
outbuf
,
len
);
LZ4F_freeCompressionContext
(
ctx
);
delete
[]
outbuf
;
}
}
private
:
private
:
...
@@ -401,9 +378,9 @@ private:
...
@@ -401,9 +378,9 @@ private:
class
LZ4_decoder
:
public
cpr_stream
{
class
LZ4_decoder
:
public
cpr_stream
{
public
:
public
:
explicit
LZ4_decoder
(
FILE
*
fp
)
explicit
LZ4_decoder
(
sFILE
&&
fp
)
:
cpr_stream
(
fp
),
out_buf
(
new
char
[
LZ4_UNCOMPRESSED
]),
buffer
(
new
char
[
LZ4_
COMPRESSED
]),
:
cpr_stream
(
std
::
move
(
fp
)),
out_buf
(
new
char
[
LZ4_UN
COMPRESSED
]),
init
(
false
),
block_sz
(
0
),
buf_off
(
0
)
{}
buffer
(
new
char
[
LZ4_COMPRESSED
]),
init
(
false
),
block_sz
(
0
),
buf_off
(
0
)
{}
~
LZ4_decoder
()
override
{
~
LZ4_decoder
()
override
{
delete
[]
out_buf
;
delete
[]
out_buf
;
...
@@ -462,16 +439,10 @@ private:
...
@@ -462,16 +439,10 @@ private:
class
LZ4_encoder
:
public
cpr_stream
{
class
LZ4_encoder
:
public
cpr_stream
{
public
:
public
:
explicit
LZ4_encoder
(
FILE
*
fp
)
explicit
LZ4_encoder
(
sFILE
&&
fp
)
:
cpr_stream
(
fp
),
outbuf
(
new
char
[
LZ4_COMPRESSED
]),
buf
(
new
char
[
LZ4_UNCOMPRESSED
]),
:
cpr_stream
(
std
::
move
(
fp
)
),
outbuf
(
new
char
[
LZ4_COMPRESSED
]),
buf
(
new
char
[
LZ4_UNCOMPRESSED
]),
init
(
false
),
buf_off
(
0
),
in_total
(
0
)
{}
init
(
false
),
buf_off
(
0
),
in_total
(
0
)
{}
~
LZ4_encoder
()
override
{
destroy
();
delete
[]
outbuf
;
delete
[]
buf
;
}
int
write
(
const
void
*
in
,
size_t
size
)
override
{
int
write
(
const
void
*
in
,
size_t
size
)
override
{
if
(
!
init
)
{
if
(
!
init
)
{
bwrite
(
"
\x02\x21\x4c\x18
"
,
4
);
bwrite
(
"
\x02\x21\x4c\x18
"
,
4
);
...
@@ -510,14 +481,15 @@ public:
...
@@ -510,14 +481,15 @@ public:
return
true
;
return
true
;
}
}
protected
:
~
LZ4_encoder
()
override
{
void
finish
()
override
{
if
(
buf_off
)
{
if
(
buf_off
)
{
int
write
=
LZ4_compress_HC
(
buf
,
outbuf
,
buf_off
,
LZ4_COMPRESSED
,
9
);
int
write
=
LZ4_compress_HC
(
buf
,
outbuf
,
buf_off
,
LZ4_COMPRESSED
,
9
);
bwrite
(
&
write
,
sizeof
(
write
));
bwrite
(
&
write
,
sizeof
(
write
));
bwrite
(
outbuf
,
write
);
bwrite
(
outbuf
,
write
);
}
}
bwrite
(
&
in_total
,
sizeof
(
in_total
));
bwrite
(
&
in_total
,
sizeof
(
in_total
));
delete
[]
outbuf
;
delete
[]
buf
;
}
}
private
:
private
:
...
@@ -528,38 +500,38 @@ private:
...
@@ -528,38 +500,38 @@ private:
unsigned
in_total
;
unsigned
in_total
;
};
};
filter_stream
*
get_encoder
(
format_t
type
,
FILE
*
fp
)
{
stream_ptr
get_encoder
(
format_t
type
,
sFILE
&&
fp
)
{
switch
(
type
)
{
switch
(
type
)
{
case
XZ
:
case
XZ
:
return
new
xz_encoder
(
fp
);
return
make_unique
<
xz_encoder
>
(
std
::
move
(
fp
)
);
case
LZMA
:
case
LZMA
:
return
new
lzma_encoder
(
fp
);
return
make_unique
<
lzma_encoder
>
(
std
::
move
(
fp
)
);
case
BZIP2
:
case
BZIP2
:
return
new
bz_encoder
(
fp
);
return
make_unique
<
bz_encoder
>
(
std
::
move
(
fp
)
);
case
LZ4
:
case
LZ4
:
return
new
LZ4F_encoder
(
fp
);
return
make_unique
<
LZ4F_encoder
>
(
std
::
move
(
fp
)
);
case
LZ4_LEGACY
:
case
LZ4_LEGACY
:
return
new
LZ4_encoder
(
fp
);
return
make_unique
<
LZ4_encoder
>
(
std
::
move
(
fp
)
);
case
GZIP
:
case
GZIP
:
default:
default:
return
new
gz_encoder
(
fp
);
return
make_unique
<
gz_encoder
>
(
std
::
move
(
fp
)
);
}
}
}
}
filter_stream
*
get_decoder
(
format_t
type
,
FILE
*
fp
)
{
stream_ptr
get_decoder
(
format_t
type
,
sFILE
&&
fp
)
{
switch
(
type
)
{
switch
(
type
)
{
case
XZ
:
case
XZ
:
case
LZMA
:
case
LZMA
:
return
new
lzma_decoder
(
fp
);
return
make_unique
<
lzma_decoder
>
(
std
::
move
(
fp
)
);
case
BZIP2
:
case
BZIP2
:
return
new
bz_decoder
(
fp
);
return
make_unique
<
bz_decoder
>
(
std
::
move
(
fp
)
);
case
LZ4
:
case
LZ4
:
return
new
LZ4F_decoder
(
fp
);
return
make_unique
<
LZ4F_decoder
>
(
std
::
move
(
fp
)
);
case
LZ4_LEGACY
:
case
LZ4_LEGACY
:
return
new
LZ4_decoder
(
fp
);
return
make_unique
<
LZ4_decoder
>
(
std
::
move
(
fp
)
);
case
GZIP
:
case
GZIP
:
default:
default:
return
new
gz_decoder
(
fp
);
return
make_unique
<
gz_decoder
>
(
std
::
move
(
fp
)
);
}
}
}
}
...
@@ -568,7 +540,7 @@ void decompress(char *infile, const char *outfile) {
...
@@ -568,7 +540,7 @@ void decompress(char *infile, const char *outfile) {
bool
rm_in
=
false
;
bool
rm_in
=
false
;
FILE
*
in_fp
=
in_std
?
stdin
:
xfopen
(
infile
,
"re"
);
FILE
*
in_fp
=
in_std
?
stdin
:
xfopen
(
infile
,
"re"
);
unique_ptr
<
stream
>
strm
;
stream_ptr
strm
;
char
buf
[
4096
];
char
buf
[
4096
];
size_t
len
;
size_t
len
;
...
@@ -601,14 +573,14 @@ void decompress(char *infile, const char *outfile) {
...
@@ -601,14 +573,14 @@ void decompress(char *infile, const char *outfile) {
}
}
FILE
*
out_fp
=
outfile
==
"-"
sv
?
stdout
:
xfopen
(
outfile
,
"we"
);
FILE
*
out_fp
=
outfile
==
"-"
sv
?
stdout
:
xfopen
(
outfile
,
"we"
);
strm
.
reset
(
get_decoder
(
type
,
out_fp
));
strm
=
get_decoder
(
type
,
make_sFILE
(
out_fp
));
if
(
ext
)
*
ext
=
'.'
;
if
(
ext
)
*
ext
=
'.'
;
}
}
if
(
strm
->
write
(
buf
,
len
)
<
0
)
if
(
strm
->
write
(
buf
,
len
)
<
0
)
LOGE
(
"Decompression error!
\n
"
);
LOGE
(
"Decompression error!
\n
"
);
}
}
strm
->
close
(
);
strm
.
reset
(
nullptr
);
fclose
(
in_fp
);
fclose
(
in_fp
);
if
(
rm_in
)
if
(
rm_in
)
...
@@ -642,7 +614,7 @@ void compress(const char *method, const char *infile, const char *outfile) {
...
@@ -642,7 +614,7 @@ void compress(const char *method, const char *infile, const char *outfile) {
out_fp
=
outfile
==
"-"
sv
?
stdout
:
xfopen
(
outfile
,
"we"
);
out_fp
=
outfile
==
"-"
sv
?
stdout
:
xfopen
(
outfile
,
"we"
);
}
}
unique_ptr
<
stream
>
strm
(
get_encoder
(
it
->
second
,
out_fp
));
auto
strm
=
get_encoder
(
it
->
second
,
make_sFILE
(
out_fp
));
char
buf
[
4096
];
char
buf
[
4096
];
size_t
len
;
size_t
len
;
...
@@ -651,7 +623,7 @@ void compress(const char *method, const char *infile, const char *outfile) {
...
@@ -651,7 +623,7 @@ void compress(const char *method, const char *infile, const char *outfile) {
LOGE
(
"Compression error!
\n
"
);
LOGE
(
"Compression error!
\n
"
);
};
};
strm
->
close
(
);
strm
.
reset
(
nullptr
);
fclose
(
in_fp
);
fclose
(
in_fp
);
if
(
rm_in
)
if
(
rm_in
)
...
...
native/jni/magiskboot/compress.h
View file @
78d7c45b
...
@@ -4,7 +4,10 @@
...
@@ -4,7 +4,10 @@
#include "format.h"
#include "format.h"
filter_stream
*
get_encoder
(
format_t
type
,
FILE
*
fp
=
nullptr
);
stream_ptr
get_encoder
(
format_t
type
,
sFILE
&&
fp
);
filter_stream
*
get_decoder
(
format_t
type
,
FILE
*
fp
=
nullptr
);
stream_ptr
get_decoder
(
format_t
type
,
sFILE
&&
fp
);
void
compress
(
const
char
*
method
,
const
char
*
infile
,
const
char
*
outfile
);
void
compress
(
const
char
*
method
,
const
char
*
infile
,
const
char
*
outfile
);
void
decompress
(
char
*
infile
,
const
char
*
outfile
);
void
decompress
(
char
*
infile
,
const
char
*
outfile
);
native/jni/magiskboot/ramdisk.cpp
View file @
78d7c45b
...
@@ -244,8 +244,8 @@ void magisk_cpio::compress() {
...
@@ -244,8 +244,8 @@ void magisk_cpio::compress() {
uint8_t
*
data
;
uint8_t
*
data
;
size_t
len
;
size_t
len
;
FILE
*
fp
=
open_stream
(
get_encoder
(
XZ
,
open
_stream
<
byte_stream
>
(
data
,
len
)));
auto
strm
=
make_stream
(
get_encoder
(
XZ
,
make
_stream
<
byte_stream
>
(
data
,
len
)));
dump
(
fp
);
dump
(
strm
.
release
()
);
entries
.
clear
();
entries
.
clear
();
entries
.
insert
(
std
::
move
(
init
));
entries
.
insert
(
std
::
move
(
init
));
...
@@ -263,9 +263,10 @@ void magisk_cpio::decompress() {
...
@@ -263,9 +263,10 @@ void magisk_cpio::decompress() {
char
*
data
;
char
*
data
;
size_t
len
;
size_t
len
;
auto
strm
=
get_decoder
(
XZ
,
open_stream
<
byte_stream
>
(
data
,
len
));
{
strm
->
write
(
it
->
second
->
data
,
it
->
second
->
filesize
);
auto
strm
=
get_decoder
(
XZ
,
make_stream
<
byte_stream
>
(
data
,
len
));
delete
strm
;
strm
->
write
(
it
->
second
->
data
,
it
->
second
->
filesize
);
}
entries
.
erase
(
it
);
entries
.
erase
(
it
);
load_cpio
(
data
,
len
);
load_cpio
(
data
,
len
);
...
...
native/jni/magiskpolicy/policydb.cpp
View file @
78d7c45b
...
@@ -174,19 +174,20 @@ int compile_split_cil() {
...
@@ -174,19 +174,20 @@ int compile_split_cil() {
}
}
int
dump_policydb
(
const
char
*
file
)
{
int
dump_policydb
(
const
char
*
file
)
{
struct
policy_file
pf
;
policy_file_init
(
&
pf
);
uint8_t
*
data
;
uint8_t
*
data
;
size_t
len
;
size_t
len
;
pf
.
type
=
PF_USE_STDIO
;
{
pf
.
fp
=
open_stream
<
byte_stream
>
(
data
,
len
);
auto
fp
=
make_stream
<
byte_stream
>
(
data
,
len
);
if
(
policydb_write
(
magisk_policydb
,
&
pf
))
{
struct
policy_file
pf
;
LOGE
(
"Fail to create policy image
\n
"
);
policy_file_init
(
&
pf
);
return
1
;
pf
.
type
=
PF_USE_STDIO
;
pf
.
fp
=
fp
.
get
();
if
(
policydb_write
(
magisk_policydb
,
&
pf
))
{
LOGE
(
"Fail to create policy image
\n
"
);
return
1
;
}
}
}
fclose
(
pf
.
fp
);
int
fd
=
xopen
(
file
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
|
O_CLOEXEC
,
0644
);
int
fd
=
xopen
(
file
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
|
O_CLOEXEC
,
0644
);
if
(
fd
<
0
)
if
(
fd
<
0
)
...
...
native/jni/magiskpolicy/rules.cpp
View file @
78d7c45b
...
@@ -196,7 +196,7 @@ void sepol_magisk_rules() {
...
@@ -196,7 +196,7 @@ void sepol_magisk_rules() {
// Allow update_engine/addon.d-v2 to run permissive on all ROMs
// Allow update_engine/addon.d-v2 to run permissive on all ROMs
sepol_permissive
(
"update_engine"
);
sepol_permissive
(
"update_engine"
);
#if
def MAGISK_DEBUG
#if
0
// Remove all dontaudit in debug mode
// Remove all dontaudit in debug mode
strip_dontaudit();
strip_dontaudit();
#endif
#endif
...
...
native/jni/utils/cpio.cpp
View file @
78d7c45b
...
@@ -109,7 +109,7 @@ bool cpio::exists(const char *name) {
...
@@ -109,7 +109,7 @@ bool cpio::exists(const char *name) {
return
entries
.
count
(
name
)
!=
0
;
return
entries
.
count
(
name
)
!=
0
;
}
}
#define do_out(buf, len) pos += fwrite(buf,
len, 1
, out);
#define do_out(buf, len) pos += fwrite(buf,
1, len
, out);
#define out_align() do_out(zeros, align_off(pos, 4))
#define out_align() do_out(zeros, align_off(pos, 4))
void
cpio
::
dump
(
FILE
*
out
)
{
void
cpio
::
dump
(
FILE
*
out
)
{
size_t
pos
=
0
;
size_t
pos
=
0
;
...
@@ -142,7 +142,7 @@ void cpio::dump(FILE *out) {
...
@@ -142,7 +142,7 @@ void cpio::dump(FILE *out) {
}
}
// Write trailer
// Write trailer
sprintf
(
header
,
"070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x"
,
sprintf
(
header
,
"070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x"
,
inode
++
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
11
,
0
);
inode
++
,
0
755
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
11
,
0
);
do_out
(
header
,
110
);
do_out
(
header
,
110
);
do_out
(
"TRAILER!!!
\0
"
,
11
);
do_out
(
"TRAILER!!!
\0
"
,
11
);
out_align
();
out_align
();
...
...
native/jni/utils/files.h
View file @
78d7c45b
#pragma once
#pragma once
#include <mntent.h>
#include <functional>
#include <functional>
#include <string_view>
#include <string_view>
#define do_align(p, a) (((p) + (a) - 1) / (a) * (a))
#define do_align(p, a) (((p) + (a) - 1) / (a) * (a))
#define align_off(p, a) (do_align(p, a) - (p))
#define align_off(p, a) (do_align(p, a) - (p))
using
sFILE
=
std
::
unique_ptr
<
FILE
,
decltype
(
&
fclose
)
>
;
static
inline
sFILE
make_sFILE
(
FILE
*
fp
=
nullptr
)
{
return
sFILE
(
fp
,
fclose
);
}
struct
file_attr
{
struct
file_attr
{
struct
stat
st
;
struct
stat
st
;
char
con
[
128
];
char
con
[
128
];
...
@@ -37,7 +43,7 @@ void parse_prop_file(const char *file, const std::function
...
@@ -37,7 +43,7 @@ void parse_prop_file(const char *file, const std::function
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
,
std
::
initializer_list
<
const
char
*>
excl
=
std
::
initializer_list
<
const
char
*>
());
void
frm_rf
(
int
dirfd
,
std
::
initializer_list
<
const
char
*>
excl
=
std
::
initializer_list
<
const
char
*>
());
void
clone_dir
(
int
src
,
int
dest
,
bool
overwrite
=
true
);
void
clone_dir
(
int
src
,
int
dest
,
bool
overwrite
=
true
);
void
parse_mnt
(
const
char
*
file
,
const
std
::
function
<
bool
(
mntent
*
)
>
&
fn
);
void
parse_mnt
(
const
char
*
file
,
const
std
::
function
<
bool
(
mntent
*
)
>
&
fn
);
template
<
typename
T
>
template
<
typename
T
>
void
full_read
(
const
char
*
filename
,
T
&
buf
,
size_t
&
size
)
{
void
full_read
(
const
char
*
filename
,
T
&
buf
,
size_t
&
size
)
{
...
...
native/jni/utils/include/stream.h
View file @
78d7c45b
#pragma once
#pragma once
#include <unistd.h>
#include <stdio.h>
#include <stdio.h>
#include <memory>
#include <memory>
// #include <utils.h>
#include "../files.h"
class
stream
;
class
stream
;
FILE
*
open_stream
(
stream
*
strm
);
using
stream_ptr
=
std
::
unique_ptr
<
stream
>
;
sFILE
make_stream
(
stream_ptr
&&
strm
);
template
<
class
T
,
class
...
Args
>
template
<
class
T
,
class
...
Args
>
FILE
*
open
_stream
(
Args
&&
...
args
)
{
sFILE
make
_stream
(
Args
&&
...
args
)
{
return
open_stream
(
new
T
(
args
...
));
return
make_stream
(
stream_ptr
(
new
T
(
std
::
forward
<
Args
>
(
args
)...)
));
}
}
class
stream
{
class
stream
{
...
@@ -20,28 +21,25 @@ public:
...
@@ -20,28 +21,25 @@ public:
virtual
int
read
(
void
*
buf
,
size_t
len
);
virtual
int
read
(
void
*
buf
,
size_t
len
);
virtual
int
write
(
const
void
*
buf
,
size_t
len
);
virtual
int
write
(
const
void
*
buf
,
size_t
len
);
virtual
off_t
seek
(
off_t
off
,
int
whence
);
virtual
off_t
seek
(
off_t
off
,
int
whence
);
virtual
int
close
();
virtual
~
stream
()
=
default
;
virtual
~
stream
()
=
default
;
};
};
// Delegates all operations to the base FILE pointer
// Delegates all operations to the base FILE pointer
class
filter_stream
:
public
stream
{
class
filter_stream
:
public
stream
{
public
:
public
:
filter_stream
(
FILE
*
fp
)
:
fp
(
fp
)
{}
filter_stream
(
sFILE
&&
fp
=
make_sFILE
())
:
fp
(
std
::
move
(
fp
))
{}
~
filter_stream
()
override
{
if
(
fp
)
close
();
}
int
read
(
void
*
buf
,
size_t
len
)
override
;
int
read
(
void
*
buf
,
size_t
len
)
override
;
int
write
(
const
void
*
buf
,
size_t
len
)
override
;
int
write
(
const
void
*
buf
,
size_t
len
)
override
;
int
close
()
override
;
void
set_base
(
FILE
*
f
);
void
set_base
(
sFILE
&&
f
);
template
<
class
T
,
class
...
Args
>
template
<
class
T
,
class
...
Args
>
void
set_base
(
Args
&&
...
args
)
{
void
set_base
(
Args
&&
...
args
)
{
set_base
(
open_stream
<
T
>
(
args
...));
set_base
(
make_stream
<
T
>
(
std
::
forward
<
Args
>
(
args
)
...));
}
}
protected
:
protected
:
FILE
*
fp
;
sFILE
fp
;
};
};
// Handy interface for classes that need custom seek logic
// Handy interface for classes that need custom seek logic
...
@@ -69,7 +67,7 @@ private:
...
@@ -69,7 +67,7 @@ private:
size_t
_cap
=
0
;
size_t
_cap
=
0
;
void
resize
(
size_t
new_pos
,
bool
zero
=
false
);
void
resize
(
size_t
new_pos
,
bool
zero
=
false
);
size_t
end_pos
()
override
{
return
_len
;
}
size_t
end_pos
()
final
{
return
_len
;
}
};
};
// File stream but does not close the file descriptor at any time
// File stream but does not close the file descriptor at any time
...
...
native/jni/utils/stream.cpp
View file @
78d7c45b
...
@@ -19,15 +19,13 @@ static fpos_t strm_seek(void *v, fpos_t off, int whence) {
...
@@ -19,15 +19,13 @@ static fpos_t strm_seek(void *v, fpos_t off, int whence) {
static
int
strm_close
(
void
*
v
)
{
static
int
strm_close
(
void
*
v
)
{
auto
strm
=
reinterpret_cast
<
stream
*>
(
v
);
auto
strm
=
reinterpret_cast
<
stream
*>
(
v
);
int
ret
=
strm
->
close
();
delete
strm
;
delete
strm
;
return
ret
;
return
0
;
}
}
FILE
*
open_stream
(
stream
*
strm
)
{
sFILE
make_stream
(
stream_ptr
&&
strm
)
{
FILE
*
fp
=
funopen
(
strm
,
strm_read
,
strm_write
,
strm_seek
,
strm_close
);
sFILE
fp
(
funopen
(
strm
.
release
(),
strm_read
,
strm_write
,
strm_seek
,
strm_close
),
fclose
);
// Disable buffering
setbuf
(
fp
.
get
(),
nullptr
);
setbuf
(
fp
,
nullptr
);
return
fp
;
return
fp
;
}
}
...
@@ -46,27 +44,16 @@ off_t stream::seek(off_t off, int whence) {
...
@@ -46,27 +44,16 @@ off_t stream::seek(off_t off, int whence) {
return
-
1
;
return
-
1
;
}
}
int
stream
::
close
()
{
return
0
;
}
int
filter_stream
::
read
(
void
*
buf
,
size_t
len
)
{
int
filter_stream
::
read
(
void
*
buf
,
size_t
len
)
{
return
fread
(
buf
,
len
,
1
,
fp
);
return
fread
(
buf
,
1
,
len
,
fp
.
get
()
);
}
}
int
filter_stream
::
write
(
const
void
*
buf
,
size_t
len
)
{
int
filter_stream
::
write
(
const
void
*
buf
,
size_t
len
)
{
return
fwrite
(
buf
,
len
,
1
,
fp
);
return
fwrite
(
buf
,
1
,
len
,
fp
.
get
());
}
int
filter_stream
::
close
()
{
int
ret
=
fclose
(
fp
);
fp
=
nullptr
;
return
ret
;
}
}
void
filter_stream
::
set_base
(
FILE
*
f
)
{
void
filter_stream
::
set_base
(
sFILE
&&
f
)
{
if
(
fp
)
fclose
(
fp
);
fp
=
std
::
move
(
f
);
fp
=
f
;
}
}
off_t
seekable_stream
::
seek_pos
(
off_t
off
,
int
whence
)
{
off_t
seekable_stream
::
seek_pos
(
off_t
off
,
int
whence
)
{
...
...
shared/src/main/java/com/topjohnwu/magisk/FileProvider.java
View file @
78d7c45b
...
@@ -154,7 +154,7 @@ public class FileProvider extends ContentProvider {
...
@@ -154,7 +154,7 @@ public class FileProvider extends ContentProvider {
public
Bundle
call
(
String
method
,
String
arg
,
Bundle
extras
)
{
public
Bundle
call
(
String
method
,
String
arg
,
Bundle
extras
)
{
if
(
callHandler
!=
null
)
if
(
callHandler
!=
null
)
return
callHandler
.
call
(
getContext
(),
method
,
arg
,
extras
);
return
callHandler
.
call
(
getContext
(),
method
,
arg
,
extras
);
return
null
;
return
Bundle
.
EMPTY
;
}
}
@Override
@Override
...
...
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