mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-11 21:42:14 +00:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78f7fa348e | ||
|
|
d8c448b99d | ||
|
|
d4b83b6a44 | ||
|
|
e5d36d1d24 | ||
|
|
ff18cb8e70 | ||
|
|
37a9724a54 | ||
|
|
d660401063 | ||
|
|
88541d6f49 | ||
|
|
ecd6129fe5 | ||
|
|
6dfe9df9e2 | ||
|
|
e81de7ec36 | ||
|
|
c78da1ce24 | ||
|
|
7b2d40987c | ||
|
|
3a37e8c9c5 | ||
|
|
58b405bce1 | ||
|
|
810174ef73 | ||
|
|
690a5ac033 | ||
|
|
89aad31f7e | ||
|
|
7124db98e3 | ||
|
|
0860e859f7 | ||
|
|
04008949b8 | ||
|
|
39f2940bd1 | ||
|
|
1460317ebd | ||
|
|
12340c9bd5 | ||
|
|
c4590fe2ba | ||
|
|
b36066bbcd | ||
|
|
65d1c5827c | ||
|
|
1d675c8b2e | ||
|
|
0b494ed7df | ||
|
|
48d9fc24eb | ||
|
|
83426f7f36 | ||
|
|
0e86d4dbcb | ||
|
|
5e050d7456 | ||
|
|
898580bf90 | ||
|
|
86621a4c46 | ||
|
|
a834e72b71 | ||
|
|
d8cf42af16 | ||
|
|
8c79d66b7b | ||
|
|
fada8b148a | ||
|
|
dc0acea47c | ||
|
|
78d1200608 | ||
|
|
527bbc0368 | ||
|
|
4c89c7e2b3 | ||
|
|
adbea7e313 | ||
|
|
76962f965e | ||
|
|
a4b8c5e46b | ||
|
|
83c707439c | ||
|
|
25dd6121f4 | ||
|
|
67f35ad027 | ||
|
|
0c4b8afbc5 | ||
|
|
34b30d7ce1 | ||
|
|
2215088973 | ||
|
|
8b7fb6cdde | ||
|
|
94c7dbedf2 | ||
|
|
b1dc47a047 |
2
.github/actions/setup/action.yml
vendored
2
.github/actions/setup/action.yml
vendored
@@ -70,7 +70,7 @@ runs:
|
|||||||
.gradle/caches
|
.gradle/caches
|
||||||
.gradle/wrapper
|
.gradle/wrapper
|
||||||
!.gradle/caches/build-cache-*
|
!.gradle/caches/build-cache-*
|
||||||
key: gradle-cache-${{ hashFiles('gradle/**') }}
|
key: gradle-cache-${{ hashFiles('app/gradle/**') }}
|
||||||
restore-keys: gradle-cache-
|
restore-keys: gradle-cache-
|
||||||
|
|
||||||
- name: Restore Gradle dependencies
|
- name: Restore Gradle dependencies
|
||||||
|
|||||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -110,7 +110,7 @@ jobs:
|
|||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
env:
|
env:
|
||||||
AVD_TEST_LOG: 1
|
AVD_TEST_LOG: 1
|
||||||
run: scripts/avd_test.sh ${{ matrix.version }} ${{ matrix.type }}
|
run: scripts/avd.sh test ${{ matrix.version }} ${{ matrix.type }}
|
||||||
|
|
||||||
- name: Upload logs on error
|
- name: Upload logs on error
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
@@ -152,7 +152,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
FORCE_32_BIT: 1
|
FORCE_32_BIT: 1
|
||||||
AVD_TEST_LOG: 1
|
AVD_TEST_LOG: 1
|
||||||
run: scripts/avd_test.sh ${{ matrix.version }}
|
run: scripts/avd.sh test ${{ matrix.version }}
|
||||||
|
|
||||||
- name: Upload logs on error
|
- name: Upload logs on error
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -10,9 +10,6 @@
|
|||||||
[submodule "libcxx"]
|
[submodule "libcxx"]
|
||||||
path = native/src/external/libcxx
|
path = native/src/external/libcxx
|
||||||
url = https://github.com/topjohnwu/libcxx.git
|
url = https://github.com/topjohnwu/libcxx.git
|
||||||
[submodule "zopfli"]
|
|
||||||
path = native/src/external/zopfli
|
|
||||||
url = https://github.com/google/zopfli.git
|
|
||||||
[submodule "cxx-rs"]
|
[submodule "cxx-rs"]
|
||||||
path = native/src/external/cxx-rs
|
path = native/src/external/cxx-rs
|
||||||
url = https://github.com/topjohnwu/cxx.git
|
url = https://github.com/topjohnwu/cxx.git
|
||||||
|
|||||||
@@ -16,13 +16,7 @@ Some highlight features:
|
|||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
|
|
||||||
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
|
[Github](https://github.com/topjohnwu/Magisk/releases) is the only source where you can get official Magisk information and downloads.
|
||||||
|
|
||||||
Click the icon below to download Magisk apk.
|
|
||||||
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v29.0)
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/canary-28104)
|
|
||||||
|
|
||||||
## Useful Links
|
## Useful Links
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import androidx.core.widget.ImageViewCompat
|
|||||||
import androidx.databinding.BindingAdapter
|
import androidx.databinding.BindingAdapter
|
||||||
import androidx.databinding.InverseBindingAdapter
|
import androidx.databinding.InverseBindingAdapter
|
||||||
import androidx.databinding.InverseBindingListener
|
import androidx.databinding.InverseBindingListener
|
||||||
|
import androidx.databinding.InverseMethod
|
||||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
@@ -33,9 +34,11 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
|||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.slider.Slider
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||||
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.utils.TextHolder
|
import com.topjohnwu.magisk.utils.TextHolder
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
import com.topjohnwu.widget.IndeterminateCheckBox
|
import com.topjohnwu.widget.IndeterminateCheckBox
|
||||||
@@ -306,3 +309,38 @@ fun TextView.setText(text: TextHolder) {
|
|||||||
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
|
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
|
||||||
adapter = ArrayAdapter(context, layoutRes, items)
|
adapter = ArrayAdapter(context, layoutRes, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("labelFormatter")
|
||||||
|
fun Slider.setLabelFormatter(formatter: (Float) -> Int) {
|
||||||
|
setLabelFormatter { value -> resources.getString(formatter(value)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseBindingAdapter(attribute = "android:value")
|
||||||
|
fun Slider.getValueBinding() = value
|
||||||
|
|
||||||
|
@BindingAdapter("android:valueAttrChanged")
|
||||||
|
fun Slider.setListener(attrChange: InverseBindingListener) {
|
||||||
|
addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||||
|
override fun onStartTrackingTouch(slider: Slider) = Unit
|
||||||
|
override fun onStopTrackingTouch(slider: Slider) = attrChange.onChange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseMethod("sliderValueToPolicy")
|
||||||
|
fun policyToSliderValue(policy: Int): Float {
|
||||||
|
return when (policy) {
|
||||||
|
SuPolicy.DENY -> 1f
|
||||||
|
SuPolicy.RESTRICT -> 2f
|
||||||
|
SuPolicy.ALLOW -> 3f
|
||||||
|
else -> 1f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sliderValueToPolicy(value: Float): Int {
|
||||||
|
return when (value) {
|
||||||
|
1f -> SuPolicy.DENY
|
||||||
|
2f -> SuPolicy.RESTRICT
|
||||||
|
3f -> SuPolicy.ALLOW
|
||||||
|
else -> SuPolicy.DENY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.dialog
|
|||||||
import com.topjohnwu.magisk.core.AppContext
|
import com.topjohnwu.magisk.core.AppContext
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.R
|
import com.topjohnwu.magisk.core.R
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
@@ -11,15 +10,10 @@ import java.io.File
|
|||||||
|
|
||||||
class ManagerInstallDialog : MarkDownDialog() {
|
class ManagerInstallDialog : MarkDownDialog() {
|
||||||
|
|
||||||
private val svc get() = ServiceLocator.networkService
|
|
||||||
|
|
||||||
override suspend fun getMarkdownText(): String {
|
override suspend fun getMarkdownText(): String {
|
||||||
val text = svc.fetchString(Info.remote.magisk.note)
|
val text = Info.update.note
|
||||||
// Cache the changelog
|
// Cache the changelog
|
||||||
AppContext.cacheDir.listFiles { _, name -> name.endsWith(".md") }.orEmpty().forEach {
|
File(AppContext.cacheDir, "${Info.update.versionCode}.md").writeText(text)
|
||||||
it.delete()
|
|
||||||
}
|
|
||||||
File(AppContext.cacheDir, "${Info.remote.magisk.versionCode}.md").writeText(text)
|
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,16 +91,15 @@ class HomeViewModel(
|
|||||||
|
|
||||||
override suspend fun doLoadWork() {
|
override suspend fun doLoadWork() {
|
||||||
appState = State.LOADING
|
appState = State.LOADING
|
||||||
Info.getRemote(svc)?.apply {
|
Info.fetchUpdate(svc)?.apply {
|
||||||
appState = when {
|
appState = when {
|
||||||
BuildConfig.APP_VERSION_CODE < magisk.versionCode -> State.OUTDATED
|
BuildConfig.APP_VERSION_CODE < versionCode -> State.OUTDATED
|
||||||
else -> State.UP_TO_DATE
|
else -> State.UP_TO_DATE
|
||||||
}
|
}
|
||||||
|
|
||||||
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
|
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
|
||||||
managerRemoteVersion =
|
managerRemoteVersion =
|
||||||
("${magisk.version} (${magisk.versionCode})" +
|
("$version (${versionCode})" + if (isDebug) " (D)" else "").asText()
|
||||||
if (isDebug) " (D)" else "").asText()
|
|
||||||
} ?: run {
|
} ?: run {
|
||||||
appState = State.INVALID
|
appState = State.INVALID
|
||||||
managerRemoteVersion = CoreR.string.not_available.asText()
|
managerRemoteVersion = CoreR.string.not_available.asText()
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import com.topjohnwu.magisk.BR
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
import com.topjohnwu.magisk.core.AppContext
|
import com.topjohnwu.magisk.core.AppContext
|
||||||
import com.topjohnwu.magisk.core.BuildConfig
|
import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
@@ -70,17 +69,16 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md")
|
val noteFile = File(AppContext.cacheDir, "${APP_VERSION_CODE}.md")
|
||||||
val text = when {
|
val noteText = when {
|
||||||
file.exists() -> file.readText()
|
noteFile.exists() -> noteFile.readText()
|
||||||
Const.Url.CHANGELOG_URL.isEmpty() -> ""
|
|
||||||
else -> {
|
else -> {
|
||||||
val str = svc.fetchString(Const.Url.CHANGELOG_URL)
|
val note = svc.fetchUpdate(APP_VERSION_CODE).note
|
||||||
file.writeText(str)
|
noteFile.writeText(note)
|
||||||
str
|
note
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val spanned = markwon.toMarkdown(text)
|
val spanned = markwon.toMarkdown(noteText)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
notes = spanned
|
notes = spanned
|
||||||
}
|
}
|
||||||
@@ -100,13 +98,15 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveState(state: Bundle) {
|
override fun onSaveState(state: Bundle) {
|
||||||
state.putParcelable(INSTALL_STATE_KEY, InstallState(
|
state.putParcelable(
|
||||||
methodId,
|
INSTALL_STATE_KEY, InstallState(
|
||||||
step,
|
methodId,
|
||||||
Config.keepVerity,
|
step,
|
||||||
Config.keepEnc,
|
Config.keepVerity,
|
||||||
Config.recovery
|
Config.keepEnc,
|
||||||
))
|
Config.recovery
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRestoreState(state: Bundle) {
|
override fun onRestoreState(state: Bundle) {
|
||||||
@@ -124,6 +124,7 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
override fun onActivityLaunch() {
|
override fun onActivityLaunch() {
|
||||||
AppContext.toast(CoreR.string.patch_file_msg, Toast.LENGTH_LONG)
|
AppContext.toast(CoreR.string.patch_file_msg, Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(result: Uri) {
|
override fun onActivityResult(result: Uri) {
|
||||||
uri.value = result
|
uri.value = result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,19 +147,11 @@ object UpdateChannel : BaseSettingsItem.Selector() {
|
|||||||
get() = Config.updateChannel
|
get() = Config.updateChannel
|
||||||
set(value) {
|
set(value) {
|
||||||
Config.updateChannel = value
|
Config.updateChannel = value
|
||||||
Info.remote = Info.EMPTY_REMOTE
|
Info.resetUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val title = CoreR.string.settings_update_channel_title.asText()
|
override val title = CoreR.string.settings_update_channel_title.asText()
|
||||||
|
|
||||||
override val entryRes = CoreR.array.update_channel
|
override val entryRes = CoreR.array.update_channel
|
||||||
override fun entries(res: Resources): Array<String> {
|
|
||||||
return super.entries(res).let {
|
|
||||||
if (!Const.APP_IS_CANARY && !BuildConfig.DEBUG)
|
|
||||||
it.copyOfRange(0, Config.Value.CANARY_CHANNEL)
|
|
||||||
else it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object UpdateChannelUrl : BaseSettingsItem.Input() {
|
object UpdateChannelUrl : BaseSettingsItem.Input() {
|
||||||
@@ -169,7 +161,7 @@ object UpdateChannelUrl : BaseSettingsItem.Input() {
|
|||||||
get() = Config.customChannelUrl
|
get() = Config.customChannelUrl
|
||||||
set(value) {
|
set(value) {
|
||||||
Config.customChannelUrl = value
|
Config.customChannelUrl = value
|
||||||
Info.remote = Info.EMPTY_REMOTE
|
Info.resetUpdate()
|
||||||
notifyPropertyChanged(BR.description)
|
notifyPropertyChanged(BR.description)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,6 +322,12 @@ object Reauthenticate : BaseSettingsItem.Toggle() {
|
|||||||
override var value by Config::suReAuth
|
override var value by Config::suReAuth
|
||||||
|
|
||||||
override fun refresh() {
|
override fun refresh() {
|
||||||
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Info.showSuperUser
|
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Restrict : BaseSettingsItem.Toggle() {
|
||||||
|
override val title = CoreR.string.settings_su_restrict_title.asText()
|
||||||
|
override val description = CoreR.string.settings_su_restrict_summary.asText()
|
||||||
|
override var value by Config::suRestrict
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
// Can hide overlay windows on 12.0+
|
// Can hide overlay windows on 12.0+
|
||||||
list.remove(Tapjack)
|
list.remove(Tapjack)
|
||||||
}
|
}
|
||||||
|
if (Const.Version.atLeast_30_1()) {
|
||||||
|
list.add(Restrict)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list
|
return list
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import android.graphics.drawable.Drawable
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.databinding.DiffItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.ItemWrapper
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class PolicyRvItem(
|
class PolicyRvItem(
|
||||||
private val viewModel: SuperuserViewModel,
|
private val viewModel: SuperuserViewModel,
|
||||||
@@ -33,14 +35,34 @@ class PolicyRvItem(
|
|||||||
var isExpanded = false
|
var isExpanded = false
|
||||||
set(value) = set(value, field, { field = it }, BR.expanded)
|
set(value) = set(value, field, { field = it }, BR.expanded)
|
||||||
|
|
||||||
|
val showSlider = Config.suRestrict || item.policy == SuPolicy.RESTRICT
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var isEnabled
|
var isEnabled
|
||||||
get() = item.policy == SuPolicy.ALLOW
|
get() = item.policy >= SuPolicy.ALLOW
|
||||||
set(value) = setImpl(value, isEnabled) {
|
set(value) = setImpl(value, isEnabled) {
|
||||||
notifyPropertyChanged(BR.enabled)
|
notifyPropertyChanged(BR.enabled)
|
||||||
viewModel.togglePolicy(this, value)
|
viewModel.updatePolicy(this, if (it) SuPolicy.ALLOW else SuPolicy.DENY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@get:Bindable
|
||||||
|
var sliderValue
|
||||||
|
get() = item.policy
|
||||||
|
set(value) = setImpl(value, sliderValue) {
|
||||||
|
notifyPropertyChanged(BR.sliderValue)
|
||||||
|
notifyPropertyChanged(BR.enabled)
|
||||||
|
viewModel.updatePolicy(this, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sliderValueToPolicyString: (Float) -> Int = { value ->
|
||||||
|
when (value.toInt()) {
|
||||||
|
1 -> CoreR.string.deny
|
||||||
|
2 -> CoreR.string.restrict
|
||||||
|
3 -> CoreR.string.grant
|
||||||
|
else -> CoreR.string.deny
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var shouldNotify
|
var shouldNotify
|
||||||
get() = item.notification
|
get() = item.notification
|
||||||
|
|||||||
@@ -156,15 +156,16 @@ class SuperuserViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun togglePolicy(item: PolicyRvItem, enable: Boolean) {
|
fun updatePolicy(item: PolicyRvItem, policy: Int) {
|
||||||
val items = itemsPolicies.filter { it.item.uid == item.item.uid }
|
val items = itemsPolicies.filter { it.item.uid == item.item.uid }
|
||||||
fun updateState() {
|
fun updateState() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val res = if (enable) R.string.su_snack_grant else R.string.su_snack_deny
|
val res = if (policy >= SuPolicy.ALLOW) R.string.su_snack_grant else R.string.su_snack_deny
|
||||||
item.item.policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY
|
item.item.policy = policy
|
||||||
db.update(item.item)
|
db.update(item.item)
|
||||||
items.forEach {
|
items.forEach {
|
||||||
it.notifyPropertyChanged(BR.enabled)
|
it.notifyPropertyChanged(BR.enabled)
|
||||||
|
it.notifyPropertyChanged(BR.sliderValue)
|
||||||
}
|
}
|
||||||
SnackbarEvent(res.asText(item.appName)).publish()
|
SnackbarEvent(res.asText(item.appName)).publish()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/log_track_container"
|
android:id="@+id/log_track_container"
|
||||||
bullet="@{item.log.action == 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
|
bullet="@{item.log.action >= 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
|
||||||
isBottom="@{item.isBottom}"
|
isBottom="@{item.isBottom}"
|
||||||
isSelected="@{item.log.action != 2}"
|
isSelected="@{item.log.action != 2}"
|
||||||
isTop="@{item.isTop}"
|
isTop="@{item.isTop}"
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
|
<import type="com.topjohnwu.magisk.databinding.DataBindingAdaptersKt" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="item"
|
name="item"
|
||||||
type="com.topjohnwu.magisk.ui.superuser.PolicyRvItem" />
|
type="com.topjohnwu.magisk.ui.superuser.PolicyRvItem" />
|
||||||
@@ -85,16 +87,32 @@
|
|||||||
app:layout_constraintVertical_bias="0"
|
app:layout_constraintVertical_bias="0"
|
||||||
tools:text="com.topjohnwu.magisk" />
|
tools:text="com.topjohnwu.magisk" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<FrameLayout
|
||||||
android:id="@+id/policy_indicator"
|
android:id="@+id/policy_indicator"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="@dimen/l1"
|
android:layout_marginEnd="@dimen/l1"
|
||||||
android:checked="@={item.enabled}"
|
|
||||||
android:nextFocusLeft="@id/policy"
|
android:nextFocusLeft="@id/policy"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
gone="@{item.showSlider}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="@={item.enabled}" />
|
||||||
|
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
goneUnless="@{item.showSlider}"
|
||||||
|
labelFormatter="@{item.sliderValueToPolicyString}"
|
||||||
|
android:layout_width="96dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:stepSize="1"
|
||||||
|
android:value="@={DataBindingAdaptersKt.policyToSliderValue(item.sliderValue)}"
|
||||||
|
android:valueFrom="1"
|
||||||
|
android:valueTo="3" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -30,5 +30,6 @@ dependencies {
|
|||||||
implementation(libs.ksp.plugin)
|
implementation(libs.ksp.plugin)
|
||||||
implementation(libs.navigation.safe.args.plugin)
|
implementation(libs.navigation.safe.args.plugin)
|
||||||
implementation(libs.lsparanoid.plugin)
|
implementation(libs.lsparanoid.plugin)
|
||||||
|
implementation(libs.moshi.plugin)
|
||||||
implementation(libs.jgit)
|
implementation(libs.jgit)
|
||||||
}
|
}
|
||||||
|
|||||||
77
app/buildSrc/src/main/java/AddCommentTask.kt
Normal file
77
app/buildSrc/src/main/java/AddCommentTask.kt
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import com.android.build.api.artifact.ArtifactTransformationRequest
|
||||||
|
import com.android.build.api.dsl.ApkSigningConfig
|
||||||
|
import com.android.builder.internal.packaging.IncrementalPackager
|
||||||
|
import com.android.tools.build.apkzlib.sign.SigningExtension
|
||||||
|
import com.android.tools.build.apkzlib.sign.SigningOptions
|
||||||
|
import com.android.tools.build.apkzlib.zfile.ZFiles
|
||||||
|
import com.android.tools.build.apkzlib.zip.ZFileOptions
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
|
import org.gradle.api.provider.Property
|
||||||
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.gradle.api.tasks.InputFiles
|
||||||
|
import org.gradle.api.tasks.Internal
|
||||||
|
import org.gradle.api.tasks.OutputDirectory
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import java.io.File
|
||||||
|
import java.security.KeyStore
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import java.util.jar.JarFile
|
||||||
|
|
||||||
|
abstract class AddCommentTask: DefaultTask() {
|
||||||
|
@get:Input
|
||||||
|
abstract val comment: Property<String>
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
abstract val signingConfig: Property<ApkSigningConfig>
|
||||||
|
|
||||||
|
@get:InputFiles
|
||||||
|
abstract val apkFolder: DirectoryProperty
|
||||||
|
|
||||||
|
@get:OutputDirectory
|
||||||
|
abstract val outFolder: DirectoryProperty
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
|
abstract val transformationRequest: Property<ArtifactTransformationRequest<AddCommentTask>>
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun taskAction() = transformationRequest.get().submit(this) { artifact ->
|
||||||
|
val inFile = File(artifact.outputFile)
|
||||||
|
val outFile = outFolder.file(inFile.name).get().asFile
|
||||||
|
|
||||||
|
val privateKey = signingConfig.get().getPrivateKey()
|
||||||
|
val signingOptions = SigningOptions.builder()
|
||||||
|
.setMinSdkVersion(0)
|
||||||
|
.setV1SigningEnabled(true)
|
||||||
|
.setV2SigningEnabled(true)
|
||||||
|
.setKey(privateKey.privateKey)
|
||||||
|
.setCertificates(privateKey.certificate as X509Certificate)
|
||||||
|
.setValidation(SigningOptions.Validation.ASSUME_INVALID)
|
||||||
|
.build()
|
||||||
|
val options = ZFileOptions().apply {
|
||||||
|
noTimestamps = true
|
||||||
|
autoSortFiles = true
|
||||||
|
}
|
||||||
|
outFile.parentFile?.mkdirs()
|
||||||
|
inFile.copyTo(outFile, overwrite = true)
|
||||||
|
ZFiles.apk(outFile, options).use {
|
||||||
|
SigningExtension(signingOptions).register(it)
|
||||||
|
it.eocdComment = comment.get().toByteArray()
|
||||||
|
it.get(IncrementalPackager.APP_METADATA_ENTRY_PATH)?.delete()
|
||||||
|
it.get(IncrementalPackager.VERSION_CONTROL_INFO_ENTRY_PATH)?.delete()
|
||||||
|
it.get(JarFile.MANIFEST_NAME)?.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ApkSigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
|
||||||
|
val keyStore = KeyStore.getInstance(storeType ?: KeyStore.getDefaultType())
|
||||||
|
storeFile!!.inputStream().use {
|
||||||
|
keyStore.load(it, storePassword!!.toCharArray())
|
||||||
|
}
|
||||||
|
val keyPwdArray = keyPassword!!.toCharArray()
|
||||||
|
val entry = keyStore.getEntry(keyAlias!!, KeyStore.PasswordProtection(keyPwdArray))
|
||||||
|
return entry as KeyStore.PrivateKeyEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,12 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.kotlin.dsl.provideDelegate
|
import org.gradle.kotlin.dsl.provideDelegate
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
import java.util.Random
|
||||||
|
|
||||||
|
// Set non-zero value here to fix the random seed for reproducible builds
|
||||||
|
// CI builds are always reproducible
|
||||||
|
val RAND_SEED = if (System.getenv("CI") != null) 42 else 0
|
||||||
|
lateinit var RANDOM: Random
|
||||||
|
|
||||||
private val props = Properties()
|
private val props = Properties()
|
||||||
private var commitHash = ""
|
private var commitHash = ""
|
||||||
@@ -28,7 +34,11 @@ object Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val Project.baseDir: File get() = rootProject.file("..")
|
fun Project.rootFile(path: String): File {
|
||||||
|
val file = File(path)
|
||||||
|
return if (file.isAbsolute) file
|
||||||
|
else File(rootProject.file(".."), path)
|
||||||
|
}
|
||||||
|
|
||||||
class MagiskPlugin : Plugin<Project> {
|
class MagiskPlugin : Plugin<Project> {
|
||||||
override fun apply(project: Project) = project.applyPlugin()
|
override fun apply(project: Project) = project.applyPlugin()
|
||||||
@@ -38,11 +48,11 @@ class MagiskPlugin : Plugin<Project> {
|
|||||||
props.clear()
|
props.clear()
|
||||||
rootProject.file("gradle.properties").inputStream().use { props.load(it) }
|
rootProject.file("gradle.properties").inputStream().use { props.load(it) }
|
||||||
val configPath: String? by this
|
val configPath: String? by this
|
||||||
val config = configPath?.let { File(it) } ?: File(baseDir, "config.prop")
|
val config = rootFile(configPath ?: "config.prop")
|
||||||
if (config.exists())
|
if (config.exists())
|
||||||
config.inputStream().use { props.load(it) }
|
config.inputStream().use { props.load(it) }
|
||||||
|
|
||||||
val repo = FileRepository(File(baseDir, ".git"))
|
val repo = FileRepository(rootFile(".git"))
|
||||||
val refId = repo.refDatabase.exactRef("HEAD").objectId
|
val refId = repo.refDatabase.exactRef("HEAD").objectId
|
||||||
commitHash = repo.newObjectReader().abbreviate(refId, 8).name()
|
commitHash = repo.newObjectReader().abbreviate(refId, 8).name()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,18 @@
|
|||||||
import com.android.build.api.artifact.ArtifactTransformationRequest
|
|
||||||
import com.android.build.api.artifact.SingleArtifact
|
import com.android.build.api.artifact.SingleArtifact
|
||||||
import com.android.build.api.dsl.ApkSigningConfig
|
|
||||||
import com.android.build.api.instrumentation.FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
|
import com.android.build.api.instrumentation.FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
|
||||||
import com.android.build.api.instrumentation.InstrumentationScope
|
import com.android.build.api.instrumentation.InstrumentationScope
|
||||||
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||||
import com.android.build.gradle.BaseExtension
|
import com.android.build.gradle.BaseExtension
|
||||||
import com.android.build.gradle.LibraryExtension
|
import com.android.build.gradle.LibraryExtension
|
||||||
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
|
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
|
||||||
import com.android.builder.internal.packaging.IncrementalPackager
|
|
||||||
import com.android.tools.build.apkzlib.sign.SigningExtension
|
|
||||||
import com.android.tools.build.apkzlib.sign.SigningOptions
|
|
||||||
import com.android.tools.build.apkzlib.zfile.ZFiles
|
|
||||||
import com.android.tools.build.apkzlib.zip.ZFileOptions
|
|
||||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||||
import org.gradle.api.Action
|
import org.gradle.api.Action
|
||||||
import org.gradle.api.DefaultTask
|
|
||||||
import org.gradle.api.JavaVersion
|
import org.gradle.api.JavaVersion
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.file.DirectoryProperty
|
|
||||||
import org.gradle.api.provider.Property
|
|
||||||
import org.gradle.api.tasks.Copy
|
import org.gradle.api.tasks.Copy
|
||||||
import org.gradle.api.tasks.Delete
|
import org.gradle.api.tasks.Delete
|
||||||
import org.gradle.api.tasks.Input
|
|
||||||
import org.gradle.api.tasks.InputFiles
|
|
||||||
import org.gradle.api.tasks.Internal
|
|
||||||
import org.gradle.api.tasks.OutputDirectory
|
|
||||||
import org.gradle.api.tasks.StopExecutionException
|
import org.gradle.api.tasks.StopExecutionException
|
||||||
import org.gradle.api.tasks.Sync
|
import org.gradle.api.tasks.Sync
|
||||||
import org.gradle.api.tasks.TaskAction
|
|
||||||
import org.gradle.kotlin.dsl.assign
|
import org.gradle.kotlin.dsl.assign
|
||||||
import org.gradle.kotlin.dsl.exclude
|
import org.gradle.kotlin.dsl.exclude
|
||||||
import org.gradle.kotlin.dsl.filter
|
import org.gradle.kotlin.dsl.filter
|
||||||
@@ -36,18 +21,14 @@ import org.gradle.kotlin.dsl.getValue
|
|||||||
import org.gradle.kotlin.dsl.named
|
import org.gradle.kotlin.dsl.named
|
||||||
import org.gradle.kotlin.dsl.provideDelegate
|
import org.gradle.kotlin.dsl.provideDelegate
|
||||||
import org.gradle.kotlin.dsl.register
|
import org.gradle.kotlin.dsl.register
|
||||||
import org.gradle.kotlin.dsl.registering
|
|
||||||
import org.gradle.kotlin.dsl.withType
|
import org.gradle.kotlin.dsl.withType
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.security.KeyStore
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
import java.util.HexFormat
|
import java.util.HexFormat
|
||||||
import java.util.jar.JarFile
|
|
||||||
import java.util.zip.Deflater
|
import java.util.zip.Deflater
|
||||||
import java.util.zip.DeflaterOutputStream
|
import java.util.zip.DeflaterOutputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
@@ -60,13 +41,13 @@ private fun Project.androidBase(configure: Action<BaseExtension>) =
|
|||||||
private fun Project.android(configure: Action<BaseAppModuleExtension>) =
|
private fun Project.android(configure: Action<BaseAppModuleExtension>) =
|
||||||
extensions.configure("android", configure)
|
extensions.configure("android", configure)
|
||||||
|
|
||||||
private val Project.androidApp: BaseAppModuleExtension
|
internal val Project.androidApp: BaseAppModuleExtension
|
||||||
get() = extensions["android"] as BaseAppModuleExtension
|
get() = extensions["android"] as BaseAppModuleExtension
|
||||||
|
|
||||||
private val Project.androidLib: LibraryExtension
|
private val Project.androidLib: LibraryExtension
|
||||||
get() = extensions["android"] as LibraryExtension
|
get() = extensions["android"] as LibraryExtension
|
||||||
|
|
||||||
private val Project.androidComponents
|
internal val Project.androidComponents
|
||||||
get() = extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
|
get() = extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
|
||||||
|
|
||||||
fun Project.setupCommon() {
|
fun Project.setupCommon() {
|
||||||
@@ -74,7 +55,7 @@ fun Project.setupCommon() {
|
|||||||
compileSdkVersion(36)
|
compileSdkVersion(36)
|
||||||
buildToolsVersion = "36.0.0"
|
buildToolsVersion = "36.0.0"
|
||||||
ndkPath = "$sdkDirectory/ndk/magisk"
|
ndkPath = "$sdkDirectory/ndk/magisk"
|
||||||
ndkVersion = "29.0.13113456"
|
ndkVersion = "28.1.13356709"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 23
|
minSdk = 23
|
||||||
@@ -145,46 +126,42 @@ const val BUSYBOX_ZIP_CHECKSUM =
|
|||||||
fun Project.setupCoreLib() {
|
fun Project.setupCoreLib() {
|
||||||
setupCommon()
|
setupCommon()
|
||||||
|
|
||||||
val abiList = Config.abiList
|
androidLib.libraryVariants.all {
|
||||||
|
val variant = name
|
||||||
|
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
||||||
|
val abiList = Config.abiList
|
||||||
|
|
||||||
val syncLibs by tasks.registering(Sync::class) {
|
val syncLibs = tasks.register("sync${variantCapped}JniLibs", Sync::class) {
|
||||||
into("src/main/jniLibs")
|
into("src/$variant/jniLibs")
|
||||||
for (abi in abiList) {
|
for (abi in abiList) {
|
||||||
into(abi) {
|
into(abi) {
|
||||||
from(File(baseDir, "native/out/$abi")) {
|
from(rootFile("native/out/$abi")) {
|
||||||
include("magiskboot", "magiskinit", "magiskpolicy", "magisk", "libinit-ld.so")
|
include("magiskboot", "magiskinit", "magiskpolicy", "magisk", "libinit-ld.so")
|
||||||
rename { if (it.endsWith(".so")) it else "lib$it.so" }
|
rename { if (it.endsWith(".so")) it else "lib$it.so" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
from(zipTree(downloadFile(BUSYBOX_DOWNLOAD_URL, BUSYBOX_ZIP_CHECKSUM)))
|
||||||
|
include(abiList.map { "$it/libbusybox.so" })
|
||||||
|
onlyIf {
|
||||||
|
if (inputs.sourceFiles.files.size != abiList.size * 6)
|
||||||
|
throw StopExecutionException("Please build binaries first! (./build.py binary)")
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onlyIf {
|
|
||||||
if (inputs.sourceFiles.files.size != abiList.size * 5)
|
tasks.getByPath("merge${variantCapped}JniLibFolders").dependsOn(syncLibs)
|
||||||
throw StopExecutionException("Please build binaries first! (./build.py binary)")
|
|
||||||
true
|
val syncResources = tasks.register("sync${variantCapped}Resources", Sync::class) {
|
||||||
|
into("src/$variant/resources/META-INF/com/google/android")
|
||||||
|
from(rootFile("scripts/update_binary.sh")) {
|
||||||
|
rename { "update-binary" }
|
||||||
|
}
|
||||||
|
from(rootFile("scripts/flash_script.sh")) {
|
||||||
|
rename { "updater-script" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val downloadBusybox by tasks.registering(Copy::class) {
|
|
||||||
dependsOn(syncLibs)
|
|
||||||
from(zipTree(downloadFile(BUSYBOX_DOWNLOAD_URL, BUSYBOX_ZIP_CHECKSUM)))
|
|
||||||
include(abiList.map { "$it/libbusybox.so" })
|
|
||||||
into("src/main/jniLibs")
|
|
||||||
}
|
|
||||||
|
|
||||||
val syncResources by tasks.registering(Sync::class) {
|
|
||||||
into("src/main/resources/META-INF/com/google/android")
|
|
||||||
from(File(baseDir, "scripts/update_binary.sh")) {
|
|
||||||
rename { "update-binary" }
|
|
||||||
}
|
|
||||||
from(File(baseDir, "scripts/flash_script.sh")) {
|
|
||||||
rename { "updater-script" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
androidLib.libraryVariants.all {
|
|
||||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
|
||||||
|
|
||||||
tasks.getByPath("merge${variantCapped}JniLibFolders").dependsOn(downloadBusybox)
|
|
||||||
processJavaResourcesProvider.configure { dependsOn(syncResources) }
|
processJavaResourcesProvider.configure { dependsOn(syncResources) }
|
||||||
|
|
||||||
val stubTask = tasks.getByPath(":stub:comment$variantCapped")
|
val stubTask = tasks.getByPath(":stub:comment$variantCapped")
|
||||||
@@ -196,15 +173,15 @@ fun Project.setupCoreLib() {
|
|||||||
dependsOn(stubTask)
|
dependsOn(stubTask)
|
||||||
inputs.property("version", Config.version)
|
inputs.property("version", Config.version)
|
||||||
inputs.property("versionCode", Config.versionCode)
|
inputs.property("versionCode", Config.versionCode)
|
||||||
into("src/${this@all.name}/assets")
|
into("src/$variant/assets")
|
||||||
from(File(baseDir, "scripts")) {
|
from(rootFile("scripts")) {
|
||||||
include("util_functions.sh", "boot_patch.sh", "addon.d.sh",
|
include("util_functions.sh", "boot_patch.sh", "addon.d.sh",
|
||||||
"app_functions.sh", "uninstaller.sh", "module_installer.sh")
|
"app_functions.sh", "uninstaller.sh", "module_installer.sh")
|
||||||
}
|
}
|
||||||
from(File(baseDir, "tools/bootctl"))
|
from(rootFile("tools/bootctl"))
|
||||||
into("chromeos") {
|
into("chromeos") {
|
||||||
from(File(baseDir, "tools/futility"))
|
from(rootFile("tools/futility"))
|
||||||
from(File(baseDir, "tools/keys")) {
|
from(rootFile("tools/keys")) {
|
||||||
include("kernel_data_key.vbprivk", "kernel.keyblock")
|
include("kernel_data_key.vbprivk", "kernel.keyblock")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,72 +206,14 @@ fun Project.setupCoreLib() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ApkSigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
|
|
||||||
val keyStore = KeyStore.getInstance(storeType ?: KeyStore.getDefaultType())
|
|
||||||
storeFile!!.inputStream().use {
|
|
||||||
keyStore.load(it, storePassword!!.toCharArray())
|
|
||||||
}
|
|
||||||
val keyPwdArray = keyPassword!!.toCharArray()
|
|
||||||
val entry = keyStore.getEntry(keyAlias!!, KeyStore.PasswordProtection(keyPwdArray))
|
|
||||||
return entry as KeyStore.PrivateKeyEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AddCommentTask: DefaultTask() {
|
|
||||||
@get:Input
|
|
||||||
abstract val comment: Property<String>
|
|
||||||
|
|
||||||
@get:Input
|
|
||||||
abstract val signingConfig: Property<ApkSigningConfig>
|
|
||||||
|
|
||||||
@get:InputFiles
|
|
||||||
abstract val apkFolder: DirectoryProperty
|
|
||||||
|
|
||||||
@get:OutputDirectory
|
|
||||||
abstract val outFolder: DirectoryProperty
|
|
||||||
|
|
||||||
@get:Internal
|
|
||||||
abstract val transformationRequest: Property<ArtifactTransformationRequest<AddCommentTask>>
|
|
||||||
|
|
||||||
@TaskAction
|
|
||||||
fun taskAction() = transformationRequest.get().submit(this) { artifact ->
|
|
||||||
val inFile = File(artifact.outputFile)
|
|
||||||
val outFile = outFolder.file(inFile.name).get().asFile
|
|
||||||
|
|
||||||
val privateKey = signingConfig.get().getPrivateKey()
|
|
||||||
val signingOptions = SigningOptions.builder()
|
|
||||||
.setMinSdkVersion(0)
|
|
||||||
.setV1SigningEnabled(true)
|
|
||||||
.setV2SigningEnabled(true)
|
|
||||||
.setKey(privateKey.privateKey)
|
|
||||||
.setCertificates(privateKey.certificate as X509Certificate)
|
|
||||||
.setValidation(SigningOptions.Validation.ASSUME_INVALID)
|
|
||||||
.build()
|
|
||||||
val options = ZFileOptions().apply {
|
|
||||||
noTimestamps = true
|
|
||||||
autoSortFiles = true
|
|
||||||
}
|
|
||||||
outFile.parentFile?.mkdirs()
|
|
||||||
inFile.copyTo(outFile, overwrite = true)
|
|
||||||
ZFiles.apk(outFile, options).use {
|
|
||||||
SigningExtension(signingOptions).register(it)
|
|
||||||
it.eocdComment = comment.get().toByteArray()
|
|
||||||
it.get(IncrementalPackager.APP_METADATA_ENTRY_PATH)?.delete()
|
|
||||||
it.get(IncrementalPackager.VERSION_CONTROL_INFO_ENTRY_PATH)?.delete()
|
|
||||||
it.get(JarFile.MANIFEST_NAME)?.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
outFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Project.setupAppCommon() {
|
fun Project.setupAppCommon() {
|
||||||
setupCommon()
|
setupCommon()
|
||||||
|
|
||||||
android {
|
android {
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
create("config") {
|
Config["keyStore"]?.also {
|
||||||
Config["keyStore"]?.also {
|
create("config") {
|
||||||
storeFile = File(baseDir, it)
|
storeFile = rootFile(it)
|
||||||
storePassword = Config["keyStorePass"]
|
storePassword = Config["keyStorePass"]
|
||||||
keyAlias = Config["keyAlias"]
|
keyAlias = Config["keyAlias"]
|
||||||
keyPassword = Config["keyPass"]
|
keyPassword = Config["keyPass"]
|
||||||
@@ -310,15 +229,12 @@ fun Project.setupAppCommon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
signingConfigs["config"].also {
|
val config = signingConfigs.findByName("config") ?: signingConfigs["debug"]
|
||||||
debug {
|
debug {
|
||||||
signingConfig = if (it.storeFile?.exists() == true) it
|
signingConfig = config
|
||||||
else signingConfigs["debug"]
|
}
|
||||||
}
|
release {
|
||||||
release {
|
signingConfig = config
|
||||||
signingConfig = if (it.storeFile?.exists() == true) it
|
|
||||||
else signingConfigs["debug"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,89 +301,6 @@ fun Project.setupMainApk() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.setupStubApk() {
|
|
||||||
setupAppCommon()
|
|
||||||
|
|
||||||
androidComponents.onVariants { variant ->
|
|
||||||
val variantName = variant.name
|
|
||||||
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
|
|
||||||
val manifestUpdater =
|
|
||||||
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
|
|
||||||
dependsOn("generate${variantCapped}ObfuscatedClass")
|
|
||||||
applicationId = variant.applicationId
|
|
||||||
appClassDir.set(layout.buildDirectory.dir("generated/source/app/$variantName"))
|
|
||||||
factoryClassDir.set(layout.buildDirectory.dir("generated/source/factory/$variantName"))
|
|
||||||
}
|
|
||||||
variant.artifacts.use(manifestUpdater)
|
|
||||||
.wiredWithFiles(
|
|
||||||
ManifestUpdater::mergedManifest,
|
|
||||||
ManifestUpdater::outputManifest)
|
|
||||||
.toTransform(SingleArtifact.MERGED_MANIFEST)
|
|
||||||
}
|
|
||||||
|
|
||||||
androidApp.applicationVariants.all {
|
|
||||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
|
||||||
val variantLowered = name.lowercase()
|
|
||||||
val outFactoryClassDir = layout.buildDirectory.file("generated/source/factory/${variantLowered}").get().asFile
|
|
||||||
val outAppClassDir = layout.buildDirectory.file("generated/source/app/${variantLowered}").get().asFile
|
|
||||||
val outResDir = layout.buildDirectory.dir("generated/source/res/${variantLowered}").get().asFile
|
|
||||||
val aapt = File(androidApp.sdkDirectory, "build-tools/${androidApp.buildToolsVersion}/aapt2")
|
|
||||||
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
|
||||||
"${variantLowered}/process${variantCapped}Resources/linked-resources-binary-format-${variantLowered}.ap_").get().asFile
|
|
||||||
|
|
||||||
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
|
|
||||||
inputs.property("seed", RAND_SEED)
|
|
||||||
outputs.dirs(outFactoryClassDir, outAppClassDir)
|
|
||||||
doLast {
|
|
||||||
outFactoryClassDir.mkdirs()
|
|
||||||
outAppClassDir.mkdirs()
|
|
||||||
genStubClasses(outFactoryClassDir, outAppClassDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
registerJavaGeneratingTask(genManifestTask, outFactoryClassDir, outAppClassDir)
|
|
||||||
|
|
||||||
val processResourcesTask = tasks.named("process${variantCapped}Resources") {
|
|
||||||
outputs.dir(outResDir)
|
|
||||||
doLast {
|
|
||||||
val apkTmp = File("${apk}.tmp")
|
|
||||||
exec {
|
|
||||||
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
|
|
||||||
}
|
|
||||||
|
|
||||||
val bos = ByteArrayOutputStream()
|
|
||||||
ZipFile(apkTmp).use { src ->
|
|
||||||
ZipOutputStream(apk.outputStream()).use {
|
|
||||||
it.setLevel(Deflater.BEST_COMPRESSION)
|
|
||||||
it.putNextEntry(ZipEntry("AndroidManifest.xml"))
|
|
||||||
src.getInputStream(src.getEntry("AndroidManifest.xml")).transferTo(it)
|
|
||||||
it.closeEntry()
|
|
||||||
}
|
|
||||||
DeflaterOutputStream(bos, Deflater(Deflater.BEST_COMPRESSION)).use {
|
|
||||||
src.getInputStream(src.getEntry("resources.arsc")).transferTo(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apkTmp.delete()
|
|
||||||
genEncryptedResources(bos.toByteArray(), outResDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerJavaGeneratingTask(processResourcesTask, outResDir)
|
|
||||||
}
|
|
||||||
// Override optimizeReleaseResources task
|
|
||||||
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
|
||||||
"release/processReleaseResources/linked-resources-binary-format-release.ap_").get().asFile
|
|
||||||
val optRes = layout.buildDirectory.file("intermediates/optimized_processed_res/" +
|
|
||||||
"release/optimizeReleaseResources/resources-release-optimize.ap_").get().asFile
|
|
||||||
afterEvaluate {
|
|
||||||
tasks.named("optimizeReleaseResources") {
|
|
||||||
doLast { apk.copyTo(optRes, true) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.named<Delete>("clean") {
|
|
||||||
delete.addAll(listOf("src/debug/AndroidManifest.xml", "src/release/AndroidManifest.xml"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const val LSPOSED_DOWNLOAD_URL =
|
const val LSPOSED_DOWNLOAD_URL =
|
||||||
"https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed-v1.9.2-7024-zygisk-release.zip"
|
"https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed-v1.9.2-7024-zygisk-release.zip"
|
||||||
const val LSPOSED_CHECKSUM =
|
const val LSPOSED_CHECKSUM =
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import com.android.build.api.artifact.SingleArtifact
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.file.DirectoryProperty
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.file.RegularFileProperty
|
import org.gradle.api.file.RegularFileProperty
|
||||||
import org.gradle.api.provider.Property
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.tasks.CacheableTask
|
import org.gradle.api.tasks.CacheableTask
|
||||||
|
import org.gradle.api.tasks.Delete
|
||||||
import org.gradle.api.tasks.Input
|
import org.gradle.api.tasks.Input
|
||||||
import org.gradle.api.tasks.InputFile
|
import org.gradle.api.tasks.InputFile
|
||||||
import org.gradle.api.tasks.InputFiles
|
import org.gradle.api.tasks.InputFiles
|
||||||
@@ -10,22 +13,25 @@ import org.gradle.api.tasks.OutputFile
|
|||||||
import org.gradle.api.tasks.PathSensitive
|
import org.gradle.api.tasks.PathSensitive
|
||||||
import org.gradle.api.tasks.PathSensitivity
|
import org.gradle.api.tasks.PathSensitivity
|
||||||
import org.gradle.api.tasks.TaskAction
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import org.gradle.kotlin.dsl.assign
|
||||||
|
import org.gradle.kotlin.dsl.named
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
|
import java.util.zip.Deflater
|
||||||
|
import java.util.zip.DeflaterOutputStream
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.CipherOutputStream
|
import javax.crypto.CipherOutputStream
|
||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import kotlin.random.asKotlinRandom
|
import kotlin.random.asKotlinRandom
|
||||||
|
|
||||||
// Set non-zero value here to fix the random seed for reproducible builds
|
|
||||||
// CI builds are always reproducible
|
|
||||||
val RAND_SEED = if (System.getenv("CI") != null) 42 else 0
|
|
||||||
private lateinit var RANDOM: Random
|
|
||||||
private val kRANDOM get() = RANDOM.asKotlinRandom()
|
private val kRANDOM get() = RANDOM.asKotlinRandom()
|
||||||
|
|
||||||
private val c1 = mutableListOf<String>()
|
private val c1 = mutableListOf<String>()
|
||||||
@@ -72,7 +78,7 @@ private fun PrintStream.byteField(name: String, bytes: ByteArray) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@CacheableTask
|
@CacheableTask
|
||||||
abstract class ManifestUpdater: DefaultTask() {
|
private abstract class ManifestUpdater: DefaultTask() {
|
||||||
@get:Input
|
@get:Input
|
||||||
abstract val applicationId: Property<String>
|
abstract val applicationId: Property<String>
|
||||||
|
|
||||||
@@ -182,9 +188,7 @@ abstract class ManifestUpdater: DefaultTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun genStubClasses(factoryOutDir: File, appOutDir: File) {
|
private fun genStubClasses(factoryOutDir: File, appOutDir: File) {
|
||||||
fun String.ind(level: Int) = replaceIndentByMargin(" ".repeat(level))
|
|
||||||
|
|
||||||
val classNameGenerator = sequence {
|
val classNameGenerator = sequence {
|
||||||
fun notJavaKeyword(name: String) = when (name) {
|
fun notJavaKeyword(name: String) = when (name) {
|
||||||
"do", "if", "for", "int", "new", "try" -> false
|
"do", "if", "for", "int", "new", "try" -> false
|
||||||
@@ -228,7 +232,7 @@ fun genStubClasses(factoryOutDir: File, appOutDir: File) {
|
|||||||
genClass("StubApplication", appOutDir)
|
genClass("StubApplication", appOutDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun genEncryptedResources(res: ByteArray, outDir: File) {
|
private fun genEncryptedResources(res: ByteArray, outDir: File) {
|
||||||
val mainPkgDir = File(outDir, "com/topjohnwu/magisk")
|
val mainPkgDir = File(outDir, "com/topjohnwu/magisk")
|
||||||
mainPkgDir.mkdirs()
|
mainPkgDir.mkdirs()
|
||||||
|
|
||||||
@@ -259,3 +263,86 @@ fun genEncryptedResources(res: ByteArray, outDir: File) {
|
|||||||
it.println("}")
|
it.println("}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Project.setupStubApk() {
|
||||||
|
setupAppCommon()
|
||||||
|
|
||||||
|
androidComponents.onVariants { variant ->
|
||||||
|
val variantName = variant.name
|
||||||
|
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
|
||||||
|
val manifestUpdater =
|
||||||
|
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
|
||||||
|
dependsOn("generate${variantCapped}ObfuscatedClass")
|
||||||
|
applicationId = variant.applicationId
|
||||||
|
appClassDir.set(layout.buildDirectory.dir("generated/source/app/$variantName"))
|
||||||
|
factoryClassDir.set(layout.buildDirectory.dir("generated/source/factory/$variantName"))
|
||||||
|
}
|
||||||
|
variant.artifacts.use(manifestUpdater)
|
||||||
|
.wiredWithFiles(
|
||||||
|
ManifestUpdater::mergedManifest,
|
||||||
|
ManifestUpdater::outputManifest)
|
||||||
|
.toTransform(SingleArtifact.MERGED_MANIFEST)
|
||||||
|
}
|
||||||
|
|
||||||
|
androidApp.applicationVariants.all {
|
||||||
|
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
||||||
|
val variantLowered = name.lowercase()
|
||||||
|
val outFactoryClassDir = layout.buildDirectory.file("generated/source/factory/${variantLowered}").get().asFile
|
||||||
|
val outAppClassDir = layout.buildDirectory.file("generated/source/app/${variantLowered}").get().asFile
|
||||||
|
val outResDir = layout.buildDirectory.dir("generated/source/res/${variantLowered}").get().asFile
|
||||||
|
val aapt = File(androidApp.sdkDirectory, "build-tools/${androidApp.buildToolsVersion}/aapt2")
|
||||||
|
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
||||||
|
"${variantLowered}/process${variantCapped}Resources/linked-resources-binary-format-${variantLowered}.ap_").get().asFile
|
||||||
|
|
||||||
|
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
|
||||||
|
inputs.property("seed", RAND_SEED)
|
||||||
|
outputs.dirs(outFactoryClassDir, outAppClassDir)
|
||||||
|
doLast {
|
||||||
|
outFactoryClassDir.mkdirs()
|
||||||
|
outAppClassDir.mkdirs()
|
||||||
|
genStubClasses(outFactoryClassDir, outAppClassDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registerJavaGeneratingTask(genManifestTask, outFactoryClassDir, outAppClassDir)
|
||||||
|
|
||||||
|
val processResourcesTask = tasks.named("process${variantCapped}Resources") {
|
||||||
|
outputs.dir(outResDir)
|
||||||
|
doLast {
|
||||||
|
val apkTmp = File("${apk}.tmp")
|
||||||
|
exec {
|
||||||
|
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
|
||||||
|
}
|
||||||
|
|
||||||
|
val bos = ByteArrayOutputStream()
|
||||||
|
ZipFile(apkTmp).use { src ->
|
||||||
|
ZipOutputStream(apk.outputStream()).use {
|
||||||
|
it.setLevel(Deflater.BEST_COMPRESSION)
|
||||||
|
it.putNextEntry(ZipEntry("AndroidManifest.xml"))
|
||||||
|
src.getInputStream(src.getEntry("AndroidManifest.xml")).transferTo(it)
|
||||||
|
it.closeEntry()
|
||||||
|
}
|
||||||
|
DeflaterOutputStream(bos, Deflater(Deflater.BEST_COMPRESSION)).use {
|
||||||
|
src.getInputStream(src.getEntry("resources.arsc")).transferTo(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apkTmp.delete()
|
||||||
|
genEncryptedResources(bos.toByteArray(), outResDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerJavaGeneratingTask(processResourcesTask, outResDir)
|
||||||
|
}
|
||||||
|
// Override optimizeReleaseResources task
|
||||||
|
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
||||||
|
"release/processReleaseResources/linked-resources-binary-format-release.ap_").get().asFile
|
||||||
|
val optRes = layout.buildDirectory.file("intermediates/optimized_processed_res/" +
|
||||||
|
"release/optimizeReleaseResources/resources-release-optimize.ap_").get().asFile
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.named("optimizeReleaseResources") {
|
||||||
|
doLast { apk.copyTo(optRes, true) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.named<Delete>("clean") {
|
||||||
|
delete.addAll(listOf("src/debug/AndroidManifest.xml", "src/release/AndroidManifest.xml"))
|
||||||
|
}
|
||||||
|
}
|
||||||
5
app/core/.gitignore
vendored
5
app/core/.gitignore
vendored
@@ -1,4 +1,3 @@
|
|||||||
/build
|
/build
|
||||||
src/*/assets
|
src/debug
|
||||||
src/*/jniLibs
|
src/release
|
||||||
src/*/resources
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ plugins {
|
|||||||
id("com.android.library")
|
id("com.android.library")
|
||||||
kotlin("android")
|
kotlin("android")
|
||||||
kotlin("plugin.parcelize")
|
kotlin("plugin.parcelize")
|
||||||
|
id("dev.zacsweers.moshix")
|
||||||
id("com.google.devtools.ksp")
|
id("com.google.devtools.ksp")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,9 +49,6 @@ dependencies {
|
|||||||
implementation(libs.okhttp.logging)
|
implementation(libs.okhttp.logging)
|
||||||
implementation(libs.okhttp.dnsoverhttps)
|
implementation(libs.okhttp.dnsoverhttps)
|
||||||
|
|
||||||
implementation(libs.moshi)
|
|
||||||
ksp(libs.moshi.codegen)
|
|
||||||
|
|
||||||
implementation(libs.room.runtime)
|
implementation(libs.room.runtime)
|
||||||
implementation(libs.room.ktx)
|
implementation(libs.room.ktx)
|
||||||
ksp(libs.room.compiler)
|
ksp(libs.room.compiler)
|
||||||
|
|||||||
@@ -32,8 +32,9 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
const val SU_NOTIFICATION = "su_notification"
|
const val SU_NOTIFICATION = "su_notification"
|
||||||
const val SU_REAUTH = "su_reauth"
|
const val SU_REAUTH = "su_reauth"
|
||||||
const val SU_TAPJACK = "su_tapjack"
|
const val SU_TAPJACK = "su_tapjack"
|
||||||
|
const val SU_RESTRICT = "su_restrict"
|
||||||
const val CHECK_UPDATES = "check_update"
|
const val CHECK_UPDATES = "check_update"
|
||||||
const val UPDATE_CHANNEL = "update_channel"
|
const val RELEASE_CHANNEL = "release_channel"
|
||||||
const val CUSTOM_CHANNEL = "custom_channel"
|
const val CUSTOM_CHANNEL = "custom_channel"
|
||||||
const val LOCALE = "locale"
|
const val LOCALE = "locale"
|
||||||
const val DARK_THEME = "dark_theme_extended"
|
const val DARK_THEME = "dark_theme_extended"
|
||||||
@@ -48,7 +49,7 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK)
|
SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Value {
|
object OldValue {
|
||||||
// Update channels
|
// Update channels
|
||||||
const val DEFAULT_CHANNEL = -1
|
const val DEFAULT_CHANNEL = -1
|
||||||
const val STABLE_CHANNEL = 0
|
const val STABLE_CHANNEL = 0
|
||||||
@@ -56,6 +57,15 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
const val CUSTOM_CHANNEL = 2
|
const val CUSTOM_CHANNEL = 2
|
||||||
const val CANARY_CHANNEL = 3
|
const val CANARY_CHANNEL = 3
|
||||||
const val DEBUG_CHANNEL = 4
|
const val DEBUG_CHANNEL = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
object Value {
|
||||||
|
// Update channels
|
||||||
|
const val DEFAULT_CHANNEL = -1
|
||||||
|
const val STABLE_CHANNEL = 0
|
||||||
|
const val BETA_CHANNEL = 1
|
||||||
|
const val DEBUG_CHANNEL = 2
|
||||||
|
const val CUSTOM_CHANNEL = 3
|
||||||
|
|
||||||
// root access mode
|
// root access mode
|
||||||
const val ROOT_ACCESS_DISABLED = 0
|
const val ROOT_ACCESS_DISABLED = 0
|
||||||
@@ -86,14 +96,6 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60)
|
val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val defaultChannel =
|
|
||||||
if (BuildConfig.DEBUG)
|
|
||||||
Value.DEBUG_CHANNEL
|
|
||||||
else if (Const.APP_IS_CANARY)
|
|
||||||
Value.CANARY_CHANNEL
|
|
||||||
else
|
|
||||||
Value.DEFAULT_CHANNEL
|
|
||||||
|
|
||||||
@JvmField var keepVerity = false
|
@JvmField var keepVerity = false
|
||||||
@JvmField var keepEnc = false
|
@JvmField var keepEnc = false
|
||||||
@JvmField var recovery = false
|
@JvmField var recovery = false
|
||||||
@@ -109,7 +111,7 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
private var checkUpdatePrefs by preference(Key.CHECK_UPDATES, true)
|
private var checkUpdatePrefs by preference(Key.CHECK_UPDATES, true)
|
||||||
private var localePrefs by preference(Key.LOCALE, "")
|
private var localePrefs by preference(Key.LOCALE, "")
|
||||||
var doh by preference(Key.DOH, false)
|
var doh by preference(Key.DOH, false)
|
||||||
var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel)
|
var updateChannel by preference(Key.RELEASE_CHANNEL, Value.DEFAULT_CHANNEL)
|
||||||
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
|
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
|
||||||
var downloadDir by preference(Key.DOWNLOAD_DIR, "")
|
var downloadDir by preference(Key.DOWNLOAD_DIR, "")
|
||||||
var randName by preference(Key.RAND_NAME, true)
|
var randName by preference(Key.RAND_NAME, true)
|
||||||
@@ -146,8 +148,10 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
}
|
}
|
||||||
var suReAuth by preference(Key.SU_REAUTH, false)
|
var suReAuth by preference(Key.SU_REAUTH, false)
|
||||||
var suTapjack by preference(Key.SU_TAPJACK, true)
|
var suTapjack by preference(Key.SU_TAPJACK, true)
|
||||||
|
var suRestrict by preference(Key.SU_RESTRICT, false)
|
||||||
|
|
||||||
private const val SU_FINGERPRINT = "su_fingerprint"
|
private const val SU_FINGERPRINT = "su_fingerprint"
|
||||||
|
private const val UPDATE_CHANNEL = "update_channel"
|
||||||
|
|
||||||
fun toBundle(): Bundle {
|
fun toBundle(): Bundle {
|
||||||
val map = prefs.all - Key.NO_MIGRATION
|
val map = prefs.all - Key.NO_MIGRATION
|
||||||
@@ -183,17 +187,23 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
// Settings migration
|
// Migrate su_fingerprint
|
||||||
if (prefs.getBoolean(SU_FINGERPRINT, false))
|
if (prefs.getBoolean(SU_FINGERPRINT, false))
|
||||||
suBiometric = true
|
suBiometric = true
|
||||||
remove(SU_FINGERPRINT)
|
remove(SU_FINGERPRINT)
|
||||||
prefs.getString(Key.UPDATE_CHANNEL, null).also {
|
|
||||||
if (it == null ||
|
// Migrate update_channel
|
||||||
it.toInt() > Value.DEBUG_CHANNEL ||
|
prefs.getString(UPDATE_CHANNEL, null)?.let {
|
||||||
it.toInt() < Value.DEFAULT_CHANNEL) {
|
val channel = when (it.toInt()) {
|
||||||
putString(Key.UPDATE_CHANNEL, defaultChannel.toString())
|
OldValue.STABLE_CHANNEL -> Value.STABLE_CHANNEL
|
||||||
|
OldValue.CANARY_CHANNEL, OldValue.BETA_CHANNEL -> Value.BETA_CHANNEL
|
||||||
|
OldValue.DEBUG_CHANNEL -> Value.DEBUG_CHANNEL
|
||||||
|
OldValue.CUSTOM_CHANNEL -> Value.CUSTOM_CHANNEL
|
||||||
|
else -> Value.DEFAULT_CHANNEL
|
||||||
}
|
}
|
||||||
|
putInt(Key.RELEASE_CHANNEL, channel)
|
||||||
}
|
}
|
||||||
|
remove(UPDATE_CHANNEL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.topjohnwu.magisk.core
|
|||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
|
import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
object Const {
|
object Const {
|
||||||
@@ -20,18 +21,16 @@ object Const {
|
|||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
val USER_ID = Process.myUid() / 100000
|
val USER_ID = Process.myUid() / 100000
|
||||||
val APP_IS_CANARY get() = Version.isCanary(BuildConfig.APP_VERSION_CODE)
|
|
||||||
|
|
||||||
object Version {
|
object Version {
|
||||||
const val MIN_VERSION = "v22.0"
|
const val MIN_VERSION = "v22.0"
|
||||||
const val MIN_VERCODE = 22000
|
const val MIN_VERCODE = 22000
|
||||||
|
|
||||||
|
private fun isCanary() = (Info.env.versionCode % 100) != 0
|
||||||
fun atLeast_24_0() = Info.env.versionCode >= 24000 || isCanary()
|
fun atLeast_24_0() = Info.env.versionCode >= 24000 || isCanary()
|
||||||
fun atLeast_25_0() = Info.env.versionCode >= 25000 || isCanary()
|
fun atLeast_25_0() = Info.env.versionCode >= 25000 || isCanary()
|
||||||
fun atLeast_28_0() = Info.env.versionCode >= 28000 || isCanary()
|
fun atLeast_28_0() = Info.env.versionCode >= 28000 || isCanary()
|
||||||
fun isCanary() = isCanary(Info.env.versionCode)
|
fun atLeast_30_1() = Info.env.versionCode >= 30100 || isCanary()
|
||||||
|
|
||||||
fun isCanary(ver: Int) = ver > 0 && ver % 100 != 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object ID {
|
object ID {
|
||||||
@@ -43,13 +42,9 @@ object Const {
|
|||||||
const val PATREON_URL = "https://www.patreon.com/topjohnwu"
|
const val PATREON_URL = "https://www.patreon.com/topjohnwu"
|
||||||
const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"
|
const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"
|
||||||
|
|
||||||
val CHANGELOG_URL = if (APP_IS_CANARY) Info.remote.magisk.note
|
|
||||||
else "https://topjohnwu.github.io/Magisk/releases/${BuildConfig.APP_VERSION_CODE}.md"
|
|
||||||
|
|
||||||
const val GITHUB_RAW_URL = "https://raw.githubusercontent.com/"
|
|
||||||
const val GITHUB_API_URL = "https://api.github.com/"
|
const val GITHUB_API_URL = "https://api.github.com/"
|
||||||
const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/"
|
const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/"
|
||||||
const val JS_DELIVR_URL = "https://cdn.jsdelivr.net/gh/"
|
const val INVALID_URL = "https://example.com/"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Key {
|
object Key {
|
||||||
|
|||||||
@@ -19,12 +19,18 @@ object Info {
|
|||||||
|
|
||||||
var stub: StubApk.Data? = null
|
var stub: StubApk.Data? = null
|
||||||
|
|
||||||
val EMPTY_REMOTE = UpdateInfo()
|
private val EMPTY_UPDATE = UpdateInfo()
|
||||||
var remote = EMPTY_REMOTE
|
var update = EMPTY_UPDATE
|
||||||
suspend fun getRemote(svc: NetworkService): UpdateInfo? {
|
private set
|
||||||
return if (remote === EMPTY_REMOTE) {
|
|
||||||
svc.fetchUpdate()?.apply { remote = this }
|
suspend fun fetchUpdate(svc: NetworkService): UpdateInfo? {
|
||||||
} else remote
|
return if (update === EMPTY_UPDATE) {
|
||||||
|
svc.fetchUpdate()?.apply { update = this }
|
||||||
|
} else update
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetUpdate() {
|
||||||
|
update = EMPTY_UPDATE
|
||||||
}
|
}
|
||||||
|
|
||||||
var isRooted = false
|
var isRooted = false
|
||||||
|
|||||||
@@ -75,9 +75,8 @@ class JobService : BaseJobService() {
|
|||||||
|
|
||||||
private fun checkUpdate(params: JobParameters): Boolean {
|
private fun checkUpdate(params: JobParameters): Boolean {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
ServiceLocator.networkService.fetchUpdate()?.let {
|
Info.fetchUpdate(ServiceLocator.networkService)?.let {
|
||||||
Info.remote = it
|
if (Info.env.isActive && BuildConfig.APP_VERSION_CODE < it.versionCode)
|
||||||
if (Info.env.isActive && BuildConfig.APP_VERSION_CODE < it.magisk.versionCode)
|
|
||||||
Notifications.updateAvailable()
|
Notifications.updateAvailable()
|
||||||
jobFinished(params, false)
|
jobFinished(params, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.core.data
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.core.model.BranchInfo
|
|
||||||
import com.topjohnwu.magisk.core.model.ModuleJson
|
|
||||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
|
||||||
import okhttp3.ResponseBody
|
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.Headers
|
|
||||||
import retrofit2.http.Path
|
|
||||||
import retrofit2.http.Streaming
|
|
||||||
import retrofit2.http.Url
|
|
||||||
|
|
||||||
private const val BRANCH = "branch"
|
|
||||||
private const val REPO = "repo"
|
|
||||||
private const val FILE = "file"
|
|
||||||
|
|
||||||
interface GithubPageServices {
|
|
||||||
|
|
||||||
@GET
|
|
||||||
suspend fun fetchUpdateJSON(@Url file: String): UpdateInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RawServices {
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Streaming
|
|
||||||
suspend fun fetchFile(@Url url: String): ResponseBody
|
|
||||||
|
|
||||||
@GET
|
|
||||||
suspend fun fetchString(@Url url: String): String
|
|
||||||
|
|
||||||
@GET
|
|
||||||
suspend fun fetchModuleJson(@Url url: String): ModuleJson
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GithubApiServices {
|
|
||||||
|
|
||||||
@GET("repos/{$REPO}/branches/{$BRANCH}")
|
|
||||||
@Headers("Accept: application/vnd.github.v3+json")
|
|
||||||
suspend fun fetchBranch(
|
|
||||||
@Path(REPO, encoded = true) repo: String,
|
|
||||||
@Path(BRANCH) branch: String
|
|
||||||
): BranchInfo
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.topjohnwu.magisk.core.data
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.core.model.ModuleJson
|
||||||
|
import com.topjohnwu.magisk.core.model.Release
|
||||||
|
import com.topjohnwu.magisk.core.model.UpdateJson
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import retrofit2.Response
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Headers
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
import retrofit2.http.Streaming
|
||||||
|
import retrofit2.http.Url
|
||||||
|
|
||||||
|
interface RawUrl {
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Streaming
|
||||||
|
suspend fun fetchFile(@Url url: String): ResponseBody
|
||||||
|
|
||||||
|
@GET
|
||||||
|
suspend fun fetchString(@Url url: String): String
|
||||||
|
|
||||||
|
@GET
|
||||||
|
suspend fun fetchModuleJson(@Url url: String): ModuleJson
|
||||||
|
|
||||||
|
@GET
|
||||||
|
suspend fun fetchUpdateJson(@Url url: String): UpdateJson
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GithubApiServices {
|
||||||
|
|
||||||
|
@GET("/repos/{owner}/{repo}/releases")
|
||||||
|
@Headers("Accept: application/vnd.github+json")
|
||||||
|
suspend fun fetchReleases(
|
||||||
|
@Path("owner") owner: String = "topjohnwu",
|
||||||
|
@Path("repo") repo: String = "Magisk",
|
||||||
|
@Query("per_page") per: Int = 10,
|
||||||
|
@Query("page") page: Int = 1,
|
||||||
|
): Response<MutableList<Release>>
|
||||||
|
|
||||||
|
@GET("/repos/{owner}/{repo}/releases/latest")
|
||||||
|
@Headers("Accept: application/vnd.github+json")
|
||||||
|
suspend fun fetchLatestRelease(
|
||||||
|
@Path("owner") owner: String = "topjohnwu",
|
||||||
|
@Path("repo") repo: String = "Magisk",
|
||||||
|
): Release
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.squareup.moshi.Moshi
|
|||||||
import com.topjohnwu.magisk.ProviderInstaller
|
import com.topjohnwu.magisk.ProviderInstaller
|
||||||
import com.topjohnwu.magisk.core.BuildConfig
|
import com.topjohnwu.magisk.core.BuildConfig
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
|
import com.topjohnwu.magisk.core.model.DateTimeAdapter
|
||||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import okhttp3.ConnectionSpec
|
import okhttp3.ConnectionSpec
|
||||||
@@ -77,7 +78,7 @@ fun createOkHttpClient(context: Context): OkHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createMoshiConverterFactory(): MoshiConverterFactory {
|
fun createMoshiConverterFactory(): MoshiConverterFactory {
|
||||||
val moshi = Moshi.Builder().build()
|
val moshi = Moshi.Builder().add(DateTimeAdapter()).build()
|
||||||
return MoshiConverterFactory.create(moshi)
|
return MoshiConverterFactory.create(moshi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ object ServiceLocator {
|
|||||||
val markwon by lazy { createMarkwon(AppContext) }
|
val markwon by lazy { createMarkwon(AppContext) }
|
||||||
val networkService by lazy {
|
val networkService by lazy {
|
||||||
NetworkService(
|
NetworkService(
|
||||||
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),
|
createApiService(retrofit, Const.Url.INVALID_URL),
|
||||||
createApiService(retrofit, Const.Url.GITHUB_RAW_URL),
|
createApiService(retrofit, Const.Url.GITHUB_API_URL),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import android.net.Uri
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.model.MagiskJson
|
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||||
import com.topjohnwu.magisk.view.Notifications
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
@@ -38,7 +38,7 @@ abstract class Subject : Parcelable {
|
|||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class App(
|
class App(
|
||||||
private val json: MagiskJson = Info.remote.magisk,
|
private val json: UpdateInfo = Info.update,
|
||||||
override val notifyId: Int = Notifications.nextId()
|
override val notifyId: Int = Notifications.nextId()
|
||||||
) : Subject() {
|
) : Subject() {
|
||||||
override val title: String get() = "Magisk-${json.version}(${json.versionCode})"
|
override val title: String get() = "Magisk-${json.version}(${json.versionCode})"
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
package com.topjohnwu.magisk.core.model
|
package com.topjohnwu.magisk.core.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.squareup.moshi.FromJson
|
||||||
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import com.squareup.moshi.JsonQualifier
|
||||||
|
import com.squareup.moshi.ToJson
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class UpdateInfo(
|
class UpdateJson(
|
||||||
val magisk: MagiskJson = MagiskJson(),
|
val magisk: UpdateInfo = UpdateInfo(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MagiskJson(
|
data class UpdateInfo(
|
||||||
val version: String = "",
|
val version: String = "",
|
||||||
val versionCode: Int = -1,
|
val versionCode: Int = -1,
|
||||||
val link: String = "",
|
val link: String = "",
|
||||||
@@ -27,11 +33,37 @@ data class ModuleJson(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class CommitInfo(
|
data class ReleaseAssets(
|
||||||
val sha: String
|
val name: String,
|
||||||
|
@Json(name = "browser_download_url") val url: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class DateTimeAdapter {
|
||||||
|
@ToJson
|
||||||
|
fun toJson(date: LocalDateTime): String {
|
||||||
|
return date.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson
|
||||||
|
fun fromJson(date: String): LocalDateTime {
|
||||||
|
return LocalDateTime.parse(date, ISO_OFFSET_DATE_TIME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class BranchInfo(
|
data class Release(
|
||||||
val commit: CommitInfo
|
@Json(name = "tag_name") val tag: String,
|
||||||
)
|
val name: String,
|
||||||
|
val prerelease: Boolean,
|
||||||
|
val assets: List<ReleaseAssets>,
|
||||||
|
val body: String,
|
||||||
|
@Json(name = "created_at") val createdTime: LocalDateTime,
|
||||||
|
) {
|
||||||
|
val versionCode: Int get() {
|
||||||
|
return if (tag[0] == 'v') {
|
||||||
|
(tag.drop(1).toFloat() * 1000).toInt()
|
||||||
|
} else {
|
||||||
|
tag.drop(7).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ import com.topjohnwu.magisk.core.data.magiskdb.MagiskDB
|
|||||||
|
|
||||||
class SuPolicy(
|
class SuPolicy(
|
||||||
val uid: Int,
|
val uid: Int,
|
||||||
var policy: Int = INTERACTIVE,
|
var policy: Int = QUERY,
|
||||||
var remain: Long = -1L,
|
var remain: Long = -1L,
|
||||||
var logging: Boolean = true,
|
var logging: Boolean = true,
|
||||||
var notification: Boolean = true,
|
var notification: Boolean = true,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val INTERACTIVE = 0
|
const val QUERY = 0
|
||||||
const val DENY = 1
|
const val DENY = 1
|
||||||
const val ALLOW = 2
|
const val ALLOW = 2
|
||||||
|
const val RESTRICT = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toMap(): MutableMap<String, Any> {
|
fun toMap(): MutableMap<String, Any> {
|
||||||
|
|||||||
@@ -1,46 +1,112 @@
|
|||||||
package com.topjohnwu.magisk.core.repository
|
package com.topjohnwu.magisk.core.repository
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.core.BuildConfig
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Config.Value.BETA_CHANNEL
|
import com.topjohnwu.magisk.core.Config.Value.BETA_CHANNEL
|
||||||
import com.topjohnwu.magisk.core.Config.Value.CANARY_CHANNEL
|
|
||||||
import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL
|
import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL
|
||||||
import com.topjohnwu.magisk.core.Config.Value.DEBUG_CHANNEL
|
import com.topjohnwu.magisk.core.Config.Value.DEBUG_CHANNEL
|
||||||
import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL
|
import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL
|
||||||
import com.topjohnwu.magisk.core.Config.Value.STABLE_CHANNEL
|
import com.topjohnwu.magisk.core.Config.Value.STABLE_CHANNEL
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.data.GithubPageServices
|
import com.topjohnwu.magisk.core.data.GithubApiServices
|
||||||
import com.topjohnwu.magisk.core.data.RawServices
|
import com.topjohnwu.magisk.core.data.RawUrl
|
||||||
|
import com.topjohnwu.magisk.core.model.Release
|
||||||
|
import com.topjohnwu.magisk.core.model.ReleaseAssets
|
||||||
|
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
class NetworkService(
|
class NetworkService(
|
||||||
private val pages: GithubPageServices,
|
private val raw: RawUrl,
|
||||||
private val raw: RawServices
|
private val api: GithubApiServices,
|
||||||
) {
|
) {
|
||||||
suspend fun fetchUpdate() = safe {
|
suspend fun fetchUpdate() = safe {
|
||||||
var info = when (Config.updateChannel) {
|
var info = when (Config.updateChannel) {
|
||||||
DEFAULT_CHANNEL, STABLE_CHANNEL -> fetchStableUpdate()
|
DEFAULT_CHANNEL -> if (BuildConfig.DEBUG) fetchDebugUpdate() else fetchStableUpdate()
|
||||||
|
STABLE_CHANNEL -> fetchStableUpdate()
|
||||||
BETA_CHANNEL -> fetchBetaUpdate()
|
BETA_CHANNEL -> fetchBetaUpdate()
|
||||||
CANARY_CHANNEL -> fetchCanaryUpdate()
|
|
||||||
DEBUG_CHANNEL -> fetchDebugUpdate()
|
DEBUG_CHANNEL -> fetchDebugUpdate()
|
||||||
CUSTOM_CHANNEL -> fetchCustomUpdate(Config.customChannelUrl)
|
CUSTOM_CHANNEL -> fetchCustomUpdate(Config.customChannelUrl)
|
||||||
else -> throw IllegalArgumentException()
|
else -> throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
if (info.magisk.versionCode < Info.env.versionCode &&
|
if (info.versionCode < Info.env.versionCode &&
|
||||||
Config.updateChannel == DEFAULT_CHANNEL) {
|
Config.updateChannel == DEFAULT_CHANNEL &&
|
||||||
|
!BuildConfig.DEBUG
|
||||||
|
) {
|
||||||
Config.updateChannel = BETA_CHANNEL
|
Config.updateChannel = BETA_CHANNEL
|
||||||
info = fetchBetaUpdate()
|
info = fetchBetaUpdate()
|
||||||
}
|
}
|
||||||
info
|
info
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateInfo
|
suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }.asInfo()
|
||||||
private suspend fun fetchStableUpdate() = pages.fetchUpdateJSON("stable.json")
|
|
||||||
private suspend fun fetchBetaUpdate() = pages.fetchUpdateJSON("beta.json")
|
// Keep going through all release pages until we find a match
|
||||||
private suspend fun fetchCanaryUpdate() = pages.fetchUpdateJSON("canary.json")
|
private suspend inline fun findRelease(predicate: (Release) -> Boolean): Release? {
|
||||||
private suspend fun fetchDebugUpdate() = pages.fetchUpdateJSON("debug.json")
|
var page = 1
|
||||||
private suspend fun fetchCustomUpdate(url: String) = pages.fetchUpdateJSON(url)
|
while (true) {
|
||||||
|
val response = api.fetchReleases(page = page)
|
||||||
|
val releases = response.body() ?: throw HttpException(response)
|
||||||
|
// Remove all non Magisk releases
|
||||||
|
releases.removeAll { it.tag[0] != 'v' && !it.tag.startsWith("canary") }
|
||||||
|
// Make sure it's sorted correctly
|
||||||
|
releases.sortByDescending { it.createdTime }
|
||||||
|
releases.find(predicate)?.let { return it }
|
||||||
|
if (response.headers()["link"]?.contains("rel=\"next\"", ignoreCase = true) == true) {
|
||||||
|
page += 1
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun Release?.asInfo(
|
||||||
|
selector: (ReleaseAssets) -> Boolean = {
|
||||||
|
// Default selector picks the non-debug APK
|
||||||
|
it.name.run { endsWith(".apk") && !contains("debug") }
|
||||||
|
}): UpdateInfo {
|
||||||
|
return if (this == null) UpdateInfo()
|
||||||
|
else if (tag[0] == 'v') asPublicInfo(selector)
|
||||||
|
else asCanaryInfo(selector)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun Release.asPublicInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo {
|
||||||
|
val version = tag.drop(1)
|
||||||
|
val date = createdTime.format(DateTimeFormatter.ofPattern("yyyy.M.d"))
|
||||||
|
return UpdateInfo(
|
||||||
|
version = version,
|
||||||
|
versionCode = versionCode,
|
||||||
|
link = assets.find(selector)!!.url,
|
||||||
|
note = "## $date $name\n\n$body"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun Release.asCanaryInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo {
|
||||||
|
return UpdateInfo(
|
||||||
|
version = name.substring(8, 16),
|
||||||
|
versionCode = versionCode,
|
||||||
|
link = assets.find(selector)!!.url,
|
||||||
|
note = "## $name\n\n$body"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version number: debug == beta >= stable
|
||||||
|
|
||||||
|
// Find the latest non-prerelease
|
||||||
|
private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asInfo()
|
||||||
|
|
||||||
|
// Find the latest release, regardless whether it's prerelease
|
||||||
|
private suspend fun fetchBetaUpdate() = findRelease { true }.asInfo()
|
||||||
|
|
||||||
|
private suspend fun fetchDebugUpdate() =
|
||||||
|
findRelease { true }.asInfo { it.name == "app-debug.apk" }
|
||||||
|
|
||||||
|
private suspend fun fetchCustomUpdate(url: String): UpdateInfo {
|
||||||
|
val info = raw.fetchUpdateJson(url).magisk
|
||||||
|
return info.let { it.copy(note = raw.fetchString(it.note)) }
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun <T> safe(factory: () -> T): T? {
|
private inline fun <T> safe(factory: () -> T): T? {
|
||||||
return try {
|
return try {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ object SuCallbackHandler {
|
|||||||
}.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids)
|
}.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids)
|
||||||
|
|
||||||
if (notify)
|
if (notify)
|
||||||
notify(context, log.action == SuPolicy.ALLOW, log.appName)
|
notify(context, log.action >= SuPolicy.ALLOW, log.appName)
|
||||||
|
|
||||||
runBlocking { ServiceLocator.logRepo.insert(log) }
|
runBlocking { ServiceLocator.logRepo.insert(log) }
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ object SuCallbackHandler {
|
|||||||
pm.getPackageInfo(uid, pid)?.applicationInfo?.getLabel(pm)
|
pm.getPackageInfo(uid, pid)?.applicationInfo?.getLabel(pm)
|
||||||
}.getOrNull() ?: "[UID] $uid"
|
}.getOrNull() ?: "[UID] $uid"
|
||||||
|
|
||||||
notify(context, policy == SuPolicy.ALLOW, appName)
|
notify(context, policy >= SuPolicy.ALLOW, appName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notify(context: Context, granted: Boolean, appName: String) {
|
private fun notify(context: Context, granted: Boolean, appName: String) {
|
||||||
|
|||||||
@@ -82,7 +82,11 @@ class SuRequestHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun respond(action: Int, time: Long) {
|
suspend fun respond(action: Int, time: Long) {
|
||||||
policy.policy = action
|
if (action == SuPolicy.ALLOW && Config.suRestrict) {
|
||||||
|
policy.policy = SuPolicy.RESTRICT
|
||||||
|
} else {
|
||||||
|
policy.policy = action
|
||||||
|
}
|
||||||
if (time >= 0) {
|
if (time >= 0) {
|
||||||
policy.remain = TimeUnit.MINUTES.toSeconds(time)
|
policy.remain = TimeUnit.MINUTES.toSeconds(time)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class NetworkObserver(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun postValue(b: Boolean) {
|
private fun postValue(b: Boolean) {
|
||||||
Info.remote = Info.EMPTY_REMOTE
|
Info.resetUpdate()
|
||||||
Info.isConnected.postValue(b)
|
Info.isConnected.postValue(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class AdditionalTest : BaseTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testModuleCount() {
|
fun testModuleCount() {
|
||||||
var expected = 2
|
var expected = 3
|
||||||
if (Environment.mount()) expected++
|
if (Environment.mount()) expected++
|
||||||
if (Environment.preinit()) expected++
|
if (Environment.preinit()) expected++
|
||||||
if (Environment.lsposed()) expected++
|
if (Environment.lsposed()) expected++
|
||||||
@@ -90,8 +90,8 @@ class AdditionalTest : BaseTest {
|
|||||||
|
|
||||||
assertNotNull("$MOUNT_TEST is not installed", modules.find { it.id == MOUNT_TEST })
|
assertNotNull("$MOUNT_TEST is not installed", modules.find { it.id == MOUNT_TEST })
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"/system/etc/newfile should exist",
|
"/system/fonts/newfile should exist",
|
||||||
RootUtils.fs.getFile("/system/etc/newfile").exists()
|
RootUtils.fs.getFile("/system/fonts/newfile").exists()
|
||||||
)
|
)
|
||||||
assertFalse(
|
assertFalse(
|
||||||
"/system/bin/screenrecord should not exist",
|
"/system/bin/screenrecord should not exist",
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ class Environment : BaseTest {
|
|||||||
val error = "$MOUNT_TEST setup failed"
|
val error = "$MOUNT_TEST setup failed"
|
||||||
val path = root.getChildFile(MOUNT_TEST)
|
val path = root.getChildFile(MOUNT_TEST)
|
||||||
|
|
||||||
// Create /system/etc/newfile
|
// Create /system/fonts/newfile
|
||||||
val etc = path.getChildFile("system").getChildFile("etc")
|
val etc = path.getChildFile("system").getChildFile("fonts")
|
||||||
assertTrue(error, etc.mkdirs())
|
assertTrue(error, etc.mkdirs())
|
||||||
assertTrue(error, etc.getChildFile("newfile").createNewFile())
|
assertTrue(error, etc.getChildFile("newfile").createNewFile())
|
||||||
|
|
||||||
@@ -116,6 +116,10 @@ class Environment : BaseTest {
|
|||||||
assertTrue(error, Shell.cmd("set_default_perm $path").exec().isSuccess)
|
assertTrue(error, Shell.cmd("set_default_perm $path").exec().isSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupSystemlessHost() {
|
||||||
|
assertTrue("hosts setup failed", Shell.cmd("add_hosts_module").exec().isSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupSepolicyRuleModule(root: ExtendedFile) {
|
private fun setupSepolicyRuleModule(root: ExtendedFile) {
|
||||||
val error = "$SEPOLICY_RULE setup failed"
|
val error = "$SEPOLICY_RULE setup failed"
|
||||||
val path = root.getChildFile(SEPOLICY_RULE)
|
val path = root.getChildFile(SEPOLICY_RULE)
|
||||||
@@ -215,6 +219,7 @@ class Environment : BaseTest {
|
|||||||
val root = RootUtils.fs.getFile(Const.MODULE_PATH)
|
val root = RootUtils.fs.getFile(Const.MODULE_PATH)
|
||||||
if (mount()) { setupMountTest(root) }
|
if (mount()) { setupMountTest(root) }
|
||||||
if (preinit()) { setupSepolicyRuleModule(root) }
|
if (preinit()) { setupSepolicyRuleModule(root) }
|
||||||
|
setupSystemlessHost()
|
||||||
setupEmptyZygiskModule(root)
|
setupEmptyZygiskModule(root)
|
||||||
setupInvalidZygiskModule(root)
|
setupInvalidZygiskModule(root)
|
||||||
setupRemoveModule(root)
|
setupRemoveModule(root)
|
||||||
|
|||||||
252
app/core/src/main/res/values-b+sr+Latn/strings.xml
Normal file
252
app/core/src/main/res/values-b+sr+Latn/strings.xml
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
<resources>
|
||||||
|
<!--Author: Radoš Milićev (https://github.com/rammba)-->
|
||||||
|
|
||||||
|
<!--Sections-->
|
||||||
|
<string name="modules">Moduli</string>
|
||||||
|
<string name="superuser">Super-korisnik</string>
|
||||||
|
<string name="logs">Logovi</string>
|
||||||
|
<string name="settings">Podešavanja</string>
|
||||||
|
<string name="install">Instalacija</string>
|
||||||
|
<string name="section_home">Početno</string>
|
||||||
|
<string name="section_theme">Teme</string>
|
||||||
|
<string name="denylist">Lista zabrana</string>
|
||||||
|
|
||||||
|
<!--Home-->
|
||||||
|
<string name="no_connection">Nedostupna konekcija</string>
|
||||||
|
<string name="app_changelog">Promene u aplikaciji</string>
|
||||||
|
<string name="loading">Učitavanje…</string>
|
||||||
|
<string name="update">Ažuriranje</string>
|
||||||
|
<string name="not_available">N/A</string>
|
||||||
|
<string name="hide">Sakrij</string>
|
||||||
|
<string name="home_package">Paket</string>
|
||||||
|
<string name="home_app_title">Apl.</string>
|
||||||
|
|
||||||
|
<string name="home_notice_content">Preuzmite Magisk SAMO sa zvanične GitHub stranice. Fajlovi iz nepoznatih izvora mogu biti maliciozni!</string>
|
||||||
|
<string name="home_support_title">Podržite nas</string>
|
||||||
|
<string name="home_follow_title">Zapratite nas</string>
|
||||||
|
<string name="home_item_source">Izvor</string>
|
||||||
|
<string name="home_support_content">Magisk jeste i uvek će biti besplatan i open source. Možete pokazati da vam je stalo svojom donacijom.</string>
|
||||||
|
<string name="home_installed_version">Instalirano</string>
|
||||||
|
<string name="home_latest_version">Najnovije</string>
|
||||||
|
<string name="invalid_update_channel">Nevalidan kanal ažuriranja</string>
|
||||||
|
<string name="uninstall_magisk_title">Deinstaliraj Magisk</string>
|
||||||
|
<string name="uninstall_magisk_msg">Svi moduli će biti onemogućeni/uklonjeni!\nKoren će biti uklonjen!\nSvako neenkriptovano interno skladište će upotrebom Magisk-a biti ponovo enkriptovano!</string>
|
||||||
|
|
||||||
|
<!--Install-->
|
||||||
|
<string name="keep_force_encryption">Zadrži forsiranu enkripciju</string>
|
||||||
|
<string name="keep_dm_verity">Zadrži AVB 2.0/dm-verity</string>
|
||||||
|
<string name="recovery_mode">Režim oporavka</string>
|
||||||
|
<string name="install_options_title">Opcije</string>
|
||||||
|
<string name="install_method_title">Metod</string>
|
||||||
|
<string name="install_next">Naredno</string>
|
||||||
|
<string name="install_start">Počnimo</string>
|
||||||
|
<string name="manager_download_install">Pritisni da preuzmeš i instaliraš</string>
|
||||||
|
<string name="direct_install">Direktna instalacija (Preporučeno)</string>
|
||||||
|
<string name="install_inactive_slot">Instalacija na neaktivan slot (Nakon OTA)</string>
|
||||||
|
<string name="install_inactive_slot_msg">Vaš uređaj će biti FORSIRAN da se pokrene na trenutno neaktivnom slotu nakon ponovnog pokretanja!\nKoristite opciju samo kad se OTA završi.\nNastavi?</string>
|
||||||
|
<string name="setup_title">Dodatne postavke</string>
|
||||||
|
<string name="select_patch_file">Izaberite fajl</string>
|
||||||
|
<string name="patch_file_msg">Izaberite sliku (*.img) ili ODIN tarfile (*.tar) ili payload.bin (*.bin)</string>
|
||||||
|
<string name="reboot_delay_toast">Ponovo pokretanje za 5 sekundi…</string>
|
||||||
|
<string name="flash_screen_title">Instalacija</string>
|
||||||
|
|
||||||
|
<!--Superuser-->
|
||||||
|
<string name="su_request_title">Super-korisnički zahtev</string>
|
||||||
|
<string name="touch_filtered_warning">Magisk ne može da verifikuje vaš odgovor, jer aplikacija prikriva super-korisnički zahtev</string>
|
||||||
|
<string name="deny">Zabrani</string>
|
||||||
|
<string name="prompt">Zahtev</string>
|
||||||
|
<string name="grant">Dozvoli</string>
|
||||||
|
<string name="su_warning">Pruža potpun pristup vašem uređaju.\nZabranite ako niste sigurni!</string>
|
||||||
|
<string name="forever">Zauvek</string>
|
||||||
|
<string name="once">Jednom</string>
|
||||||
|
<string name="tenmin">10 min</string>
|
||||||
|
<string name="twentymin">20 min</string>
|
||||||
|
<string name="thirtymin">30 min</string>
|
||||||
|
<string name="sixtymin">60 min</string>
|
||||||
|
<string name="su_allow_toast">%1$s je dobio prava na super-korisnika</string>
|
||||||
|
<string name="su_deny_toast">%1$s nije dobio prava na super-korisnika</string>
|
||||||
|
<string name="su_snack_grant">Super-korisnička prava od %1$s su pružena</string>
|
||||||
|
<string name="su_snack_deny">Super-korisnička prava od %1$s su odbijena</string>
|
||||||
|
<string name="su_snack_notif_on">Notifikacije od %1$s su omogućene</string>
|
||||||
|
<string name="su_snack_notif_off">Notifikacije od %1$s su onemogućene</string>
|
||||||
|
<string name="su_snack_log_on">Logovanje za %1$s je omogućeno</string>
|
||||||
|
<string name="su_snack_log_off">Logovanje za %1$s je onemogućeno</string>
|
||||||
|
<string name="su_revoke_title">Opozovi?</string>
|
||||||
|
<string name="su_revoke_msg">Potvrdi da opozoveš prava na super-korisnika od %1$s?</string>
|
||||||
|
<string name="toast">Toast</string>
|
||||||
|
<string name="none">Ništa</string>
|
||||||
|
|
||||||
|
<string name="superuser_toggle_notification">Notifikacije</string>
|
||||||
|
<string name="superuser_toggle_revoke">Opozovi</string>
|
||||||
|
<string name="superuser_policy_none">Nijedna aplikacija nije tražila permisije za super-korisnika još uvek.</string>
|
||||||
|
|
||||||
|
<!--Logs-->
|
||||||
|
<string name="log_data_none">Nemate logova, pokušajte koristiti korenske aplikacije više</string>
|
||||||
|
<string name="log_data_magisk_none">Magisk logovi su prazni, to je čudno</string>
|
||||||
|
<string name="menuSaveLog">Sačuvaj log</string>
|
||||||
|
<string name="menuClearLog">Ukloni log</string>
|
||||||
|
<string name="logs_cleared">Log uspešno uklonjen</string>
|
||||||
|
<string name="pid">PID: %1$d</string>
|
||||||
|
<string name="target_uid">Ciljani UID: %1$d</string>
|
||||||
|
<string name="target_pid">Mount ns cinjani PID: %s</string>
|
||||||
|
<string name="selinux_context">SELinux kontekst: %s</string>
|
||||||
|
<string name="supp_group">Dopunska grupa: %s</string>
|
||||||
|
|
||||||
|
<!--SafetyNet-->
|
||||||
|
|
||||||
|
<!--MagiskHide-->
|
||||||
|
<string name="show_system_app">Prikaži sistemske apl.</string>
|
||||||
|
<string name="show_os_app">Prikaži apl. OS-a</string>
|
||||||
|
<string name="hide_filter_hint">Filtriraj po imenu</string>
|
||||||
|
<string name="hide_search">Pretraga</string>
|
||||||
|
|
||||||
|
<!--Module-->
|
||||||
|
<string name="no_info_provided">(Bez informacija)</string>
|
||||||
|
<string name="reboot_userspace">Lako ponovo pokretanje</string>
|
||||||
|
<string name="reboot_recovery">Ponovo pokreni za oporavak</string>
|
||||||
|
<string name="reboot_bootloader">Ponovo pokreni za bootloader</string>
|
||||||
|
<string name="reboot_download">Ponovo pokreni za preuzimanje</string>
|
||||||
|
<string name="reboot_edl">Ponovo pokreni za EDL</string>
|
||||||
|
<string name="reboot_safe_mode">Siguran mod</string>
|
||||||
|
<string name="module_version_author">%1$s od %2$s</string>
|
||||||
|
<string name="module_state_remove">Ukloni</string>
|
||||||
|
<string name="module_action">Akcija</string>
|
||||||
|
<string name="module_state_restore">Povrati</string>
|
||||||
|
<string name="module_action_install_external">Instaliraj iz skladišta</string>
|
||||||
|
<string name="update_available">Ažuriranje dostupno</string>
|
||||||
|
<string name="suspend_text_riru">Modul je suspendovan jer je %1$s omogućeno</string>
|
||||||
|
<string name="suspend_text_zygisk">Modul je suspendovan jer %1$s nije omogućeno</string>
|
||||||
|
<string name="zygisk_module_unloaded">Zygisk modul nije učitan zbog nekompatibilnosti</string>
|
||||||
|
<string name="module_empty">Nijedan modul nije instaliran</string>
|
||||||
|
<string name="confirm_install">Instaliraj modul %1$s?</string>
|
||||||
|
<string name="confirm_install_title">Potvrda instalacije</string>
|
||||||
|
|
||||||
|
<!--Settings-->
|
||||||
|
<string name="settings_dark_mode_title">Tema</string>
|
||||||
|
<string name="settings_dark_mode_message">Izaberite temu koja vam najviše odgovara!</string>
|
||||||
|
<string name="settings_dark_mode_light">Uvek svetlo</string>
|
||||||
|
<string name="settings_dark_mode_system">Prati sistem</string>
|
||||||
|
<string name="settings_dark_mode_dark">Uvek tamno</string>
|
||||||
|
<string name="settings_download_path_title">Putanja za preuzimanje</string>
|
||||||
|
<string name="settings_download_path_message">Fajlovi će biti sačuvani na %1$s</string>
|
||||||
|
<string name="settings_hide_app_title">Sakrij Magisk apl.</string>
|
||||||
|
<string name="settings_hide_app_summary">Instaliraj proxy aplikaciju sa nasumičnim ID-jem paketa i prilagođenom labelom</string>
|
||||||
|
<string name="settings_restore_app_title">Povrati Magisk apl.</string>
|
||||||
|
<string name="settings_restore_app_summary">Otkrij apl. i povrati originalni APK</string>
|
||||||
|
<string name="language">Jezik</string>
|
||||||
|
<string name="system_default">(Podrazumevano sistemski)</string>
|
||||||
|
<string name="settings_check_update_title">Proveri ažuriranja</string>
|
||||||
|
<string name="settings_check_update_summary">Periodično proveri ažuriranja u pozadini</string>
|
||||||
|
<string name="settings_update_channel_title">Kanal ažuriranja</string>
|
||||||
|
<string name="settings_update_stable">Stabilno</string>
|
||||||
|
<string name="settings_update_beta">Beta</string>
|
||||||
|
<string name="settings_update_custom">Prilagođeno</string>
|
||||||
|
<string name="settings_update_custom_msg">Unesi prilagođeni URL kanala</string>
|
||||||
|
<string name="settings_zygisk_summary">Pokreni delove Magisk-a u zygote daemon-u</string>
|
||||||
|
<string name="settings_denylist_title">Sprovedi listu zabrana</string>
|
||||||
|
<string name="settings_denylist_summary">Procesi na listi zabrana će povratiti sve Magisk izmene</string>
|
||||||
|
<string name="settings_denylist_config_title">Konfiguriši listu zabrana</string>
|
||||||
|
<string name="settings_denylist_config_summary">Izaberi procese koji će biti na listi zabrana</string>
|
||||||
|
<string name="settings_hosts_title">Bezsistemski domaćini (hosts)</string>
|
||||||
|
<string name="settings_hosts_summary">Podrška bezsistemskih domaćina za aplikacije blokiranja reklama</string>
|
||||||
|
<string name="settings_hosts_toast">Modul bezsistemskih domaćina dodat</string>
|
||||||
|
<string name="settings_app_name_hint">Novo ime</string>
|
||||||
|
<string name="settings_app_name_helper">Apl. će biti spakovana pod ovim imenom</string>
|
||||||
|
<string name="settings_app_name_error">Nevalidan format</string>
|
||||||
|
<string name="settings_su_app_adb">Aplikacije i ADB</string>
|
||||||
|
<string name="settings_su_app">Samo aplikacije</string>
|
||||||
|
<string name="settings_su_adb">Samo ADB</string>
|
||||||
|
<string name="settings_su_disable">Onemogućeno</string>
|
||||||
|
<string name="settings_su_request_10">10 sekundi</string>
|
||||||
|
<string name="settings_su_request_15">15 sekundi</string>
|
||||||
|
<string name="settings_su_request_20">20 sekundi</string>
|
||||||
|
<string name="settings_su_request_30">30 sekundi</string>
|
||||||
|
<string name="settings_su_request_45">45 sekundi</string>
|
||||||
|
<string name="settings_su_request_60">60 sekundi</string>
|
||||||
|
<string name="superuser_access">Pristup super-korisnika</string>
|
||||||
|
<string name="auto_response">Automatski odgovor</string>
|
||||||
|
<string name="request_timeout">Istek zahteva</string>
|
||||||
|
<string name="superuser_notification">Notifikacije super-korisnika</string>
|
||||||
|
<string name="settings_su_reauth_title">Ponovo odobri nakon ažuriranja</string>
|
||||||
|
<string name="settings_su_reauth_summary">Ponovo traži permisije super-korisnika nakon ažuriranja aplikacija</string>
|
||||||
|
<string name="settings_su_tapjack_title">Zaštita od tapjacking-a</string>
|
||||||
|
<string name="settings_su_tapjack_summary">Prompt dijalog super-korisnika neće reagovati dok je prikriven drugim prozorom ili overlay-em</string>
|
||||||
|
<string name="settings_su_auth_title">Autentifikacija korisnika</string>
|
||||||
|
<string name="settings_su_auth_summary">Traži autentifikaciju korisnika tokom zahteva super-korisnika</string>
|
||||||
|
<string name="settings_su_auth_insecure">Nijedan metod autentifikacije nije podešen na uređaju</string>
|
||||||
|
<string name="settings_customization">Prilagođavanje</string>
|
||||||
|
<string name="setting_add_shortcut_summary">Dodaj lepu prečicu na početni ekran u slučaju da se ime i ikonica ne prepoznaju lako nakon skrivanja aplikacije</string>
|
||||||
|
<string name="settings_doh_title">DNS preko HTTPS-a</string>
|
||||||
|
<string name="settings_doh_description">Zaobilazno rešenje DNS trovanja u nekim nacijama</string>
|
||||||
|
<string name="settings_random_name_title">Nasumično ime na izlazu</string>
|
||||||
|
<string name="settings_random_name_description">Nasumično ime izlaznog fajla slika i tar fajlova radi sprečavanja detekcije</string>
|
||||||
|
|
||||||
|
<string name="multiuser_mode">Višekorisnički režim</string>
|
||||||
|
<string name="settings_owner_only">Samo vlasnik uređaja</string>
|
||||||
|
<string name="settings_owner_manage">Određeno od strane vlasnika</string>
|
||||||
|
<string name="settings_user_independent">Nezavisno od korisnika</string>
|
||||||
|
<string name="owner_only_summary">Samo vlasnik ima pristup korenu</string>
|
||||||
|
<string name="owner_manage_summary">Samo vlasnik može da pristupa korenu i da prima zahteve za njega</string>
|
||||||
|
<string name="user_independent_summary">Svaki korisnik ima svoja pravila korena</string>
|
||||||
|
|
||||||
|
<string name="mount_namespace_mode">Mount režim namespace-a</string>
|
||||||
|
<string name="settings_ns_global">Globalni namespace</string>
|
||||||
|
<string name="settings_ns_requester">Nasleđeni namespace</string>
|
||||||
|
<string name="settings_ns_isolate">Izolovani namespace</string>
|
||||||
|
<string name="global_summary">Sve korenske sesije koriste globalni mount namespace</string>
|
||||||
|
<string name="requester_summary">Korenske sesije će naslediti namespace od podnosioca zahteva</string>
|
||||||
|
<string name="isolate_summary">Svaka korenska sesija će imati svoj izolovani namespace</string>
|
||||||
|
|
||||||
|
<!--Notifications-->
|
||||||
|
<string name="update_channel">Ažuriranja Magisk-a</string>
|
||||||
|
<string name="progress_channel">Notifikacije o progresu</string>
|
||||||
|
<string name="updated_channel">Ažuriranje završeno</string>
|
||||||
|
<string name="download_complete">Preuzimanje završeno</string>
|
||||||
|
<string name="download_file_error">Greška pri preuzimanju fajla</string>
|
||||||
|
<string name="magisk_update_title">Ažuriranje Magisk-a dostupno!</string>
|
||||||
|
<string name="updated_title">Magisk je ažuriran</string>
|
||||||
|
<string name="updated_text">Klikni da otvoriš aplikaciju</string>
|
||||||
|
|
||||||
|
<!--Toasts, Dialogs-->
|
||||||
|
<string name="yes">Da</string>
|
||||||
|
<string name="no">Ne</string>
|
||||||
|
<string name="repo_install_title">Instaliraj %1$s %2$s(%3$d)</string>
|
||||||
|
<string name="download">Preuzmi</string>
|
||||||
|
<string name="reboot">Ponovo pokreni</string>
|
||||||
|
<string name="close">Zatvori</string>
|
||||||
|
<string name="release_notes">Release notes</string>
|
||||||
|
<string name="flashing">Flešovanje…</string>
|
||||||
|
<string name="running">Pokretanje…</string>
|
||||||
|
<string name="done">Završeno!</string>
|
||||||
|
<string name="done_action">Pokretanje akcije %1$s završeno</string>
|
||||||
|
<string name="failure">Neuspešno!</string>
|
||||||
|
<string name="hide_app_title">Skrivanje Magisk aplikacije…</string>
|
||||||
|
<string name="open_link_failed_toast">Nije pronađena aplikacija za otvaranje linka</string>
|
||||||
|
<string name="complete_uninstall">Kompletna deinstalacija</string>
|
||||||
|
<string name="restore_img">Povrati slike</string>
|
||||||
|
<string name="restore_img_msg">Povratak…</string>
|
||||||
|
<string name="restore_done">Povratak uspešan!</string>
|
||||||
|
<string name="restore_fail">Fabrički bekap ne postoji!</string>
|
||||||
|
<string name="setup_fail">Neuspešna postavka</string>
|
||||||
|
<string name="env_fix_title">Potrebno dodatno podešavanje</string>
|
||||||
|
<string name="env_fix_msg">Vaš uređaj zahteva dodatno podešavanje da bi Magisk radio kako treba. Da li želite nastaviti i pokrenuti ponovo?</string>
|
||||||
|
<string name="env_full_fix_msg">Vaš uređaj zahteva ponovno flešovanje da bi Magisk radio kako treba. Reinstalirajte Magisk kroz aplikaciju, režim oporavka ne može dobiti tačne informacije o uređaju.</string>
|
||||||
|
<string name="setup_msg">Pokretanje podešavanja okruženja…</string>
|
||||||
|
<string name="unsupport_magisk_title">Nepodržana verzija Magisk-a</string>
|
||||||
|
<string name="unsupport_magisk_msg">Ova verzija aplikacije ne podržava Magisk verzije manje od %1$s.\n\nAplikacija će se ponašati kao da Magisk nije instaliran, molimo ažurirajte Magisk što pre.</string>
|
||||||
|
<string name="unsupport_general_title">Nenormalno stanje</string>
|
||||||
|
<string name="unsupport_system_app_msg">Pokretanje aplikacije kao sistemske nije podržano. Molimo postavite aplikaciju da bude korisnička.</string>
|
||||||
|
<string name="unsupport_other_su_msg">Detektovan \"su\" binary koji nije Magisk-ov. Molimo uklonite konkurentno korensko rešenje i/ili reinstalirajte Magisk.</string>
|
||||||
|
<string name="unsupport_external_storage_msg">Magisk je instaliran na eksterno skladište. Molimo pomerite apl. u interno skladište.</string>
|
||||||
|
<string name="unsupport_nonroot_stub_msg">Skrivena Magisk aplikacija ne može nastaviti sa radom jer je koren izgubljen. Molimo povratite originalni APK.</string>
|
||||||
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
|
<string name="external_rw_permission_denied">Dozvolite permisiju za skladište da biste omogućili ovu funkcionalnost</string>
|
||||||
|
<string name="post_notifications_denied">Dozvolite permisiju za notifikacije da biste omogućili ovu funkcionalnost</string>
|
||||||
|
<string name="install_unknown_denied">Dozvolite "instaliranje nepoznatih aplikacija" da biste omogućili ovu funkcionalnost</string>
|
||||||
|
<string name="add_shortcut_title">Dodaj prečicu na početni ekran</string>
|
||||||
|
<string name="add_shortcut_msg">Nakon skrivanja aplikacije, njeno ime i ikonicu ćete teško prepoznati. Želite li dodati lepu prečicu na početni ekran?</string>
|
||||||
|
<string name="app_not_found">Nije pronađena aplikacija za ovu akciju</string>
|
||||||
|
<string name="reboot_apply_change">Ponovo pokreni da primeniš izmene</string>
|
||||||
|
<string name="restore_app_confirmation">Ovo će vratiti skrivenu aplikaciju na originalnu. Da li stvarno to želite?</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<!--Sections-->
|
<!--Sections-->
|
||||||
<string name="modules">מודולים</string>
|
<string name="modules">מודולים</string>
|
||||||
<string name="superuser">משתמש על</string>
|
<string name="superuser">משתמש על</string>
|
||||||
<string name="logs">יומני רישום</string>
|
<string name="logs">Log</string>
|
||||||
<string name="settings">הגדרות</string>
|
<string name="settings">הגדרות</string>
|
||||||
<string name="install">התקנה</string>
|
<string name="install">התקנה</string>
|
||||||
<string name="section_home">בית</string>
|
<string name="section_home">בית</string>
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
|
|
||||||
<!--Home-->
|
<!--Home-->
|
||||||
<string name="no_connection">אין חיבור זמין</string>
|
<string name="no_connection">אין חיבור זמין</string>
|
||||||
<string name="app_changelog">יומן שינויים</string>
|
<string name="app_changelog">רשימת שינויים</string>
|
||||||
<string name="loading">טוען…</string>
|
<string name="loading">טוען…</string>
|
||||||
<string name="update">עדכון</string>
|
<string name="update">עדכון</string>
|
||||||
<string name="not_available">ל/ז</string>
|
<string name="not_available">לא זמין</string>
|
||||||
<string name="hide">הסתרה</string>
|
<string name="hide">הסתרה</string>
|
||||||
<string name="home_package">חבילה</string>
|
<string name="home_package">חבילה</string>
|
||||||
<string name="home_app_title">יישום</string>
|
<string name="home_app_title">יישום</string>
|
||||||
@@ -23,28 +23,28 @@
|
|||||||
<string name="home_support_title">תמיכה בנו</string>
|
<string name="home_support_title">תמיכה בנו</string>
|
||||||
<string name="home_follow_title">עקבו אחרינו</string>
|
<string name="home_follow_title">עקבו אחרינו</string>
|
||||||
<string name="home_item_source">מקור</string>
|
<string name="home_item_source">מקור</string>
|
||||||
<string name="home_support_content">Magisk היה ותמיד יהיה בעל קוד מקור פתוח. עם זאת באפשרותך להראות לנו שאכפת לך על ידי שליחת תרומה קטנה.</string>
|
<string name="home_support_content">Magisk היה ותמיד יהיה בקוד פתוח. עם זאת באפשרותך להראות לנו שאכפת לך על ידי שליחת תרומה קטנה.</string>
|
||||||
<string name="home_installed_version">מותקנת</string>
|
<string name="home_installed_version">מותקנת</string>
|
||||||
<string name="home_latest_version">אחרונה</string>
|
<string name="home_latest_version">אחרונה</string>
|
||||||
<string name="invalid_update_channel">ערוץ עדכון לא חוקי</string>
|
<string name="invalid_update_channel">ערוץ עדכון לא חוקי</string>
|
||||||
<string name="uninstall_magisk_title">הסרת Magisk</string>
|
<string name="uninstall_magisk_title">הסרת Magisk</string>
|
||||||
<string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת שורש תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string>
|
<string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת Root תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string>
|
||||||
|
|
||||||
<!--Install-->
|
<!--Install-->
|
||||||
<string name="keep_force_encryption">שמירה על הצפנה בכח</string>
|
<string name="keep_force_encryption">שמירה על הצפנה בכח</string>
|
||||||
<string name="keep_dm_verity">שמירה על AVB 2.0/dm-verity</string>
|
<string name="keep_dm_verity">שמירה על AVB 2.0/dm-verity</string>
|
||||||
<string name="recovery_mode">מצב שחזור</string>
|
<string name="recovery_mode">מצב Recovery</string>
|
||||||
<string name="install_options_title">אפשרויות</string>
|
<string name="install_options_title">אפשרויות</string>
|
||||||
<string name="install_method_title">שיטה</string>
|
<string name="install_method_title">שיטה</string>
|
||||||
<string name="install_next">הבא</string>
|
<string name="install_next">הבא</string>
|
||||||
<string name="install_start">צא לדרך</string>
|
<string name="install_start">צא לדרך</string>
|
||||||
<string name="manager_download_install">לחיצה להורדה והתקנה</string>
|
<string name="manager_download_install">לחיצה להורדה והתקנה</string>
|
||||||
<string name="direct_install">התקנה ישירה (מומלץ)</string>
|
<string name="direct_install">התקנה ישירה (מומלץ)</string>
|
||||||
<string name="install_inactive_slot">התקנה לחריץ לא פעיל (לאחר OTA)</string>
|
<string name="install_inactive_slot">התקנה לסלוט לא פעיל (לאחר OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לחריץ הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
|
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לסלוט הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
|
||||||
<string name="setup_title">התקנה נוספת</string>
|
<string name="setup_title">התקנה נוספת</string>
|
||||||
<string name="select_patch_file">בחירה והתקנת קובץ</string>
|
<string name="select_patch_file">בחירה והתקנת קובץ</string>
|
||||||
<string name="patch_file_msg">בחירת תמונה גולמית (*.img) או ODIN tarfile (*.tar) או payload.bin (*.bin)</string>
|
<string name="patch_file_msg">בחירת קובץ גולמי (*.img) או ODIN tarfile (*.tar) או payload.bin (*.bin)</string>
|
||||||
<string name="reboot_delay_toast">מאתחל בעוד 5 שניות…</string>
|
<string name="reboot_delay_toast">מאתחל בעוד 5 שניות…</string>
|
||||||
<string name="flash_screen_title">התקנה</string>
|
<string name="flash_screen_title">התקנה</string>
|
||||||
|
|
||||||
@@ -67,22 +67,22 @@
|
|||||||
<string name="su_snack_deny">הרשאות משתמש על עבור %1$s נשללו</string>
|
<string name="su_snack_deny">הרשאות משתמש על עבור %1$s נשללו</string>
|
||||||
<string name="su_snack_notif_on">התראות של %1$s מופעלות</string>
|
<string name="su_snack_notif_on">התראות של %1$s מופעלות</string>
|
||||||
<string name="su_snack_notif_off">התראות של %1$s מושבתות</string>
|
<string name="su_snack_notif_off">התראות של %1$s מושבתות</string>
|
||||||
<string name="su_snack_log_on">יומני רישום עבור %1$s פועלות</string>
|
<string name="su_snack_log_on">Log עבור %1$s מופעל</string>
|
||||||
<string name="su_snack_log_off">יומני רישום עבור %1$s מושבתות</string>
|
<string name="su_snack_log_off">Log עבור %1$s מושבת</string>
|
||||||
<string name="su_revoke_title">להסיר?</string>
|
<string name="su_revoke_title">להסיר?</string>
|
||||||
<string name="su_revoke_msg">נא לאשר שלילת הרשאות עבור %1$s?</string>
|
<string name="su_revoke_msg">נא לאשר שלילת הרשאות עבור %1$s?</string>
|
||||||
<string name="toast">הרמת כוסית</string>
|
<string name="toast">התראה</string>
|
||||||
<string name="none">ללא</string>
|
<string name="none">ללא</string>
|
||||||
<string name="superuser_toggle_notification">התראות</string>
|
<string name="superuser_toggle_notification">התראות</string>
|
||||||
<string name="superuser_toggle_revoke">הסרה</string>
|
<string name="superuser_toggle_revoke">הסרה</string>
|
||||||
<string name="superuser_policy_none">טרם נתבקשו הרשאות משתמש על על ידי יישומים</string>
|
<string name="superuser_policy_none">טרם נתבקשו הרשאות משתמש על על ידי יישומים</string>
|
||||||
|
|
||||||
<!--Logs-->
|
<!--Logs-->
|
||||||
<string name="log_data_none">הינך ללא יומן, יש לנסות להשתמש יותר ביישומי השורש שלך</string>
|
<string name="log_data_none">אין Log, יש לנסות להשתמש יותר ביישומי הRoot שלך</string>
|
||||||
<string name="log_data_magisk_none">יומני רישום Magisk ריקים, זה מוזר</string>
|
<string name="log_data_magisk_none">Log Magisk ריק, זה מוזר</string>
|
||||||
<string name="menuSaveLog">שמירת יומן רישום</string>
|
<string name="menuSaveLog">שמירת Log</string>
|
||||||
<string name="menuClearLog">ניקוי יומן רישום כעת</string>
|
<string name="menuClearLog">ניקוי Log כעת</string>
|
||||||
<string name="logs_cleared">יומני רישום נוקו בהצלחה</string>
|
<string name="logs_cleared">Log נוקה בהצלחה</string>
|
||||||
<string name="pid">PID: %1$d</string>
|
<string name="pid">PID: %1$d</string>
|
||||||
<string name="target_uid">יעד UID: %1$d</string>
|
<string name="target_uid">יעד UID: %1$d</string>
|
||||||
<string name="target_pid">מציב ns יעד PID: %s</string>
|
<string name="target_pid">מציב ns יעד PID: %s</string>
|
||||||
@@ -100,15 +100,15 @@
|
|||||||
<!--Module-->
|
<!--Module-->
|
||||||
<string name="no_info_provided">(לא סופק מידע)</string>
|
<string name="no_info_provided">(לא סופק מידע)</string>
|
||||||
<string name="reboot_userspace">אתחול רך</string>
|
<string name="reboot_userspace">אתחול רך</string>
|
||||||
<string name="reboot_recovery">אתחול למצב שחזור</string>
|
<string name="reboot_recovery">אתחול למצב Recovery</string>
|
||||||
<string name="reboot_bootloader">אתחול לטוען האתחול</string>
|
<string name="reboot_bootloader">אתחול לBootloader</string>
|
||||||
<string name="reboot_download">אתחול למצב הורדה</string>
|
<string name="reboot_download">אתחול למצב הורדה</string>
|
||||||
<string name="reboot_edl">אתחול למצב EDL</string>
|
<string name="reboot_edl">אתחול למצב EDL</string>
|
||||||
<string name="reboot_safe_mode">מצב בטוח</string>
|
<string name="reboot_safe_mode">מצב בטוח</string>
|
||||||
<string name="module_version_author">%1$s מאת %2$s</string>
|
<string name="module_version_author">%1$s מאת %2$s</string>
|
||||||
<string name="module_state_remove">הסרה</string>
|
<string name="module_state_remove">הסרה</string>
|
||||||
<string name="module_action">פעולה</string>
|
<string name="module_action">פעולה</string>
|
||||||
<string name="module_state_restore">שחזור</string>
|
<string name="module_state_restore">שיחזור</string>
|
||||||
<string name="module_action_install_external">התקנה מהאחסון</string>
|
<string name="module_action_install_external">התקנה מהאחסון</string>
|
||||||
<string name="update_available">עדכונים זמינים</string>
|
<string name="update_available">עדכונים זמינים</string>
|
||||||
<string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string>
|
<string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string>
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
<string name="settings_hide_app_title">הסתרת היישום Magisk</string>
|
<string name="settings_hide_app_title">הסתרת היישום Magisk</string>
|
||||||
<string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
|
<string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
|
||||||
<string name="settings_restore_app_title">שיחזור היישום Magisk</string>
|
<string name="settings_restore_app_title">שיחזור היישום Magisk</string>
|
||||||
<string name="settings_restore_app_summary">ביטול הסתרת היישום ושחזור אל ה-APK המקורי</string>
|
<string name="settings_restore_app_summary">ביטול הסתרת היישום ושיחזור אל ה-APK המקורי</string>
|
||||||
<string name="language">שפה</string>
|
<string name="language">שפה</string>
|
||||||
<string name="system_default">(ברירת מחדל מערכת)</string>
|
<string name="system_default">(ברירת מחדל מערכת)</string>
|
||||||
<string name="settings_check_update_title">בדיקת עדכונים</string>
|
<string name="settings_check_update_title">בדיקת עדכונים</string>
|
||||||
@@ -144,9 +144,9 @@
|
|||||||
<string name="settings_denylist_summary">כל השינויים של Magisk יוחזרו לתהליכים ברשימת הדחייה</string>
|
<string name="settings_denylist_summary">כל השינויים של Magisk יוחזרו לתהליכים ברשימת הדחייה</string>
|
||||||
<string name="settings_denylist_config_title">הגדרת רשימת הדחייה</string>
|
<string name="settings_denylist_config_title">הגדרת רשימת הדחייה</string>
|
||||||
<string name="settings_denylist_config_summary">בחירת התהליכים שייכללו ברשימת הדחייה</string>
|
<string name="settings_denylist_config_summary">בחירת התהליכים שייכללו ברשימת הדחייה</string>
|
||||||
<string name="settings_hosts_title">מארחים חסרי מערכת</string>
|
<string name="settings_hosts_title">hosts חסרי מערכת</string>
|
||||||
<string name="settings_hosts_summary">מארחים חסרי מערכת תומכים ביישומים חוסמי פרסומות</string>
|
<string name="settings_hosts_summary">hosts חסרי מערכת תומכים ביישומים חוסמי פרסומות</string>
|
||||||
<string name="settings_hosts_toast">הוספת מודול מארחים חסרי מערכת</string>
|
<string name="settings_hosts_toast">הוספת מודול hosts חסרי מערכת</string>
|
||||||
<string name="settings_app_name_hint">שם חדש</string>
|
<string name="settings_app_name_hint">שם חדש</string>
|
||||||
<string name="settings_app_name_helper">היישום יארז מחדש בשם זה</string>
|
<string name="settings_app_name_helper">היישום יארז מחדש בשם זה</string>
|
||||||
<string name="settings_app_name_error">פורמט לא חוקי</string>
|
<string name="settings_app_name_error">פורמט לא חוקי</string>
|
||||||
@@ -181,16 +181,16 @@
|
|||||||
<string name="settings_owner_only">בעל ההתקן בלבד</string>
|
<string name="settings_owner_only">בעל ההתקן בלבד</string>
|
||||||
<string name="settings_owner_manage">אחראי ניהול ההתקן</string>
|
<string name="settings_owner_manage">אחראי ניהול ההתקן</string>
|
||||||
<string name="settings_user_independent">משתמש עצמאי</string>
|
<string name="settings_user_independent">משתמש עצמאי</string>
|
||||||
<string name="owner_only_summary">לבעלים בלבד ישנה גישת שורש</string>
|
<string name="owner_only_summary">לבעלים בלבד ישנה גישת Root</string>
|
||||||
<string name="owner_manage_summary">הבעלים בלבד יכול לנהל גישת שורש ולקבל הנחיות לבקשה</string>
|
<string name="owner_manage_summary">הבעלים בלבד יכול לנהל גישת Root ולקבל הנחיות לבקשה</string>
|
||||||
<string name="user_independent_summary">לכל משתמש יש כללי שורש נפרדים משלו</string>
|
<string name="user_independent_summary">לכל משתמש יש כללי Root נפרדים משלו</string>
|
||||||
<string name="mount_namespace_mode">מצב הצבת מרחב שם</string>
|
<string name="mount_namespace_mode">מצב הצבת מרחב שם</string>
|
||||||
<string name="settings_ns_global">מרחב שם גלובלי</string>
|
<string name="settings_ns_global">מרחב שם גלובלי</string>
|
||||||
<string name="settings_ns_requester">מרחב שם מורש</string>
|
<string name="settings_ns_requester">מרחב שם מורש</string>
|
||||||
<string name="settings_ns_isolate">מרחב שם מבודד</string>
|
<string name="settings_ns_isolate">מרחב שם מבודד</string>
|
||||||
<string name="global_summary">כלל חיבורי השורש משתמשים במרחב שם הגלובלי</string>
|
<string name="global_summary">כלל חיבורי הRoot משתמשים במרחב שם הגלובלי</string>
|
||||||
<string name="requester_summary">חיבורי השורש יירשו את מרחב השם של המבקש</string>
|
<string name="requester_summary">חיבורי הRoot יירשו את מרחב השם של המבקש</string>
|
||||||
<string name="isolate_summary">לכל חיבור שורש יהיה מרחב שם מבודד</string>
|
<string name="isolate_summary">לכל חיבור Root יהיה מרחב שם מבודד</string>
|
||||||
|
|
||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="update_channel">עדכוני Magisk</string>
|
<string name="update_channel">עדכוני Magisk</string>
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
<string name="setup_fail">ההתקנה כשלה</string>
|
<string name="setup_fail">ההתקנה כשלה</string>
|
||||||
<string name="env_fix_title">דורש התקנה נוספת</string>
|
<string name="env_fix_title">דורש התקנה נוספת</string>
|
||||||
<string name="env_fix_msg">ההתקן שלך זקוק להתקנה נוספת כדי ש-Magisk יפעל כראוי. האם ברצונך להמשיך ולהפעיל מחדש?</string>
|
<string name="env_fix_msg">ההתקן שלך זקוק להתקנה נוספת כדי ש-Magisk יפעל כראוי. האם ברצונך להמשיך ולהפעיל מחדש?</string>
|
||||||
<string name="env_full_fix_msg">ההתקן שלך זקוק לצריבה מחדש של Magisk כדי לעבוד כראוי. נא להתקין מחדש את Magisk בתוך היישום, מצב השחזור אינו יכול לקבל מידע נכון על ההתקן.</string>
|
<string name="env_full_fix_msg">ההתקן שלך זקוק לצריבה מחדש של Magisk כדי לעבוד כראוי. נא להתקין מחדש את Magisk בתוך היישום, מצב הRecovery אינו יכול לקבל מידע נכון על ההתקן.</string>
|
||||||
<string name="setup_msg">הגדרת סביבת ריצה…</string>
|
<string name="setup_msg">הגדרת סביבת ריצה…</string>
|
||||||
<string name="unsupport_magisk_title">גרסת Magisk אינה נתמכת</string>
|
<string name="unsupport_magisk_title">גרסת Magisk אינה נתמכת</string>
|
||||||
<string name="unsupport_magisk_msg">גרסה זו של היישום אינה תומכת ביישום Magisk הנמוך מ- %1$s.\n\nהיישום יתנהג כאילו Magisk אינו מותקן,יש לשדרג את Magisk במהירות האפשריות.</string>
|
<string name="unsupport_magisk_msg">גרסה זו של היישום אינה תומכת ביישום Magisk הנמוך מ- %1$s.\n\nהיישום יתנהג כאילו Magisk אינו מותקן,יש לשדרג את Magisk במהירות האפשריות.</string>
|
||||||
@@ -233,7 +233,7 @@
|
|||||||
<string name="unsupport_system_app_msg">הפעלת יישום זה כיישום מערכת אינה נתמך. נא להשיב את היישום כיישום משתמש.</string>
|
<string name="unsupport_system_app_msg">הפעלת יישום זה כיישום מערכת אינה נתמך. נא להשיב את היישום כיישום משתמש.</string>
|
||||||
<string name="unsupport_other_su_msg">התגלתה פקודת \"su\" שאינה שייכת ליישום Magisk נא להסיר את הפקודה שאינה נתמכת.</string>
|
<string name="unsupport_other_su_msg">התגלתה פקודת \"su\" שאינה שייכת ליישום Magisk נא להסיר את הפקודה שאינה נתמכת.</string>
|
||||||
<string name="unsupport_external_storage_msg">Magisk מותקן באחסון החיצוני. נא להעביר את היישום לאחסון הפנימי.</string>
|
<string name="unsupport_external_storage_msg">Magisk מותקן באחסון החיצוני. נא להעביר את היישום לאחסון הפנימי.</string>
|
||||||
<string name="unsupport_nonroot_stub_msg">היישום אינו יכול להמשיך לעבוד במצב הנסתר מכיוון שגישת השורש אבדה. נא לשחזר אותו חזרה ל-APK המקורי.</string>
|
<string name="unsupport_nonroot_stub_msg">היישום אינו יכול להמשיך לעבוד במצב הנסתר מכיוון שגישת הRoot אבדה. נא לשחזר אותו חזרה ל-APK המקורי.</string>
|
||||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
<string name="external_rw_permission_denied">הענת הרשאת אחסון להפעלת פונקציה זו</string>
|
<string name="external_rw_permission_denied">הענת הרשאת אחסון להפעלת פונקציה זו</string>
|
||||||
<string name="post_notifications_denied">הענקת הרשאה להתראות כדי להפעיל פונקציה זו</string>
|
<string name="post_notifications_denied">הענקת הרשאה להתראות כדי להפעיל פונקציה זו</string>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
<string name="deny">Negar</string>
|
<string name="deny">Negar</string>
|
||||||
<string name="prompt">Perguntar</string>
|
<string name="prompt">Perguntar</string>
|
||||||
<string name="grant">Permitir</string>
|
<string name="grant">Permitir</string>
|
||||||
<string name="su_warning">Permite acesso total ao seu aparelho.\nNão permita se você não tiver certeza do que está fazendo!</string>
|
<string name="su_warning">Permite acesso total ao seu dispositivo.\nNão permita se você não tiver certeza do que está fazendo!</string>
|
||||||
<string name="forever">Sempre</string>
|
<string name="forever">Sempre</string>
|
||||||
<string name="once">Uma vez</string>
|
<string name="once">Uma vez</string>
|
||||||
<string name="tenmin">10 mins</string>
|
<string name="tenmin">10 mins</string>
|
||||||
@@ -63,19 +63,19 @@
|
|||||||
<string name="sixtymin">60 mins</string>
|
<string name="sixtymin">60 mins</string>
|
||||||
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
|
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
|
||||||
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
|
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
|
||||||
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram concedidos</string>
|
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
|
||||||
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
|
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
|
||||||
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
|
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
|
||||||
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
|
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
|
||||||
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
|
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
|
||||||
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
|
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
|
||||||
<string name="su_revoke_title">Revogar?</string>
|
<string name="su_revoke_title">Revogar?</string>
|
||||||
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
|
<string name="su_revoke_msg">Confirme para revogar os acessos de SuperUsuário de %1$s</string>
|
||||||
<string name="toast">Notificação (Pop-up)</string>
|
<string name="toast">Notificação (Pop-up)</string>
|
||||||
<string name="none">Nenhum</string>
|
<string name="none">Nenhum</string>
|
||||||
<string name="superuser_toggle_notification">Notificações</string>
|
<string name="superuser_toggle_notification">Notificações</string>
|
||||||
<string name="superuser_toggle_revoke">Revogar</string>
|
<string name="superuser_toggle_revoke">Revogar</string>
|
||||||
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
|
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
|
||||||
|
|
||||||
<!--Logs-->
|
<!--Logs-->
|
||||||
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
|
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
|
||||||
@@ -135,6 +135,7 @@
|
|||||||
<string name="settings_update_channel_title">Canal de atualização</string>
|
<string name="settings_update_channel_title">Canal de atualização</string>
|
||||||
<string name="settings_update_stable">Estável</string>
|
<string name="settings_update_stable">Estável</string>
|
||||||
<string name="settings_update_beta">Beta</string>
|
<string name="settings_update_beta">Beta</string>
|
||||||
|
<string name="settings_update_debug">Debug</string>
|
||||||
<string name="settings_update_custom">Personalizado</string>
|
<string name="settings_update_custom">Personalizado</string>
|
||||||
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
|
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
|
||||||
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
|
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
|
||||||
@@ -235,7 +236,7 @@
|
|||||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
|
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
|
||||||
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
|
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
|
||||||
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
|
<string name="install_unknown_denied">Permita a opção \"Instalar apps de fontes desconhecidas\" para ativar esta funcionalidade</string>
|
||||||
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
|
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
|
||||||
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
||||||
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
|
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<!--Sections-->
|
<!--Sections-->
|
||||||
<string name="modules">Módulos</string>
|
<string name="modules">Módulos</string>
|
||||||
<string name="superuser">SuperUsuário</string>
|
<string name="superuser">SuperUsuário</string>
|
||||||
<string name="logs">Registros</string>
|
<string name="logs">Registos</string>
|
||||||
<string name="settings">Configurações</string>
|
<string name="settings">Configurações</string>
|
||||||
<string name="install">Instalar</string>
|
<string name="install">Instalar</string>
|
||||||
<string name="section_home">Início</string>
|
<string name="section_home">Início</string>
|
||||||
@@ -11,50 +11,50 @@
|
|||||||
<string name="denylist">Lista de negação</string>
|
<string name="denylist">Lista de negação</string>
|
||||||
|
|
||||||
<!--Home-->
|
<!--Home-->
|
||||||
<string name="no_connection">Nenhuma conexão disponível</string>
|
<string name="no_connection">Nenhuma ligação disponível</string>
|
||||||
<string name="app_changelog">Registro de alterações</string>
|
<string name="app_changelog">Registo de alterações</string>
|
||||||
<string name="loading">Carregando…</string>
|
<string name="loading">A carregar…</string>
|
||||||
<string name="update">Atualizar</string>
|
<string name="update">Atualizar</string>
|
||||||
<string name="not_available">Não disponível</string>
|
<string name="not_available">Não disponível</string>
|
||||||
<string name="hide">Ocultar</string>
|
<string name="hide">Ocultar</string>
|
||||||
<string name="home_package">Pacote</string>
|
<string name="home_package">Pacote</string>
|
||||||
<string name="home_app_title">App</string>
|
<string name="home_app_title">App</string>
|
||||||
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do GitHub. Arquivos de fontes desconhecidas podem ser maliciosos!</string>
|
<string name="home_notice_content">Descarregue o Magisk APENAS na página oficial do GitHub. Os ficheiros de fontes desconhecidas podem ser maliciosos!</string>
|
||||||
<string name="home_support_title">Apoie-nos</string>
|
<string name="home_support_title">Apoie-nos</string>
|
||||||
<string name="home_follow_title">Siga-nos</string>
|
<string name="home_follow_title">Siga-nos</string>
|
||||||
<string name="home_item_source">Fonte</string>
|
<string name="home_item_source">Fonte</string>
|
||||||
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação.</string>
|
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode ajudar-nos enviando uma pequena doação.</string>
|
||||||
<string name="home_installed_version">Instalado</string>
|
<string name="home_installed_version">Instalado</string>
|
||||||
<string name="home_latest_version">Recente</string>
|
<string name="home_latest_version">Recente</string>
|
||||||
<string name="invalid_update_channel">Canal de atualização inválido</string>
|
<string name="invalid_update_channel">Canal de atualização inválido</string>
|
||||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||||
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nSeus dados não criptografados devido ao uso do Magisk, serão re-criptografados!</string>
|
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nOs seus dados não encriptados devido à utilização do Magisk, serão re-encriptados!</string>
|
||||||
|
|
||||||
<!--Install-->
|
<!--Install-->
|
||||||
<string name="keep_force_encryption">Manter criptografia forçada</string>
|
<string name="keep_force_encryption">Manter encriptação forçada</string>
|
||||||
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
|
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
|
||||||
<string name="recovery_mode">Modo Recovery</string>
|
<string name="recovery_mode">Modo Recovery</string>
|
||||||
<string name="install_options_title">Opções</string>
|
<string name="install_options_title">Opções</string>
|
||||||
<string name="install_method_title">Método</string>
|
<string name="install_method_title">Método</string>
|
||||||
<string name="install_next">Próximo</string>
|
<string name="install_next">Próximo</string>
|
||||||
<string name="install_start">Vamos lá</string>
|
<string name="install_start">Vamos lá</string>
|
||||||
<string name="manager_download_install">Toque para baixar e instalar</string>
|
<string name="manager_download_install">Toque para descarregar e instalar</string>
|
||||||
<string name="direct_install">Instalação direta (recomendada)</string>
|
<string name="direct_install">Instalação direta (recomendada)</string>
|
||||||
<string name="install_inactive_slot">Instalar no slot inativo (após o OTA)</string>
|
<string name="install_inactive_slot">Instalar no slot inativo (após o OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">Seu dispositivo será FORÇADO a inicializar no slot inativo atual após uma reinicialização!\nSó use esta opção após a conclusão do OTA.\nDeseja continuar?</string>
|
<string name="install_inactive_slot_msg">O seu dispositivo será FORÇADO a inicializar no slot inativo atual após um reinício!\nSó use esta opção após a conclusão do OTA.\nDeseja continuar?</string>
|
||||||
<string name="setup_title">Configuração adicional</string>
|
<string name="setup_title">Configuração adicional</string>
|
||||||
<string name="select_patch_file">Selecione e corrija um arquivo</string>
|
<string name="select_patch_file">Selecione e corrija um ficheiro</string>
|
||||||
<string name="patch_file_msg">Selecione um arquivo imagem (*.img) ou um arquivo tar (*.tar) ou um arquivo payload.bin (*.bin)</string>
|
<string name="patch_file_msg">Selecione um ficheiro de imagem (*.img) ou um ficheiro tar (*.tar) ou um ficheiro payload.bin (*.bin)</string>
|
||||||
<string name="reboot_delay_toast">Reiniciando em 5 segundos…</string>
|
<string name="reboot_delay_toast">A reiniciar em 5 segundos…</string>
|
||||||
<string name="flash_screen_title">Instalação</string>
|
<string name="flash_screen_title">Instalação</string>
|
||||||
|
|
||||||
<!--Superuser-->
|
<!--Superuser-->
|
||||||
<string name="su_request_title">Solicitação de SuperUsuário</string>
|
<string name="su_request_title">Solicitação de SuperUsuário</string>
|
||||||
<string name="touch_filtered_warning">Como um app está ocultando uma solicitação de SuperUsuário, o Magisk não pode verificar sua resposta.</string>
|
<string name="touch_filtered_warning">Como um app está a ocultar um pedido de SuperUsuário, o Magisk não consegue verificar a sua resposta.</string>
|
||||||
<string name="deny">Negar</string>
|
<string name="deny">Negar</string>
|
||||||
<string name="prompt">Perguntar</string>
|
<string name="prompt">Perguntar</string>
|
||||||
<string name="grant">Permitir</string>
|
<string name="grant">Permitir</string>
|
||||||
<string name="su_warning">Permite acesso total ao seu aparelho.\nNão permita se você não tiver certeza do que está fazendo!</string>
|
<string name="su_warning">Permite o acesso total ao seu dispositivo.\nNão o permita se não tiver a certeza do que está a fazer!</string>
|
||||||
<string name="forever">Sempre</string>
|
<string name="forever">Sempre</string>
|
||||||
<string name="once">Uma vez</string>
|
<string name="once">Uma vez</string>
|
||||||
<string name="tenmin">10 mins</string>
|
<string name="tenmin">10 mins</string>
|
||||||
@@ -63,26 +63,26 @@
|
|||||||
<string name="sixtymin">60 mins</string>
|
<string name="sixtymin">60 mins</string>
|
||||||
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
|
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
|
||||||
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
|
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
|
||||||
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram concedidos</string>
|
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
|
||||||
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
|
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
|
||||||
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
|
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
|
||||||
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
|
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
|
||||||
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
|
<string name="su_snack_log_on">Os registos de %1$s foram ativados</string>
|
||||||
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
|
<string name="su_snack_log_off">Os registos de %1$s foram desativados</string>
|
||||||
<string name="su_revoke_title">Revogar?</string>
|
<string name="su_revoke_title">Revogar?</string>
|
||||||
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
|
<string name="su_revoke_msg">Confirme para revogar os acessos de SuperUsuário de %1$s</string>
|
||||||
<string name="toast">Notificação (Pop-up)</string>
|
<string name="toast">Notificação (Pop-up)</string>
|
||||||
<string name="none">Nenhum</string>
|
<string name="none">Nenhum</string>
|
||||||
<string name="superuser_toggle_notification">Notificações</string>
|
<string name="superuser_toggle_notification">Notificações</string>
|
||||||
<string name="superuser_toggle_revoke">Revogar</string>
|
<string name="superuser_toggle_revoke">Revogar</string>
|
||||||
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
|
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
|
||||||
|
|
||||||
<!--Logs-->
|
<!--Logs-->
|
||||||
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
|
<string name="log_data_none">Não há registos. Tente utilizar mais seus apps root.</string>
|
||||||
<string name="log_data_magisk_none">Os registros do Magisk estão vazios, isso é estranho.</string>
|
<string name="log_data_magisk_none">Os registos do Magisk estão vazios, isto é estranho.</string>
|
||||||
<string name="menuSaveLog">Salvar registros</string>
|
<string name="menuSaveLog">Salvar registos</string>
|
||||||
<string name="menuClearLog">Limpar registros agora</string>
|
<string name="menuClearLog">Limpar registos agora</string>
|
||||||
<string name="logs_cleared">Registros limpo com sucesso</string>
|
<string name="logs_cleared">Registos limpo com sucesso</string>
|
||||||
<string name="pid">PID: %1$d</string>
|
<string name="pid">PID: %1$d</string>
|
||||||
<string name="target_uid">Alvo UID: %1$d</string>
|
<string name="target_uid">Alvo UID: %1$d</string>
|
||||||
<string name="target_pid">Alvo PID: %s</string>
|
<string name="target_pid">Alvo PID: %s</string>
|
||||||
@@ -118,12 +118,12 @@
|
|||||||
|
|
||||||
<!--Settings-->
|
<!--Settings-->
|
||||||
<string name="settings_dark_mode_title">Modo do tema</string>
|
<string name="settings_dark_mode_title">Modo do tema</string>
|
||||||
<string name="settings_dark_mode_message">Selecione o modo mais adequado para você!</string>
|
<string name="settings_dark_mode_message">Selecione o modo mais adequado para si!</string>
|
||||||
<string name="settings_dark_mode_light">Sempre claro</string>
|
<string name="settings_dark_mode_light">Sempre claro</string>
|
||||||
<string name="settings_dark_mode_system">Seguir sistema</string>
|
<string name="settings_dark_mode_system">Seguir sistema</string>
|
||||||
<string name="settings_dark_mode_dark">Sempre escuro</string>
|
<string name="settings_dark_mode_dark">Sempre escuro</string>
|
||||||
<string name="settings_download_path_title">Caminho para baixar</string>
|
<string name="settings_download_path_title">Caminho para descarregar</string>
|
||||||
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
|
<string name="settings_download_path_message">Os ficheiros serão salvos em %1$s</string>
|
||||||
<string name="settings_hide_app_title">Ocultar app do Magisk</string>
|
<string name="settings_hide_app_title">Ocultar app do Magisk</string>
|
||||||
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
|
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
|
||||||
<string name="settings_restore_app_title">Restaurar app do Magisk</string>
|
<string name="settings_restore_app_title">Restaurar app do Magisk</string>
|
||||||
@@ -135,8 +135,9 @@
|
|||||||
<string name="settings_update_channel_title">Canal de atualização</string>
|
<string name="settings_update_channel_title">Canal de atualização</string>
|
||||||
<string name="settings_update_stable">Estável</string>
|
<string name="settings_update_stable">Estável</string>
|
||||||
<string name="settings_update_beta">Beta</string>
|
<string name="settings_update_beta">Beta</string>
|
||||||
|
<string name="settings_update_debug">Debug</string>
|
||||||
<string name="settings_update_custom">Personalizado</string>
|
<string name="settings_update_custom">Personalizado</string>
|
||||||
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
|
<string name="settings_update_custom_msg">Introduza um URL de canal personalizado</string>
|
||||||
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
|
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
|
||||||
<string name="settings_denylist_title">Aplicar lista de negação</string>
|
<string name="settings_denylist_title">Aplicar lista de negação</string>
|
||||||
<string name="settings_denylist_summary">Os processos na lista de negação terão todas as modificações do Magisk revertidas</string>
|
<string name="settings_denylist_summary">Os processos na lista de negação terão todas as modificações do Magisk revertidas</string>
|
||||||
@@ -167,35 +168,35 @@
|
|||||||
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
|
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
|
||||||
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
|
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
|
||||||
<string name="settings_su_auth_title">Autenticação de usuário</string>
|
<string name="settings_su_auth_title">Autenticação de usuário</string>
|
||||||
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante solicitações de SuperUsuário</string>
|
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante pedidos de SuperUsuário</string>
|
||||||
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
|
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
|
||||||
<string name="settings_customization">Personalizações</string>
|
<string name="settings_customization">Personalizações</string>
|
||||||
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
|
<string name="setting_add_shortcut_summary">Adicione um atalho no ecrã inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
|
||||||
<string name="settings_doh_title">DNS sobre HTTPS</string>
|
<string name="settings_doh_title">DNS sobre HTTPS</string>
|
||||||
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
|
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
|
||||||
<string name="settings_random_name_title">Randomizar nome de saída</string>
|
<string name="settings_random_name_title">Randomizar nome de saída</string>
|
||||||
<string name="settings_random_name_description">Randomize o nome do arquivo de saída de imagens corrigidas e arquivos tar (*.tar) para evitar a detecção</string>
|
<string name="settings_random_name_description">Randomize o nome do ficheiro de saída de imagens corrigidas e ficheiros tar (*.tar) para evitar a deteção</string>
|
||||||
<string name="multiuser_mode">Modo multiusuário</string>
|
<string name="multiuser_mode">Modo multiusuário</string>
|
||||||
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
|
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
|
||||||
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
|
<string name="settings_owner_manage">Gerido pelo proprietário do dispositivo</string>
|
||||||
<string name="settings_user_independent">Independente do usuário</string>
|
<string name="settings_user_independent">Independente do usuário</string>
|
||||||
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
|
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
|
||||||
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber pedidos de solicitação</string>
|
<string name="owner_manage_summary">Somente o proprietário pode gerir o acesso root e receber pedidos de solicitação</string>
|
||||||
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
|
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
|
||||||
<string name="mount_namespace_mode">Montar namespace</string>
|
<string name="mount_namespace_mode">Montar namespace</string>
|
||||||
<string name="settings_ns_global">Global</string>
|
<string name="settings_ns_global">Global</string>
|
||||||
<string name="settings_ns_requester">Herdado</string>
|
<string name="settings_ns_requester">Herdado</string>
|
||||||
<string name="settings_ns_isolate">Individual</string>
|
<string name="settings_ns_isolate">Individual</string>
|
||||||
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
|
<string name="global_summary">Todas as sessões root utilizam o namespace de montagem global</string>
|
||||||
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
|
<string name="requester_summary">As sessões root herdarão o namespace do requerente</string>
|
||||||
<string name="isolate_summary">Cada sessão root terá seu próprio namespace individual</string>
|
<string name="isolate_summary">Cada sessão root terá o seu próprio namespace individual</string>
|
||||||
|
|
||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="update_channel">Atualizações do Magisk</string>
|
<string name="update_channel">Atualizações do Magisk</string>
|
||||||
<string name="progress_channel">Notificações de progresso</string>
|
<string name="progress_channel">Notificações de progresso</string>
|
||||||
<string name="updated_channel">Atualização concluída</string>
|
<string name="updated_channel">Atualização concluída</string>
|
||||||
<string name="download_complete">Download concluído</string>
|
<string name="download_complete">Download concluído</string>
|
||||||
<string name="download_file_error">Erro ao baixar arquivo</string>
|
<string name="download_file_error">Erro ao descarregar ficheiro</string>
|
||||||
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
|
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
|
||||||
<string name="updated_title">Magisk atualizado</string>
|
<string name="updated_title">Magisk atualizado</string>
|
||||||
<string name="updated_text">Toque para abrir o app</string>
|
<string name="updated_text">Toque para abrir o app</string>
|
||||||
@@ -209,37 +210,37 @@
|
|||||||
<string name="close">Fechar</string>
|
<string name="close">Fechar</string>
|
||||||
<string name="release_notes">Notas da atualização</string>
|
<string name="release_notes">Notas da atualização</string>
|
||||||
<string name="flashing">Flashando…</string>
|
<string name="flashing">Flashando…</string>
|
||||||
<string name="running">Executando…</string>
|
<string name="running">A executar…</string>
|
||||||
<string name="done">Concluído!</string>
|
<string name="done">Concluído!</string>
|
||||||
<string name="done_action">Ação de execução de %1$s concluída</string>
|
<string name="done_action">Ação de execução de %1$s concluída</string>
|
||||||
<string name="failure">Falhou!</string>
|
<string name="failure">Falhou!</string>
|
||||||
<string name="hide_app_title">Ocultando o app do Magisk…</string>
|
<string name="hide_app_title">A ocultar o app do Magisk…</string>
|
||||||
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
|
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
|
||||||
<string name="complete_uninstall">Desinstalação completa</string>
|
<string name="complete_uninstall">Desinstalação completa</string>
|
||||||
<string name="restore_img">Restaurar imagens</string>
|
<string name="restore_img">Restaurar imagens</string>
|
||||||
<string name="restore_img_msg">Restaurando…</string>
|
<string name="restore_img_msg">A restaurar…</string>
|
||||||
<string name="restore_done">Restauração concluída!</string>
|
<string name="restore_done">Restauração concluída!</string>
|
||||||
<string name="restore_fail">O backup original não existe!</string>
|
<string name="restore_fail">O backup original não existe!</string>
|
||||||
<string name="setup_fail">Falha na instalação</string>
|
<string name="setup_fail">Falha na instalação</string>
|
||||||
<string name="env_fix_title">Configuração adicional exigida</string>
|
<string name="env_fix_title">Configuração adicional exigida</string>
|
||||||
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
|
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
|
||||||
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não pode obter as devidas informações do dispositivo.</string>
|
<string name="env_full_fix_msg">O seu dispositivo precisa de refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não consegue obter as devidas informações do dispositivo.</string>
|
||||||
<string name="setup_msg">Executando a configuração do ambiente…</string>
|
<string name="setup_msg">A executar a configuração do ambiente…</string>
|
||||||
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
|
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
|
||||||
<string name="unsupport_magisk_msg">Esta versão do app não suporta a versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
|
<string name="unsupport_magisk_msg">Esta versão do app não suporta versões do Magisk inferiores a %1$s.\n\nO app irá comportar-se como se nenhum Magisk estivesse instalado. Por favor, atualize o Magisk assim que possível.</string>
|
||||||
<string name="unsupport_general_title">Estado anormal</string>
|
<string name="unsupport_general_title">Estado anormal</string>
|
||||||
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
|
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
|
||||||
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
|
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
|
||||||
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
|
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
|
||||||
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar funcionando porque o root foi perdido. Por favor, restaure o APK original.</string>
|
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o root foi perdido. Por favor, restaure o APK original.</string>
|
||||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
|
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
|
||||||
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
|
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
|
||||||
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
|
<string name="install_unknown_denied">Permita a opção \"Instalar apps de fontes desconhecidas\" para ativar esta funcionalidade</string>
|
||||||
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
|
<string name="add_shortcut_title">Adicionar atalho ao ecrã inicial</string>
|
||||||
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
<string name="add_shortcut_msg">Após ocultar o app do Magisk, o seu nome e ícone serão difíceis de reconhecer. Deseja adicionar um atalho no ecrã inicial?</string>
|
||||||
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
|
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
|
||||||
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
|
<string name="reboot_apply_change">Reinicie para aplicar as alterações</string>
|
||||||
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
|
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
<!--Author: Radoš Milićev (https://github.com/rammba)-->
|
||||||
|
|
||||||
<!--Sections-->
|
<!--Sections-->
|
||||||
<string name="modules">Модули</string>
|
<string name="modules">Модули</string>
|
||||||
|
|||||||
234
app/core/src/main/res/values-ur/strings.xml
Normal file
234
app/core/src/main/res/values-ur/strings.xml
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="modules">ماڈیولز</string>
|
||||||
|
<string name="superuser">سپر یوزر</string>
|
||||||
|
<string name="logs">لاگز</string>
|
||||||
|
<string name="settings">سیٹنگز</string>
|
||||||
|
<string name="install">انسٹال کریں</string>
|
||||||
|
<string name="section_home">ہوم</string>
|
||||||
|
<string name="section_theme">تھیمز</string>
|
||||||
|
<string name="denylist">مسترد فہرست</string>
|
||||||
|
|
||||||
|
<string name="no_connection">کوئی کنکشن دستیاب نہیں</string>
|
||||||
|
<string name="app_changelog">ایپ چینج لاگ</string>
|
||||||
|
<string name="loading">لوڈ ہو رہا ہے…</string>
|
||||||
|
<string name="update">اپ ڈیٹ</string>
|
||||||
|
<string name="not_available">دستیاب نہیں</string>
|
||||||
|
<string name="hide">چھپائیں</string>
|
||||||
|
<string name="home_package">پیکیج</string>
|
||||||
|
<string name="home_app_title">ایپ</string>
|
||||||
|
|
||||||
|
<string name="home_notice_content">صرف آفیشل گٹ ہب پیج سے Magisk ڈاؤن لوڈ کریں۔ نامعلوم ذرائع سے فائلیں نقصان دہ ہو سکتی ہیں!</string>
|
||||||
|
<string name="home_support_title">ہماری مدد کریں</string>
|
||||||
|
<string name="home_follow_title">ہمیں فالو کریں</string>
|
||||||
|
<string name="home_item_source">ذریعہ</string>
|
||||||
|
<string name="home_support_content">Magisk ہمیشہ مفت اور اوپن سورس رہے گا۔ تاہم، آپ عطیہ کر کے ہمیں اپنی دیکھ بھال کا اظہار کر سکتے ہیں۔</string>
|
||||||
|
<string name="home_installed_version">انسٹال شدہ</string>
|
||||||
|
<string name="home_latest_version">تازہ ترین</string>
|
||||||
|
<string name="invalid_update_channel">غلط اپ ڈیٹ چینل</string>
|
||||||
|
<string name="uninstall_magisk_title">Magisk اَن انسٹال کریں</string>
|
||||||
|
<string name="uninstall_magisk_msg">تمام ماڈیولز غیر فعال/ہٹا دیے جائیں گے!\nروٹ ہٹا دیا جائے گا!\nMagisk کے استعمال کے ذریعے غیر اینکرپٹ کی گئی کوئی بھی اندرونی اسٹوریج دوبارہ اینکرپٹ ہو جائے گی!</string>
|
||||||
|
|
||||||
|
<string name="keep_force_encryption">جبری انکرپشن کو محفوظ رکھیں</string>
|
||||||
|
<string name="keep_dm_verity">AVB 2.0/dm-verity کو محفوظ رکھیں</string>
|
||||||
|
<string name="recovery_mode">ریکوری موڈ</string>
|
||||||
|
<string name="install_options_title">آپشنز</string>
|
||||||
|
<string name="install_method_title">طریقہ</string>
|
||||||
|
<string name="install_next">اگلا</string>
|
||||||
|
<string name="install_start">چلو شروع کرتے ہیں</string>
|
||||||
|
<string name="manager_download_install">ڈاؤن لوڈ اور انسٹال کرنے کے لیے دبائیں</string>
|
||||||
|
<string name="direct_install">براہ راست انسٹال (تجویز کردہ)</string>
|
||||||
|
<string name="install_inactive_slot">غیر فعال سلاٹ میں انسٹال کریں (OTA کے بعد)</string>
|
||||||
|
<string name="install_inactive_slot_msg">ریبوٹ کے بعد آپ کا آلہ زبردستی موجودہ غیر فعال سلاٹ میں بوٹ ہو جائے گا!\nیہ آپشن صرف OTA مکمل ہونے کے بعد استعمال کریں۔\nجاری رکھیں؟</string>
|
||||||
|
<string name="setup_title">اضافی سیٹ اپ</string>
|
||||||
|
<string name="select_patch_file">پیچ فائل منتخب اور پیچ کریں</string>
|
||||||
|
<string name="patch_file_msg">ایک خام امیج (*.img) یا ایک ODIN ٹار فائل (*.tar) یا ایک payload.bin (*.bin) منتخب کریں</string>
|
||||||
|
<string name="reboot_delay_toast">5 سیکنڈ میں ریبوٹ ہو رہا ہے…</string>
|
||||||
|
<string name="flash_screen_title">انسٹالیشن</string>
|
||||||
|
|
||||||
|
<string name="su_request_title">سپر یوزر کی درخواست</string>
|
||||||
|
<string name="touch_filtered_warning">چونکہ ایک ایپ سپر یوزر کی درخواست کو دھندلا کر رہی ہے، اس لیے Magisk آپ کے جواب کی تصدیق نہیں کر سکتا</string>
|
||||||
|
<string name="deny">منع کریں</string>
|
||||||
|
<string name="prompt">پوچھیں</string>
|
||||||
|
<string name="grant">اجازت دیں</string>
|
||||||
|
<string name="su_warning">اپنے آلے تک مکمل رسائی کی اجازت دیں۔\nاگر آپ کو یقین نہیں ہے تو منع کریں!</string>
|
||||||
|
<string name="forever">ہمیشہ کے لیے</string>
|
||||||
|
<string name="once">ایک بار</string>
|
||||||
|
<string name="tenmin">10 منٹ</string>
|
||||||
|
<string name="twentymin">20 منٹ</string>
|
||||||
|
<string name="thirtymin">30 منٹ</string>
|
||||||
|
<string name="sixtymin">60 منٹ</string>
|
||||||
|
<string name="su_allow_toast">%1$s کو سپر یوزر کے حقوق دیئے گئے</string>
|
||||||
|
<string name="su_deny_toast">%1$s کو سپر یوزر کے حقوق سے انکار کر دیا گیا</string>
|
||||||
|
<string name="su_snack_grant">%1$s کے سپر یوزر حقوق دیئے گئے</string>
|
||||||
|
<string name="su_snack_deny">%1$s کے سپر یوزر حقوق سے انکار کر دیا گیا</string>
|
||||||
|
<string name="su_snack_notif_on">%1$s کی اطلاعات فعال ہیں</string>
|
||||||
|
<string name="su_snack_notif_off">%1$s کی اطلاعات غیر فعال ہیں</string>
|
||||||
|
<string name="su_snack_log_on">%1$s کی لاگنگ فعال ہے</string>
|
||||||
|
<string name="su_snack_log_off">%1$s کی لاگنگ غیر فعال ہے</string>
|
||||||
|
<string name="su_revoke_title">منسوخ کریں؟</string>
|
||||||
|
<string name="su_revoke_msg">%1$s کے سپر یوزر حقوق منسوخ کرنے کی تصدیق کریں</string>
|
||||||
|
<string name="toast">ٹوسٹ</string>
|
||||||
|
<string name="none">کوئی نہیں</string>
|
||||||
|
|
||||||
|
<string name="superuser_toggle_notification">اطلاعات</string>
|
||||||
|
<string name="superuser_toggle_revoke">منسوخ کریں</string>
|
||||||
|
<string name="superuser_policy_none">ابھی تک کسی ایپ نے سپر یوزر کی اجازت نہیں مانگی ہے۔</string>
|
||||||
|
|
||||||
|
<string name="log_data_none">آپ لاگ فری ہیں، اپنی روٹ ایپس کو مزید استعمال کرنے کی کوشش کریں</string>
|
||||||
|
<string name="log_data_magisk_none">Magisk لاگز خالی ہیں، یہ عجیب بات ہے</string>
|
||||||
|
<string name="menuSaveLog">لاگ محفوظ کریں</string>
|
||||||
|
<string name="menuClearLog">ابھی لاگ صاف کریں</string>
|
||||||
|
<string name="logs_cleared">لاگ کامیابی سے صاف ہو گیا</string>
|
||||||
|
<string name="pid">PID: %1$d</string>
|
||||||
|
<string name="target_uid">ٹارگٹ UID: %1$d</string>
|
||||||
|
<string name="target_pid">ماؤنٹ این ایس ٹارگٹ PID: %s</string>
|
||||||
|
<string name="selinux_context">SELinux سیاق و سباق: %s</string>
|
||||||
|
<string name="supp_group">اضافی گروپ: %s</string>
|
||||||
|
|
||||||
|
<string name="show_system_app">سسٹم ایپس دکھائیں</string>
|
||||||
|
<string name="show_os_app">OS ایپس دکھائیں</string>
|
||||||
|
<string name="hide_filter_hint">نام سے فلٹر کریں</string>
|
||||||
|
<string name="hide_search">تلاش کریں</string>
|
||||||
|
|
||||||
|
<string name="no_info_provided">(کوئی معلومات فراہم نہیں کی گئی)</string>
|
||||||
|
<string name="reboot_userspace">سافٹ ریبوٹ</string>
|
||||||
|
<string name="reboot_recovery">ریکوری میں ریبوٹ کریں</string>
|
||||||
|
<string name="reboot_bootloader">بوٹ لوڈر میں ریبوٹ کریں</string>
|
||||||
|
<string name="reboot_download">ڈاؤن لوڈ میں ریبوٹ کریں</string>
|
||||||
|
<string name="reboot_edl">EDL میں ریبوٹ کریں</string>
|
||||||
|
<string name="reboot_safe_mode">محفوظ موڈ</string>
|
||||||
|
<string name="module_version_author">%2$s کی جانب سے %1$s</string>
|
||||||
|
<string name="module_state_remove">ہٹائیں</string>
|
||||||
|
<string name="module_state_restore">بحال کریں</string>
|
||||||
|
<string name="module_action_install_external">اسٹوریج سے انسٹال کریں</string>
|
||||||
|
<string name="update_available">اپ ڈیٹ دستیاب ہے</string>
|
||||||
|
<string name="suspend_text_riru">ماڈیول معطل کر دیا گیا کیونکہ %1$s فعال ہے</string>
|
||||||
|
<string name="suspend_text_zygisk">ماڈیول معطل کر دیا گیا کیونکہ %1$s فعال نہیں ہے</string>
|
||||||
|
<string name="zygisk_module_unloaded">غیر مطابقت کی وجہ سے Zygisk ماڈیول لوڈ نہیں ہوا</string>
|
||||||
|
<string name="module_empty">کوئی ماڈیول انسٹال نہیں ہے</string>
|
||||||
|
<string name="confirm_install">ماڈیول %1$s انسٹال کریں؟</string>
|
||||||
|
<string name="confirm_install_title">انسٹالیشن کی تصدیق</string>
|
||||||
|
|
||||||
|
<string name="settings_dark_mode_title">تھیم موڈ</string>
|
||||||
|
<string name="settings_dark_mode_message">وہ موڈ منتخب کریں جو آپ کے انداز کے مطابق ہو!</string>
|
||||||
|
<string name="settings_dark_mode_light">ہمیشہ لائٹ</string>
|
||||||
|
<string name="settings_dark_mode_system">سسٹم کی پیروی کریں</string>
|
||||||
|
<string name="settings_dark_mode_dark">ہمیشہ ڈارک</string>
|
||||||
|
<string name="settings_download_path_title">ڈاؤن لوڈ کا راستہ</string>
|
||||||
|
<string name="settings_download_path_message">فائلیں %1$s میں محفوظ کی جائیں گی</string>
|
||||||
|
<string name="settings_hide_app_title">Magisk ایپ کو چھپائیں</string>
|
||||||
|
<string name="settings_hide_app_summary">ایک رینڈم پیکیج ID اور کسٹم ایپ لیبل کے ساتھ ایک پراکسی ایپ انسٹال کریں</string>
|
||||||
|
<string name="settings_restore_app_title">Magisk ایپ کو بحال کریں</string>
|
||||||
|
<string name="settings_restore_app_summary">ایپ کو ان ہائیڈ کریں اور اصل APK کو بحال کریں</string>
|
||||||
|
<string name="language">زبان</string>
|
||||||
|
<string name="system_default">(سسٹم ڈیفالٹ)</string>
|
||||||
|
<string name="settings_check_update_title">اپ ڈیٹس چیک کریں</string>
|
||||||
|
<string name="settings_check_update_summary">وقفے وقفے سے پس منظر میں اپ ڈیٹس چیک کریں</string>
|
||||||
|
<string name="settings_update_channel_title">اپ ڈیٹ چینل</string>
|
||||||
|
<string name="settings_update_stable">مستحکم</string>
|
||||||
|
<string name="settings_update_beta">بیٹا</string>
|
||||||
|
<string name="settings_update_custom">کسٹم</string>
|
||||||
|
<string name="settings_update_custom_msg">ایک کسٹم چینل URL درج کریں</string>
|
||||||
|
<string name="settings_zygisk_summary">zygote ڈیمن میں Magisk کے کچھ حصے چلائیں</string>
|
||||||
|
<string name="settings_denylist_title">مسترد فہرست نافذ کریں</string>
|
||||||
|
<string name="settings_denylist_summary">مسترد فہرست میں موجود عملوں میں Magisk کی تمام ترامیم کو کالعدم قرار دیا جائے گا</string>
|
||||||
|
<string name="settings_denylist_config_title">مسترد فہرست کی تشکیل کریں</string>
|
||||||
|
<string name="settings_denylist_config_summary">مسترد فہرست میں شامل کرنے کے لیے عمل منتخب کریں</string>
|
||||||
|
<string name="settings_hosts_title">سسٹم لیس ہوسٹس</string>
|
||||||
|
<string name="settings_hosts_summary">ایڈ بلاکنگ ایپس کے لیے سسٹم لیس ہوسٹس سپورٹ</string>
|
||||||
|
<string name="settings_hosts_toast">سسٹم لیس ہوسٹس ماڈیول شامل کیا گیا</string>
|
||||||
|
<string name="settings_app_name_hint">نیا نام</string>
|
||||||
|
<string name="settings_app_name_helper">ایپ کو اس نام سے دوبارہ پیک کیا جائے گا</string>
|
||||||
|
<string name="settings_app_name_error">غلط فارمیٹ</string>
|
||||||
|
<string name="settings_su_app_adb">ایپس اور ADB</string>
|
||||||
|
<string name="settings_su_app">صرف ایپس</string>
|
||||||
|
<string name="settings_su_adb">صرف ADB</string>
|
||||||
|
<string name="settings_su_disable">غیر فعال</string>
|
||||||
|
<string name="settings_su_request_10">10 سیکنڈ</string>
|
||||||
|
<string name="settings_su_request_15">15 سیکنڈ</string>
|
||||||
|
<string name="settings_su_request_20">20 سیکنڈ</string>
|
||||||
|
<string name="settings_su_request_30">30 سیکنڈ</string>
|
||||||
|
<string name="settings_su_request_45">45 سیکنڈ</string>
|
||||||
|
<string name="settings_su_request_60">60 سیکنڈ</string>
|
||||||
|
<string name="superuser_access">سپر یوزر تک رسائی</string>
|
||||||
|
<string name="auto_response">خودکار جواب</string>
|
||||||
|
<string name="request_timeout">درخواست کا وقت ختم</string>
|
||||||
|
<string name="superuser_notification">سپر یوزر اطلاع</string>
|
||||||
|
<string name="settings_su_reauth_title">اپ گریڈ کے بعد دوبارہ تصدیق کریں</string>
|
||||||
|
<string name="settings_su_reauth_summary">ایپس کو اپ گریڈ کرنے کے بعد دوبارہ سپر یوزر کی اجازتیں مانگیں</string>
|
||||||
|
<string name="settings_su_tapjack_title">ٹیپ جیکنگ سے تحفظ</string>
|
||||||
|
<string name="settings_su_tapjack_summary">سپر یوزر پرامپٹ ڈائیلاگ کسی دوسری ونڈو یا اوورلے سے دھندلا ہونے کے دوران ان پٹ کا جواب نہیں دے گا</string>
|
||||||
|
<string name="settings_su_auth_title">صارف کی تصدیق</string>
|
||||||
|
<string name="settings_su_auth_summary">سپر یوزر کی درخواستوں کے دوران صارف کی تصدیق طلب کریں</string>
|
||||||
|
<string name="settings_su_auth_insecure">آلے پر کوئی تصدیقی طریقہ کار تشکیل نہیں دیا گیا ہے</string>
|
||||||
|
<string name="settings_customization">حسب ضرورت سازی</string>
|
||||||
|
<string name="setting_add_shortcut_summary">اگر ایپ کو چھپانے کے بعد اس کا نام اور آئیکن پہچاننا مشکل ہو جائے تو ہوم اسکرین پر ایک خوبصورت شارٹ کٹ شامل کریں</string>
|
||||||
|
<string name="settings_doh_title">HTTPS پر DNS</string>
|
||||||
|
<string name="settings_doh_description">بعض ممالک میں DNS زہر آلودگی کا حل</string>
|
||||||
|
<string name="settings_random_name_title">بے ترتیب آؤٹ پٹ نام</string>
|
||||||
|
<string name="settings_random_name_description">پتہ لگانے سے بچنے کے لیے پیچ شدہ امیجز اور ٹار فائلوں کے آؤٹ پٹ فائل کے نام کو بے ترتیب بنائیں</string>
|
||||||
|
|
||||||
|
<string name="multiuser_mode">ملٹی یوزر موڈ</string>
|
||||||
|
<string name="settings_owner_only">صرف آلہ کا مالک</string>
|
||||||
|
<string name="settings_owner_manage">آلہ کے مالک کے زیر انتظام</string>
|
||||||
|
<string name="settings_user_independent">صارف سے آزاد</string>
|
||||||
|
<string name="owner_only_summary">صرف مالک کو روٹ تک رسائی حاصل ہے</string>
|
||||||
|
<string name="owner_manage_summary">صرف مالک روٹ تک رسائی کا انتظام کر سکتا ہے اور درخواست کے اشارے وصول کر سکتا ہے</string>
|
||||||
|
<string name="user_independent_summary">ہر صارف کے اپنے علیحدہ روٹ کے قواعد ہیں</string>
|
||||||
|
|
||||||
|
<string name="mount_namespace_mode">ماؤنٹ نیم اسپیس موڈ</string>
|
||||||
|
<string name="settings_ns_global">عالمی نیم اسپیس</string>
|
||||||
|
<string name="settings_ns_requester">نیم اسپیس وراثت میں حاصل کریں</string>
|
||||||
|
<string name="settings_ns_isolate">آئسولیٹڈ نیم اسپیس</string>
|
||||||
|
<string name="isolate_summary">ہر روٹ سیشن کی اپنی آئسولیٹڈ نیم اسپیس ہوگی</string>
|
||||||
|
<string name="update_channel">Magisk اپ ڈیٹس</string>
|
||||||
|
<string name="progress_channel">پیش رفت کی اطلاعات</string>
|
||||||
|
<string name="updated_channel">اپ ڈیٹ مکمل</string>
|
||||||
|
<string name="download_complete">ڈاؤن لوڈ مکمل</string>
|
||||||
|
<string name="download_file_error">فائل ڈاؤن لوڈ کرنے میں خرابی</string>
|
||||||
|
<string name="magisk_update_title">Magisk اپ ڈیٹ دستیاب ہے!</string>
|
||||||
|
<string name="updated_title">Magisk اپ ڈیٹ ہو گیا</string>
|
||||||
|
<string name="updated_text">ایپ کھولنے کے لیے ٹیپ کریں</string>
|
||||||
|
<string name="yes">ہاں</string>
|
||||||
|
<string name="no">نہیں</string>
|
||||||
|
<string name="repo_install_title">%1$s %2$s (%3$d) انسٹال کریں</string>
|
||||||
|
<string name="download">ڈاؤن لوڈ</string>
|
||||||
|
<string name="reboot">ریبوٹ</string>
|
||||||
|
<string name="close">بند کریں</string>
|
||||||
|
<string name="release_notes">ریلیز نوٹ</string>
|
||||||
|
<string name="flashing">فلیش ہو رہا ہے…</string>
|
||||||
|
<string name="done">ہو گیا!</string>
|
||||||
|
<string name="failure">ناکام!</string>
|
||||||
|
<string name="hide_app_title">Magisk ایپ کو چھپایا جا رہا ہے…</string>
|
||||||
|
<string name="open_link_failed_toast">لنک کھولنے کے لیے کوئی ایپ نہیں ملی</string>
|
||||||
|
<string name="complete_uninstall">مکمل ان انسٹال</string>
|
||||||
|
<string name="restore_img">تصاویر بحال کریں</string>
|
||||||
|
<string name="restore_img_msg">بحال ہو رہا ہے…</string>
|
||||||
|
<string name="restore_done">بحالی مکمل ہو گئی!</string>
|
||||||
|
<string name="restore_fail">اسٹاک بیک اپ موجود نہیں ہے!</string>
|
||||||
|
<string name="setup_fail">سیٹ اپ ناکام ہو گیا</string>
|
||||||
|
<string name="env_full_fix_msg">Magisk کو صحیح طریقے سے کام کرنے کے لیے آپ کے آلے کو دوبارہ فلیش کرنے کی ضرورت ہے۔ براہ کرم ایپ کے اندر Magisk کو دوبارہ انسٹال کریں، ریکوری موڈ درست ڈیوائس کی معلومات حاصل نہیں کر سکتا۔</string>
|
||||||
|
<string name="env_fix_title">اضافی سیٹ اپ درکار ہے</string>
|
||||||
|
<string name="env_fix_msg">Magisk کو صحیح طریقے سے کام کرنے کے لیے آپ کے آلے کو اضافی سیٹ اپ کی ضرورت ہے۔ کیا آپ جاری رکھنا چاہتے ہیں اور ریبوٹ کرنا چاہتے ہیں؟</string>
|
||||||
|
<string name="setup_msg">ماحول کا سیٹ اپ چل رہا ہے…</string>
|
||||||
|
<string name="unsupport_magisk_title">Magisk کا غیر تعاون یافتہ ورژن</string>
|
||||||
|
<string name="unsupport_magisk_msg">ایپ کا یہ ورژن %1$s سے کم Magisk ورژنز کو سپورٹ نہیں کرتا ہے۔\n\nایپ ایسے برتاؤ کرے گی جیسے کوئی Magisk انسٹال نہیں ہے، براہ کرم جلد از جلد Magisk کو اپ گریڈ کریں۔</string>
|
||||||
|
<string name="unsupport_general_title">غیر معمولی حالت</string>
|
||||||
|
<string name="unsupport_system_app_msg">سسٹم ایپ کے طور پر اس ایپ کو چلانا تعاون یافتہ نہیں ہے۔ براہ کرم ایپ کو صارف ایپ میں واپس کریں۔</string>
|
||||||
|
<string name="unsupport_other_su_msg">Magisk کے علاوہ کسی اور "su" بائنری کا پتہ چلا ہے۔ براہ کرم کسی بھی مسابقتی روٹ حل کو ہٹا دیں اور/یا Magisk کو دوبارہ انسٹال کریں۔</string>
|
||||||
|
<string name="unsupport_external_storage_msg">Magisk بیرونی اسٹوریج پر انسٹال ہے۔ براہ کرم ایپ کو اندرونی اسٹوریج میں منتقل کریں۔</string>
|
||||||
|
<string name="unsupport_nonroot_stub_msg">چھپی ہوئی Magisk ایپ کام جاری نہیں رکھ سکتی کیونکہ روٹ ختم ہو گیا ہے۔ براہ کرم اصل APK کو بحال کریں۔</string>
|
||||||
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
|
<string name="external_rw_permission_denied">اس فعالیت کو فعال کرنے کے لیے اسٹوریج کی اجازت دیں</string>
|
||||||
|
<string name="post_notifications_denied">اس فعالیت کو فعال کرنے کے لیے اطلاعات کی اجازت دیں</string>
|
||||||
|
<string name="install_unknown_denied">اس فعالیت کو فعال کرنے کے لیے "نامعلوم ایپس انسٹال کریں" کی اجازت دیں</string>
|
||||||
|
<string name="add_shortcut_title">ہوم اسکرین پر شارٹ کٹ شامل کریں</string>
|
||||||
|
<string name="add_shortcut_msg">اس ایپ کو چھپانے کے بعد، اس کا نام اور آئیکن پہچاننا مشکل ہو سکتا ہے۔ کیا آپ ہوم اسکرین پر ایک خوبصورت شارٹ کٹ شامل کرنا چاہتے ہیں؟</string>
|
||||||
|
<string name="app_not_found">اس عمل کو سنبھالنے کے لیے کوئی ایپ نہیں ملی</string>
|
||||||
|
<string name="reboot_apply_change">تبدیلیاں لاگو کرنے کے لیے ریبوٹ کریں</string>
|
||||||
|
<string name="restore_app_confirmation">یہ چھپی ہوئی ایپ کو اصل ایپ میں بحال کردے گا۔ کیا آپ واقعی ایسا کرنا چاہتے ہیں؟</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
|
||||||
@@ -54,6 +54,7 @@
|
|||||||
<string name="touch_filtered_warning">由于某个应用遮挡了超级用户请求界面,因此 Magisk 无法验证您的回应</string>
|
<string name="touch_filtered_warning">由于某个应用遮挡了超级用户请求界面,因此 Magisk 无法验证您的回应</string>
|
||||||
<string name="deny">拒绝</string>
|
<string name="deny">拒绝</string>
|
||||||
<string name="prompt">提示</string>
|
<string name="prompt">提示</string>
|
||||||
|
<string name="restrict">受限</string>
|
||||||
<string name="grant">允许</string>
|
<string name="grant">允许</string>
|
||||||
<string name="su_warning">将授予对该设备的最高权限。\n如果不确定,请拒绝!</string>
|
<string name="su_warning">将授予对该设备的最高权限。\n如果不确定,请拒绝!</string>
|
||||||
<string name="forever">永久</string>
|
<string name="forever">永久</string>
|
||||||
@@ -173,6 +174,8 @@
|
|||||||
<string name="settings_su_auth_title">身份验证</string>
|
<string name="settings_su_auth_title">身份验证</string>
|
||||||
<string name="settings_su_auth_summary">对超级用户请求验证身份</string>
|
<string name="settings_su_auth_summary">对超级用户请求验证身份</string>
|
||||||
<string name="settings_su_auth_insecure">设备未配置验证方式</string>
|
<string name="settings_su_auth_insecure">设备未配置验证方式</string>
|
||||||
|
<string name="settings_su_restrict_title">限制超级用户权能</string>
|
||||||
|
<string name="settings_su_restrict_summary">默认限制新的超级用户应用。警告,这会破坏大多数应用,不建议启用。</string>
|
||||||
<string name="settings_customization">个性化</string>
|
<string name="settings_customization">个性化</string>
|
||||||
<string name="setting_add_shortcut_summary">在隐藏后难以识别名称和图标的情况下,添加快捷方式到桌面</string>
|
<string name="setting_add_shortcut_summary">在隐藏后难以识别名称和图标的情况下,添加快捷方式到桌面</string>
|
||||||
<string name="settings_doh_title">安全 DNS(DoH)</string>
|
<string name="settings_doh_title">安全 DNS(DoH)</string>
|
||||||
|
|||||||
@@ -63,9 +63,7 @@
|
|||||||
<string-array name="update_channel">
|
<string-array name="update_channel">
|
||||||
<item>@string/settings_update_stable</item>
|
<item>@string/settings_update_stable</item>
|
||||||
<item>@string/settings_update_beta</item>
|
<item>@string/settings_update_beta</item>
|
||||||
|
<item>@string/settings_update_debug</item>
|
||||||
<item>@string/settings_update_custom</item>
|
<item>@string/settings_update_custom</item>
|
||||||
<item>Canary</item>
|
|
||||||
<item>Debug</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -19,41 +19,41 @@
|
|||||||
<string name="hide">Hide</string>
|
<string name="hide">Hide</string>
|
||||||
<string name="home_package">Package</string>
|
<string name="home_package">Package</string>
|
||||||
<string name="home_app_title">App</string>
|
<string name="home_app_title">App</string>
|
||||||
|
|
||||||
<string name="home_notice_content">Download Magisk ONLY from the official GitHub page. Files from unknown sources can be malicious!</string>
|
<string name="home_notice_content">Download Magisk ONLY from the official GitHub page. Files from unknown sources can be malicious!</string>
|
||||||
<string name="home_support_title">Support Us</string>
|
<string name="home_support_title">Support Us</string>
|
||||||
<string name="home_follow_title">Follow Us</string>
|
<string name="home_follow_title">Follow Us</string>
|
||||||
<string name="home_item_source">Source</string>
|
<string name="home_item_source">Source</string>
|
||||||
<string name="home_support_content">Magisk is, and always will be, free, and open source. You can however show us that you care by making a donation.</string>
|
<string name="home_support_content">Magisk is, and always will be, free, and open source. However, you can show us that you care by making a donation.</string>
|
||||||
<string name="home_installed_version">Installed</string>
|
<string name="home_installed_version">Installed</string>
|
||||||
<string name="home_latest_version">Latest</string>
|
<string name="home_latest_version">Latest</string>
|
||||||
<string name="invalid_update_channel">Invalid Update Channel</string>
|
<string name="invalid_update_channel">Invalid update channel</string>
|
||||||
<string name="uninstall_magisk_title">Uninstall Magisk</string>
|
<string name="uninstall_magisk_title">Uninstall Magisk</string>
|
||||||
<string name="uninstall_magisk_msg">All modules will be disabled/removed!\nRoot will be removed!\nAny internal storage unencrypted through the use of Magisk will be re-encrypted!</string>
|
<string name="uninstall_magisk_msg">All modules will be disabled/removed!\nRoot will be removed!\nAny internal storage unencrypted through the use of Magisk will be re-encrypted!</string>
|
||||||
|
|
||||||
<!--Install-->
|
<!--Install-->
|
||||||
<string name="keep_force_encryption">Preserve force encryption</string>
|
<string name="keep_force_encryption">Preserve force encryption</string>
|
||||||
<string name="keep_dm_verity">Preserve AVB 2.0/dm-verity</string>
|
<string name="keep_dm_verity">Preserve AVB 2.0/dm-verity</string>
|
||||||
<string name="recovery_mode">Recovery Mode</string>
|
<string name="recovery_mode">Recovery mode</string>
|
||||||
<string name="install_options_title">Options</string>
|
<string name="install_options_title">Options</string>
|
||||||
<string name="install_method_title">Method</string>
|
<string name="install_method_title">Method</string>
|
||||||
<string name="install_next">Next</string>
|
<string name="install_next">Next</string>
|
||||||
<string name="install_start">Let\'s go</string>
|
<string name="install_start">Let\'s go</string>
|
||||||
<string name="manager_download_install">Press to download and install</string>
|
<string name="manager_download_install">Press to download and install</string>
|
||||||
<string name="direct_install">Direct Install (Recommended)</string>
|
<string name="direct_install">Direct install (Recommended)</string>
|
||||||
<string name="install_inactive_slot">Install to Inactive Slot (After OTA)</string>
|
<string name="install_inactive_slot">Install to inactive slot (After OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">Your device will be FORCED to boot to the current inactive slot after a reboot!\nOnly use this option after OTA is done.\nContinue?</string>
|
<string name="install_inactive_slot_msg">Your device will be FORCED to boot to the current inactive slot after a reboot!\nOnly use this option after OTA is done.\nContinue?</string>
|
||||||
<string name="setup_title">Additional Setup</string>
|
<string name="setup_title">Additional setup</string>
|
||||||
<string name="select_patch_file">Select and Patch a File</string>
|
<string name="select_patch_file">Select and patch a file</string>
|
||||||
<string name="patch_file_msg">Select a raw image (*.img) or an ODIN tarfile (*.tar) or a payload.bin (*.bin)</string>
|
<string name="patch_file_msg">Select a raw image (*.img) or an ODIN tarfile (*.tar) or a payload.bin (*.bin)</string>
|
||||||
<string name="reboot_delay_toast">Rebooting in 5 seconds…</string>
|
<string name="reboot_delay_toast">Rebooting in 5 seconds…</string>
|
||||||
<string name="flash_screen_title">Installation</string>
|
<string name="flash_screen_title">Installation</string>
|
||||||
|
|
||||||
<!--Superuser-->
|
<!--Superuser-->
|
||||||
<string name="su_request_title">Superuser Request</string>
|
<string name="su_request_title">Superuser request</string>
|
||||||
<string name="touch_filtered_warning">Because an app is obscuring a Superuser request, Magisk can\'t verify your response</string>
|
<string name="touch_filtered_warning">Because an app is obscuring a Superuser request, Magisk can\'t verify your response.</string>
|
||||||
<string name="deny">Deny</string>
|
<string name="deny">Deny</string>
|
||||||
<string name="prompt">Prompt</string>
|
<string name="prompt">Prompt</string>
|
||||||
|
<string name="restrict">Restrict</string>
|
||||||
<string name="grant">Grant</string>
|
<string name="grant">Grant</string>
|
||||||
<string name="su_warning">Grants full access to your device.\nDeny if you\'re not sure!</string>
|
<string name="su_warning">Grants full access to your device.\nDeny if you\'re not sure!</string>
|
||||||
<string name="forever">Forever</string>
|
<string name="forever">Forever</string>
|
||||||
@@ -74,25 +74,22 @@
|
|||||||
<string name="su_revoke_msg">Confirm to revoke %1$s Superuser rights</string>
|
<string name="su_revoke_msg">Confirm to revoke %1$s Superuser rights</string>
|
||||||
<string name="toast">Toast</string>
|
<string name="toast">Toast</string>
|
||||||
<string name="none">None</string>
|
<string name="none">None</string>
|
||||||
|
|
||||||
<string name="superuser_toggle_notification">Notifications</string>
|
<string name="superuser_toggle_notification">Notifications</string>
|
||||||
<string name="superuser_toggle_revoke">Revoke</string>
|
<string name="superuser_toggle_revoke">Revoke</string>
|
||||||
<string name="superuser_policy_none">No apps have asked for Superuser permission yet.</string>
|
<string name="superuser_policy_none">No apps have asked for Superuser permission yet.</string>
|
||||||
|
|
||||||
<!--Logs-->
|
<!--Logs-->
|
||||||
<string name="log_data_none">You\'re log-free, try using your root apps more</string>
|
<string name="log_data_none">You\'re log-free. Try using your root apps more.</string>
|
||||||
<string name="log_data_magisk_none">Magisk logs are empty, that\'s weird</string>
|
<string name="log_data_magisk_none">Magisk logs are empty, that\'s weird.</string>
|
||||||
<string name="menuSaveLog">Save log</string>
|
<string name="menuSaveLog">Save log</string>
|
||||||
<string name="menuClearLog">Clear log now</string>
|
<string name="menuClearLog">Clear log now</string>
|
||||||
<string name="logs_cleared">Log successfully cleared</string>
|
<string name="logs_cleared">Log successfully cleared</string>
|
||||||
<string name="pid">PID: %1$d</string>
|
<string name="pid">PID: %1$d</string>
|
||||||
<string name="target_uid">Target UID: %1$d</string>
|
<string name="target_uid">Target UID: %1$d</string>
|
||||||
<string name="target_pid">Mount ns target PID: %s</string>
|
<string name="target_pid">Target PID: %s</string>
|
||||||
<string name="selinux_context">SELinux context: %s</string>
|
<string name="selinux_context">SELinux context: %s</string>
|
||||||
<string name="supp_group">Supplementary group: %s</string>
|
<string name="supp_group">Supplementary group: %s</string>
|
||||||
|
|
||||||
<!--SafetyNet-->
|
|
||||||
|
|
||||||
<!--MagiskHide-->
|
<!--MagiskHide-->
|
||||||
<string name="show_system_app">Show system apps</string>
|
<string name="show_system_app">Show system apps</string>
|
||||||
<string name="show_os_app">Show OS apps</string>
|
<string name="show_os_app">Show OS apps</string>
|
||||||
@@ -112,20 +109,20 @@
|
|||||||
<string name="module_action">Action</string>
|
<string name="module_action">Action</string>
|
||||||
<string name="module_state_restore">Restore</string>
|
<string name="module_state_restore">Restore</string>
|
||||||
<string name="module_action_install_external">Install from storage</string>
|
<string name="module_action_install_external">Install from storage</string>
|
||||||
<string name="update_available">Update Available</string>
|
<string name="update_available">Update available</string>
|
||||||
<string name="suspend_text_riru">Module suspended because %1$s is enabled</string>
|
<string name="suspend_text_riru">Module suspended because %1$s is enabled</string>
|
||||||
<string name="suspend_text_zygisk">Module suspended because %1$s is not enabled</string>
|
<string name="suspend_text_zygisk">Module suspended because %1$s isn\'t enabled</string>
|
||||||
<string name="zygisk_module_unloaded">Zygisk module not loaded due to incompatibility</string>
|
<string name="zygisk_module_unloaded">Zygisk module not loaded due to incompatibility</string>
|
||||||
<string name="module_empty">No module installed</string>
|
<string name="module_empty">No module installed</string>
|
||||||
<string name="confirm_install">Install module %1$s?</string>
|
<string name="confirm_install">Install module %1$s?</string>
|
||||||
<string name="confirm_install_title">Install Confirmation</string>
|
<string name="confirm_install_title">Install confirmation</string>
|
||||||
|
|
||||||
<!--Settings-->
|
<!--Settings-->
|
||||||
<string name="settings_dark_mode_title">Theme Mode</string>
|
<string name="settings_dark_mode_title">Theme mode</string>
|
||||||
<string name="settings_dark_mode_message">Select mode which best suits your style!</string>
|
<string name="settings_dark_mode_message">Select mode which best suits your style!</string>
|
||||||
<string name="settings_dark_mode_light">Always Light</string>
|
<string name="settings_dark_mode_light">Always light</string>
|
||||||
<string name="settings_dark_mode_system">Follow System</string>
|
<string name="settings_dark_mode_system">Follow system</string>
|
||||||
<string name="settings_dark_mode_dark">Always Dark</string>
|
<string name="settings_dark_mode_dark">Always dark</string>
|
||||||
<string name="settings_download_path_title">Download path</string>
|
<string name="settings_download_path_title">Download path</string>
|
||||||
<string name="settings_download_path_message">Files will be saved to %1$s</string>
|
<string name="settings_download_path_message">Files will be saved to %1$s</string>
|
||||||
<string name="settings_hide_app_title">Hide the Magisk app</string>
|
<string name="settings_hide_app_title">Hide the Magisk app</string>
|
||||||
@@ -133,15 +130,16 @@
|
|||||||
<string name="settings_restore_app_title">Restore the Magisk app</string>
|
<string name="settings_restore_app_title">Restore the Magisk app</string>
|
||||||
<string name="settings_restore_app_summary">Unhide the app and restore the original APK</string>
|
<string name="settings_restore_app_summary">Unhide the app and restore the original APK</string>
|
||||||
<string name="language">Language</string>
|
<string name="language">Language</string>
|
||||||
<string name="system_default">(System Default)</string>
|
<string name="system_default">(System default)</string>
|
||||||
<string name="settings_check_update_title">Check Updates</string>
|
<string name="settings_check_update_title">Check for updates</string>
|
||||||
<string name="settings_check_update_summary">Periodically check for updates in the background</string>
|
<string name="settings_check_update_summary">Periodically check for updates in the background</string>
|
||||||
<string name="settings_update_channel_title">Update Channel</string>
|
<string name="settings_update_channel_title">Update channel</string>
|
||||||
<string name="settings_update_stable">Stable</string>
|
<string name="settings_update_stable">Stable</string>
|
||||||
<string name="settings_update_beta">Beta</string>
|
<string name="settings_update_beta">Beta</string>
|
||||||
|
<string name="settings_update_debug">Debug</string>
|
||||||
<string name="settings_update_custom">Custom</string>
|
<string name="settings_update_custom">Custom</string>
|
||||||
<string name="settings_update_custom_msg">Insert a custom channel URL</string>
|
<string name="settings_update_custom_msg">Insert a custom channel URL</string>
|
||||||
<string name="settings_zygisk_summary">Run parts of Magisk in the zygote daemon</string>
|
<string name="settings_zygisk_summary">Run parts of Magisk in the Zygote daemon</string>
|
||||||
<string name="settings_denylist_title">Enforce DenyList</string>
|
<string name="settings_denylist_title">Enforce DenyList</string>
|
||||||
<string name="settings_denylist_summary">Processes on the denylist will have all Magisk modifications reverted</string>
|
<string name="settings_denylist_summary">Processes on the denylist will have all Magisk modifications reverted</string>
|
||||||
<string name="settings_denylist_config_title">Configure DenyList</string>
|
<string name="settings_denylist_config_title">Configure DenyList</string>
|
||||||
@@ -162,48 +160,48 @@
|
|||||||
<string name="settings_su_request_30">30 seconds</string>
|
<string name="settings_su_request_30">30 seconds</string>
|
||||||
<string name="settings_su_request_45">45 seconds</string>
|
<string name="settings_su_request_45">45 seconds</string>
|
||||||
<string name="settings_su_request_60">60 seconds</string>
|
<string name="settings_su_request_60">60 seconds</string>
|
||||||
<string name="superuser_access">Superuser Access</string>
|
<string name="superuser_access">Superuser access</string>
|
||||||
<string name="auto_response">Automatic Response</string>
|
<string name="auto_response">Automatic response</string>
|
||||||
<string name="request_timeout">Request Timeout</string>
|
<string name="request_timeout">Request timeout</string>
|
||||||
<string name="superuser_notification">Superuser Notification</string>
|
<string name="superuser_notification">Superuser notification</string>
|
||||||
<string name="settings_su_reauth_title">Reauthenticate after upgrade</string>
|
<string name="settings_su_reauth_title">Reauthenticate after upgrade</string>
|
||||||
<string name="settings_su_reauth_summary">Ask for Superuser permissions again after upgrading apps</string>
|
<string name="settings_su_reauth_summary">Ask for Superuser permissions again after upgrading apps</string>
|
||||||
<string name="settings_su_tapjack_title">Tapjacking Protection</string>
|
<string name="settings_su_tapjack_title">Tapjacking protection</string>
|
||||||
<string name="settings_su_tapjack_summary">The Superuser prompt dialog will not respond to input while obscured by any other window or overlay</string>
|
<string name="settings_su_tapjack_summary">The Superuser prompt dialog won\'t respond to input while obscured by any other window or overlay</string>
|
||||||
<string name="settings_su_auth_title">User Authentication</string>
|
<string name="settings_su_auth_title">User authentication</string>
|
||||||
<string name="settings_su_auth_summary">Ask for user authentication during Superuser requests</string>
|
<string name="settings_su_auth_summary">Ask for user authentication during Superuser requests</string>
|
||||||
<string name="settings_su_auth_insecure">No authentication method is configured on the device</string>
|
<string name="settings_su_auth_insecure">No authentication method is configured on the device</string>
|
||||||
|
<string name="settings_su_restrict_title">Restrict root capabilities</string>
|
||||||
|
<string name="settings_su_restrict_summary">Will restrict new superuser apps by default. Warning, this will break most apps, do not enable it.</string>
|
||||||
<string name="settings_customization">Customization</string>
|
<string name="settings_customization">Customization</string>
|
||||||
<string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string>
|
<string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string>
|
||||||
<string name="settings_doh_title">DNS over HTTPS</string>
|
<string name="settings_doh_title">DNS over HTTPS</string>
|
||||||
<string name="settings_doh_description">Workaround DNS poisoning in some nations</string>
|
<string name="settings_doh_description">Workaround DNS poisoning in some nations</string>
|
||||||
<string name="settings_random_name_title">Randomize output name</string>
|
<string name="settings_random_name_title">Randomize output name</string>
|
||||||
<string name="settings_random_name_description">Randomize the output file name of patched images and tar files to prevent detection</string>
|
<string name="settings_random_name_description">Randomize the output file name of patched images and tar files to prevent detection</string>
|
||||||
|
<string name="multiuser_mode">Multiuser mode</string>
|
||||||
<string name="multiuser_mode">Multiuser Mode</string>
|
<string name="settings_owner_only">Device owner only</string>
|
||||||
<string name="settings_owner_only">Device Owner Only</string>
|
<string name="settings_owner_manage">Device owner managed</string>
|
||||||
<string name="settings_owner_manage">Device Owner Managed</string>
|
<string name="settings_user_independent">User-independent</string>
|
||||||
<string name="settings_user_independent">User-Independent</string>
|
|
||||||
<string name="owner_only_summary">Only owner has root access</string>
|
<string name="owner_only_summary">Only owner has root access</string>
|
||||||
<string name="owner_manage_summary">Only owner can manage root access and receive request prompts</string>
|
<string name="owner_manage_summary">Only owner can manage root access and receive request prompts</string>
|
||||||
<string name="user_independent_summary">Each user has their own separate root rules</string>
|
<string name="user_independent_summary">Each user has their own separate root rules</string>
|
||||||
|
<string name="mount_namespace_mode">Mount namespace mode</string>
|
||||||
<string name="mount_namespace_mode">Mount Namespace Mode</string>
|
<string name="settings_ns_global">Global namespace</string>
|
||||||
<string name="settings_ns_global">Global Namespace</string>
|
<string name="settings_ns_requester">Inherit namespace</string>
|
||||||
<string name="settings_ns_requester">Inherit Namespace</string>
|
<string name="settings_ns_isolate">Isolated namespace</string>
|
||||||
<string name="settings_ns_isolate">Isolated Namespace</string>
|
|
||||||
<string name="global_summary">All root sessions use the global mount namespace</string>
|
<string name="global_summary">All root sessions use the global mount namespace</string>
|
||||||
<string name="requester_summary">Root sessions will inherit their requester\'s namespace</string>
|
<string name="requester_summary">Root sessions will inherit their requester\'s namespace</string>
|
||||||
<string name="isolate_summary">Each root session will have its own isolated namespace</string>
|
<string name="isolate_summary">Each root session will have its own isolated namespace</string>
|
||||||
|
|
||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="update_channel">Magisk Updates</string>
|
<string name="update_channel">Magisk updates</string>
|
||||||
<string name="progress_channel">Progress Notifications</string>
|
<string name="progress_channel">Progress notifications</string>
|
||||||
<string name="updated_channel">Update Complete</string>
|
<string name="updated_channel">Update complete</string>
|
||||||
<string name="download_complete">Download complete</string>
|
<string name="download_complete">Download complete</string>
|
||||||
<string name="download_file_error">Error downloading file</string>
|
<string name="download_file_error">Error downloading file</string>
|
||||||
<string name="magisk_update_title">Magisk Update Available!</string>
|
<string name="magisk_update_title">Magisk update available!</string>
|
||||||
<string name="updated_title">Magisk Updated</string>
|
<string name="updated_title">Magisk updated</string>
|
||||||
<string name="updated_text">Tap to open app</string>
|
<string name="updated_text">Tap to open app</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
@@ -221,27 +219,27 @@
|
|||||||
<string name="failure">Failed!</string>
|
<string name="failure">Failed!</string>
|
||||||
<string name="hide_app_title">Hiding the Magisk app…</string>
|
<string name="hide_app_title">Hiding the Magisk app…</string>
|
||||||
<string name="open_link_failed_toast">No app found to open the link</string>
|
<string name="open_link_failed_toast">No app found to open the link</string>
|
||||||
<string name="complete_uninstall">Complete Uninstall</string>
|
<string name="complete_uninstall">Complete uninstall</string>
|
||||||
<string name="restore_img">Restore Images</string>
|
<string name="restore_img">Restore images</string>
|
||||||
<string name="restore_img_msg">Restoring…</string>
|
<string name="restore_img_msg">Restoring…</string>
|
||||||
<string name="restore_done">Restoration done!</string>
|
<string name="restore_done">Restoration done!</string>
|
||||||
<string name="restore_fail">Stock backup does not exist!</string>
|
<string name="restore_fail">Stock backup doesn\'t exist!</string>
|
||||||
<string name="setup_fail">Setup failed</string>
|
<string name="setup_fail">Setup failed</string>
|
||||||
<string name="env_fix_title">Requires Additional Setup</string>
|
<string name="env_fix_title">Requires additional setup</string>
|
||||||
<string name="env_fix_msg">Your device needs additional setup for Magisk to work properly. Do you want to proceed and reboot?</string>
|
<string name="env_fix_msg">Your device needs additional setup for Magisk to work properly. Do you want to proceed and reboot?</string>
|
||||||
<string name="env_full_fix_msg">Your device needs reflash Magisk to work properly. Please reinstall Magisk within app, recovery mode cannot get correct device info.</string>
|
<string name="env_full_fix_msg">Your device needs reflash Magisk to work properly. Please reinstall Magisk within app, Recovery mode cannot get correct device info.</string>
|
||||||
<string name="setup_msg">Running environment setup…</string>
|
<string name="setup_msg">Running environment setup…</string>
|
||||||
<string name="unsupport_magisk_title">Unsupported Magisk Version</string>
|
<string name="unsupport_magisk_title">Unsupported Magisk version</string>
|
||||||
<string name="unsupport_magisk_msg">This version of the app does not support Magisk versions lower than %1$s.\n\nThe app will behave as if no Magisk is installed, please upgrade Magisk as soon as possible.</string>
|
<string name="unsupport_magisk_msg">This version of the app doesn\'t support Magisk versions lower than %1$s.\n\nThe app will behave as if no Magisk is installed. Please update Magisk as soon as possible.</string>
|
||||||
<string name="unsupport_general_title">Abnormal State</string>
|
<string name="unsupport_general_title">Abnormal state</string>
|
||||||
<string name="unsupport_system_app_msg">Running this app as a system app is not supported. Please revert the app to a user app.</string>
|
<string name="unsupport_system_app_msg">Running this app as a system app isn\'t supported. Please revert the app to a user app.</string>
|
||||||
<string name="unsupport_other_su_msg">A \"su\" binary not from Magisk has been detected. Please remove any competing root solution and/or reinstall Magisk.</string>
|
<string name="unsupport_other_su_msg">A \"su\" binary not from Magisk has been detected. Please remove any competing root solution and/or reinstall Magisk.</string>
|
||||||
<string name="unsupport_external_storage_msg">Magisk is installed to external storage. Please move the app to internal storage.</string>
|
<string name="unsupport_external_storage_msg">Magisk is installed to external storage. Please move the app to internal storage.</string>
|
||||||
<string name="unsupport_nonroot_stub_msg">The hidden Magisk app cannot continue to work because root was lost. Please restore the original APK.</string>
|
<string name="unsupport_nonroot_stub_msg">The hidden Magisk app cannot continue to work because root was lost. Please restore the original APK.</string>
|
||||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
<string name="external_rw_permission_denied">Grant storage permission to enable this functionality</string>
|
<string name="external_rw_permission_denied">Grant storage permission to enable this functionality</string>
|
||||||
<string name="post_notifications_denied">Grant notifications permission to enable this functionality</string>
|
<string name="post_notifications_denied">Grant notifications permission to enable this functionality</string>
|
||||||
<string name="install_unknown_denied">Allow "install unknown apps" to enable this functionality</string>
|
<string name="install_unknown_denied">Allow \"Install unknown apps\" to enable this functionality</string>
|
||||||
<string name="add_shortcut_title">Add shortcut to home screen</string>
|
<string name="add_shortcut_title">Add shortcut to home screen</string>
|
||||||
<string name="add_shortcut_msg">After hiding this app, its name and icon might become difficult to recognize. Do you want to add a pretty shortcut to the home screen?</string>
|
<string name="add_shortcut_msg">After hiding this app, its name and icon might become difficult to recognize. Do you want to add a pretty shortcut to the home screen?</string>
|
||||||
<string name="app_not_found">No app found to handle this action</string>
|
<string name="app_not_found">No app found to handle this action</string>
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ android.nonFinalResIds=false
|
|||||||
|
|
||||||
# Magisk
|
# Magisk
|
||||||
magisk.stubVersion=40
|
magisk.stubVersion=40
|
||||||
magisk.versionCode=29000
|
magisk.versionCode=30100
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
[versions]
|
[versions]
|
||||||
kotlin = "2.1.20"
|
kotlin = "2.1.21"
|
||||||
android = "8.9.2"
|
android = "8.11.0"
|
||||||
ksp = "2.1.20-1.0.31"
|
ksp = "2.1.21-2.0.1"
|
||||||
rikka = "1.3.0"
|
rikka = "1.3.0"
|
||||||
navigation = "2.8.9"
|
navigation = "2.9.0"
|
||||||
libsu = "6.0.0"
|
libsu = "6.0.0"
|
||||||
moshi = "1.15.2"
|
|
||||||
okhttp = "4.12.0"
|
okhttp = "4.12.0"
|
||||||
retrofit = "2.11.0"
|
retrofit = "3.0.0"
|
||||||
room = "2.7.1"
|
room = "2.7.2"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
bcpkix = { module = "org.bouncycastle:bcpkix-jdk18on", version = "1.80" }
|
bcpkix = { module = "org.bouncycastle:bcpkix-jdk18on", version = "1.81" }
|
||||||
commons-compress = { module = "org.apache.commons:commons-compress", version = "1.27.1" }
|
commons-compress = { module = "org.apache.commons:commons-compress", version = "1.27.1" }
|
||||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||||
retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" }
|
retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" }
|
||||||
@@ -20,18 +19,16 @@ markwon-core = { module = "io.noties.markwon:core", version = "4.6.2" }
|
|||||||
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||||
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" }
|
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" }
|
||||||
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
|
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
|
||||||
moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi" }
|
|
||||||
moshi-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi" }
|
|
||||||
timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" }
|
timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" }
|
||||||
jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version = "7.1.0.202411261347-r" }
|
jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version = "7.1.0.202411261347-r" }
|
||||||
|
|
||||||
# AndroidX
|
# AndroidX
|
||||||
activity = { module = "androidx.activity:activity", version = "1.10.1" }
|
activity = { module = "androidx.activity:activity", version = "1.10.1" }
|
||||||
appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.0" }
|
appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.1" }
|
||||||
core-ktx = { module = "androidx.core:core-ktx", version = "1.16.0" }
|
core-ktx = { module = "androidx.core:core-ktx", version = "1.16.0" }
|
||||||
core-splashscreen = { module = "androidx.core:core-splashscreen", version = "1.0.1" }
|
core-splashscreen = { module = "androidx.core:core-splashscreen", version = "1.0.1" }
|
||||||
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.2.1" }
|
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.2.1" }
|
||||||
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.6" }
|
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.8" }
|
||||||
navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
|
navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
|
||||||
navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
|
navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
|
||||||
profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version = "1.4.1" }
|
profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version = "1.4.1" }
|
||||||
@@ -65,5 +62,6 @@ android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref
|
|||||||
ksp-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
|
ksp-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
|
||||||
navigation-safe-args-plugin = { module = "androidx.navigation:navigation-safe-args-gradle-plugin", version.ref = "navigation" }
|
navigation-safe-args-plugin = { module = "androidx.navigation:navigation-safe-args-gradle-plugin", version.ref = "navigation" }
|
||||||
lsparanoid-plugin = { module = "org.lsposed.lsparanoid:gradle-plugin", version = "0.6.0" }
|
lsparanoid-plugin = { module = "org.lsposed.lsparanoid:gradle-plugin", version = "0.6.0" }
|
||||||
|
moshi-plugin = { module = "dev.zacsweers.moshix:dev.zacsweers.moshix.gradle.plugin", version = "0.30.0" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
|||||||
BIN
app/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
app/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
app/gradle/wrapper/gradle-wrapper.properties
vendored
2
app/gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
6
app/gradlew
vendored
6
app/gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -205,7 +205,7 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-classpath "$CLASSPATH" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
4
app/gradlew.bat
vendored
4
app/gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
|||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -13,24 +13,28 @@ android {
|
|||||||
namespace = "com.topjohnwu.magisk"
|
namespace = "com.topjohnwu.magisk"
|
||||||
|
|
||||||
val canary = !Config.version.contains(".")
|
val canary = !Config.version.contains(".")
|
||||||
|
val base = "https://github.com/topjohnwu/Magisk/releases/download/"
|
||||||
val url = if (canary) null
|
val url = base + "v${Config.version}/Magisk-v${Config.version}.apk"
|
||||||
else "https://github.com/topjohnwu/Magisk/releases/download/v${Config.version}/Magisk-v${Config.version}.apk"
|
val canaryUrl = base + "canary-${Config.versionCode}/"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.topjohnwu.magisk"
|
applicationId = "com.topjohnwu.magisk"
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
buildConfigField("String", "APK_URL", url?.let { "\"$it\"" } ?: "null" )
|
buildConfigField("String", "APK_URL", "\"$url\"")
|
||||||
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
|
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
if (canary) buildConfigField("String", "APK_URL", "\"${canaryUrl}app-release.apk\"")
|
||||||
proguardFiles("proguard-rules.pro")
|
proguardFiles("proguard-rules.pro")
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
isShrinkResources = false
|
isShrinkResources = false
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
if (canary) buildConfigField("String", "APK_URL", "\"${canaryUrl}app-debug.apk\"")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import com.topjohnwu.magisk.net.Networking;
|
|||||||
import com.topjohnwu.magisk.net.Request;
|
import com.topjohnwu.magisk.net.Request;
|
||||||
import com.topjohnwu.magisk.utils.APKInstall;
|
import com.topjohnwu.magisk.utils.APKInstall;
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@@ -48,13 +46,8 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
public class DownloadActivity extends Activity {
|
public class DownloadActivity extends Activity {
|
||||||
|
|
||||||
private static final String APP_NAME = "Magisk";
|
private static final String APP_NAME = "Magisk";
|
||||||
private static final String JSON_URL = BuildConfig.DEBUG ?
|
|
||||||
"https://topjohnwu.github.io/magisk-files/debug.json" :
|
|
||||||
"https://topjohnwu.github.io/magisk-files/canary.json";
|
|
||||||
|
|
||||||
private String apkLink = BuildConfig.APK_URL;
|
|
||||||
private Context themed;
|
private Context themed;
|
||||||
private ProgressDialog dialog;
|
|
||||||
private boolean dynLoad;
|
private boolean dynLoad;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,11 +68,7 @@ public class DownloadActivity extends Activity {
|
|||||||
ProviderInstaller.install(this);
|
ProviderInstaller.install(this);
|
||||||
|
|
||||||
if (Networking.checkNetworkStatus(this)) {
|
if (Networking.checkNetworkStatus(this)) {
|
||||||
if (BuildConfig.APK_URL == null) {
|
showDialog();
|
||||||
fetchCanary();
|
|
||||||
} else {
|
|
||||||
showDialog();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
new AlertDialog.Builder(themed)
|
new AlertDialog.Builder(themed)
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
@@ -115,23 +104,10 @@ public class DownloadActivity extends Activity {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchCanary() {
|
|
||||||
dialog = ProgressDialog.show(themed, "", "", true);
|
|
||||||
request(JSON_URL).getAsJSONObject(json -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
try {
|
|
||||||
apkLink = json.getJSONObject("magisk").getString("link");
|
|
||||||
showDialog();
|
|
||||||
} catch (JSONException e) {
|
|
||||||
error(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dlAPK() {
|
private void dlAPK() {
|
||||||
dialog = ProgressDialog.show(themed, getString(dling), getString(dling) + " " + APP_NAME, true);
|
ProgressDialog.show(themed, getString(dling), getString(dling) + " " + APP_NAME, true);
|
||||||
// Download and upgrade the app
|
// Download and upgrade the app
|
||||||
var request = request(apkLink).setExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
var request = request(BuildConfig.APK_URL).setExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
if (dynLoad) {
|
if (dynLoad) {
|
||||||
request.getAsFile(StubApk.current(this), file -> StubApk.restartProcess(this));
|
request.getAsFile(StubApk.current(this), file -> StubApk.restartProcess(this));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
8
app/stub/src/main/res/values-b+sr+Latn/strings.xml
Normal file
8
app/stub/src/main/res/values-b+sr+Latn/strings.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--Author: Radoš Milićev (https://github.com/rammba)-->
|
||||||
|
<resources>
|
||||||
|
<string name="upgrade_msg">Ažurirajte Magisk da biste završili postavljanje. Preuzmi i instaliraj?</string>
|
||||||
|
<string name="no_internet_msg">Molimo povežite se na internet! Neophodno je ažuriranje Magisk-a.</string>
|
||||||
|
<string name="dling">Preuzimanje</string>
|
||||||
|
<string name="relaunch_app">Molimo pokrenite aplikaciju ponovo</string>
|
||||||
|
</resources>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="upgrade_msg">Atualize para o Magisk completo para finalizar a configuração. Deseja baixar e instalar?</string>
|
<string name="upgrade_msg">Atualize para o Magisk completo para finalizar a configuração. Deseja descarregar e instalar?</string>
|
||||||
<string name="no_internet_msg">Por favor, conecte-se à internet! É necessário atualizar para o Magisk completo.</string>
|
<string name="no_internet_msg">Por favor, ligue-se à internet! É necessário atualizar para o Magisk completo.</string>
|
||||||
<string name="dling">Baixando</string>
|
<string name="dling">A descarregar</string>
|
||||||
<string name="relaunch_app">Por favor, reinicie o app manualmente.</string>
|
<string name="relaunch_app">Por favor, reinicie o app manualmente.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--Author: Radoš Milićev (https://github.com/rammba)-->
|
||||||
<resources>
|
<resources>
|
||||||
<string name="upgrade_msg">Ажурирајте Magisk да бисте завршили постављање. Преузми и инсталирај?</string>
|
<string name="upgrade_msg">Ажурирајте Magisk да бисте завршили постављање. Преузми и инсталирај?</string>
|
||||||
<string name="no_internet_msg">Молимо повежите се на интернет! Неопходно је ажурирање Magisk-а.</string>
|
<string name="no_internet_msg">Молимо повежите се на интернет! Неопходно је ажурирање Magisk-а.</string>
|
||||||
|
|||||||
45
build.py
45
build.py
@@ -71,7 +71,7 @@ default_archs = {"armeabi-v7a", "x86", "arm64-v8a", "x86_64"}
|
|||||||
default_targets = {"magisk", "magiskinit", "magiskboot", "magiskpolicy"}
|
default_targets = {"magisk", "magiskinit", "magiskboot", "magiskpolicy"}
|
||||||
support_targets = default_targets | {"resetprop"}
|
support_targets = default_targets | {"resetprop"}
|
||||||
rust_targets = {"magisk", "magiskinit", "magiskboot", "magiskpolicy"}
|
rust_targets = {"magisk", "magiskinit", "magiskboot", "magiskpolicy"}
|
||||||
ondk_version = "r29.1"
|
ondk_version = "r28.5"
|
||||||
|
|
||||||
# Global vars
|
# Global vars
|
||||||
config = {}
|
config = {}
|
||||||
@@ -291,15 +291,7 @@ def write_if_diff(file_name: Path, text: str):
|
|||||||
|
|
||||||
|
|
||||||
def dump_flag_header():
|
def dump_flag_header():
|
||||||
flag_txt = textwrap.dedent(
|
flag_txt = "#pragma once\n"
|
||||||
"""\
|
|
||||||
#pragma once
|
|
||||||
#define quote(s) #s
|
|
||||||
#define str(s) quote(s)
|
|
||||||
#define MAGISK_FULL_VER MAGISK_VERSION "(" str(MAGISK_VER_CODE) ")"
|
|
||||||
#define NAME_WITH_VER(name) str(name) " " MAGISK_FULL_VER
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
flag_txt += f'#define MAGISK_VERSION "{config["version"]}"\n'
|
flag_txt += f'#define MAGISK_VERSION "{config["version"]}"\n'
|
||||||
flag_txt += f'#define MAGISK_VER_CODE {config["versionCode"]}\n'
|
flag_txt += f'#define MAGISK_VER_CODE {config["versionCode"]}\n'
|
||||||
flag_txt += f"#define MAGISK_DEBUG {0 if args.release else 1}\n"
|
flag_txt += f"#define MAGISK_DEBUG {0 if args.release else 1}\n"
|
||||||
@@ -313,7 +305,7 @@ def dump_flag_header():
|
|||||||
write_if_diff(native_gen_path / "flags.rs", rust_flag_txt)
|
write_if_diff(native_gen_path / "flags.rs", rust_flag_txt)
|
||||||
|
|
||||||
|
|
||||||
def build_native():
|
def ensure_toolchain():
|
||||||
ensure_paths()
|
ensure_paths()
|
||||||
|
|
||||||
# Verify NDK install
|
# Verify NDK install
|
||||||
@@ -323,6 +315,17 @@ def build_native():
|
|||||||
except:
|
except:
|
||||||
error('Unmatched NDK. Please install/upgrade NDK with "build.py ndk"')
|
error('Unmatched NDK. Please install/upgrade NDK with "build.py ndk"')
|
||||||
|
|
||||||
|
if sccache := shutil.which("sccache"):
|
||||||
|
os.environ["RUSTC_WRAPPER"] = sccache
|
||||||
|
os.environ["NDK_CCACHE"] = sccache
|
||||||
|
os.environ["CARGO_INCREMENTAL"] = "0"
|
||||||
|
if ccache := shutil.which("ccache"):
|
||||||
|
os.environ["NDK_CCACHE"] = ccache
|
||||||
|
|
||||||
|
|
||||||
|
def build_native():
|
||||||
|
ensure_toolchain()
|
||||||
|
|
||||||
if "targets" not in vars(args) or not args.targets:
|
if "targets" not in vars(args) or not args.targets:
|
||||||
targets = default_targets
|
targets = default_targets
|
||||||
else:
|
else:
|
||||||
@@ -332,13 +335,6 @@ def build_native():
|
|||||||
|
|
||||||
header("* Building: " + " ".join(targets))
|
header("* Building: " + " ".join(targets))
|
||||||
|
|
||||||
if sccache := shutil.which("sccache"):
|
|
||||||
os.environ["RUSTC_WRAPPER"] = sccache
|
|
||||||
os.environ["NDK_CCACHE"] = sccache
|
|
||||||
os.environ["CARGO_INCREMENTAL"] = "0"
|
|
||||||
if ccache := shutil.which("ccache"):
|
|
||||||
os.environ["NDK_CCACHE"] = ccache
|
|
||||||
|
|
||||||
dump_flag_header()
|
dump_flag_header()
|
||||||
build_rust_src(targets)
|
build_rust_src(targets)
|
||||||
build_cpp_src(targets)
|
build_cpp_src(targets)
|
||||||
@@ -532,6 +528,7 @@ def gen_ide():
|
|||||||
|
|
||||||
|
|
||||||
def clippy_cli():
|
def clippy_cli():
|
||||||
|
ensure_toolchain()
|
||||||
args.force_out = True
|
args.force_out = True
|
||||||
set_archs(default_archs)
|
set_archs(default_archs)
|
||||||
|
|
||||||
@@ -642,11 +639,11 @@ def push_files(script):
|
|||||||
def setup_avd():
|
def setup_avd():
|
||||||
header("* Setting up emulator")
|
header("* Setting up emulator")
|
||||||
|
|
||||||
push_files(Path("scripts", "avd_magisk.sh"))
|
push_files(Path("scripts", "live_setup.sh"))
|
||||||
|
|
||||||
proc = execv([adb_path, "shell", "sh", "/data/local/tmp/avd_magisk.sh"])
|
proc = execv([adb_path, "shell", "sh", "/data/local/tmp/live_setup.sh"])
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
error("avd_magisk.sh failed!")
|
error("live_setup.sh failed!")
|
||||||
|
|
||||||
|
|
||||||
def patch_avd_file():
|
def patch_avd_file():
|
||||||
@@ -655,7 +652,7 @@ def patch_avd_file():
|
|||||||
|
|
||||||
header(f"* Patching {input.name}")
|
header(f"* Patching {input.name}")
|
||||||
|
|
||||||
push_files(Path("scripts", "avd_patch.sh"))
|
push_files(Path("scripts", "host_patch.sh"))
|
||||||
|
|
||||||
proc = execv([adb_path, "push", input, "/data/local/tmp"])
|
proc = execv([adb_path, "push", input, "/data/local/tmp"])
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
@@ -664,9 +661,9 @@ def patch_avd_file():
|
|||||||
src_file = f"/data/local/tmp/{input.name}"
|
src_file = f"/data/local/tmp/{input.name}"
|
||||||
out_file = f"{src_file}.magisk"
|
out_file = f"{src_file}.magisk"
|
||||||
|
|
||||||
proc = execv([adb_path, "shell", "sh", "/data/local/tmp/avd_patch.sh", src_file])
|
proc = execv([adb_path, "shell", "sh", "/data/local/tmp/host_patch.sh", src_file])
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
error("avd_patch.sh failed!")
|
error("host_patch.sh failed!")
|
||||||
|
|
||||||
proc = execv([adb_path, "pull", out_file, output])
|
proc = execv([adb_path, "pull", out_file, output])
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
# Magisk Changelog
|
# Magisk Changelog
|
||||||
|
|
||||||
|
### v30.0
|
||||||
|
|
||||||
|
- [General] Various minor bug fixes
|
||||||
|
- [Core] Migrate module implementation to Rust
|
||||||
|
- [Core] Improve Magisk specific files injection logic
|
||||||
|
- [MagiskBoot] Migrate compression code to Rust
|
||||||
|
|
||||||
### v29.0
|
### v29.0
|
||||||
|
|
||||||
- [General] Massive internal refactoring and code migration
|
- [General] Massive internal refactoring and code migration
|
||||||
- [App] Support downloading module zip files with XZ compression
|
- [App] Support downloading module zip files with XZ compression
|
||||||
- [App] Disable app animations when system animations are disabled
|
- [App] Disable app animations when system animations are disabled
|
||||||
- [MagiskMount] Support systemlessly deleting files with modules using blank file nodes
|
- [Core] Support systemlessly deleting files with modules using blank file nodes
|
||||||
- [MagiskInit] Redesign sepolicy patching and injection logic
|
- [MagiskInit] Redesign sepolicy patching and injection logic
|
||||||
- [MagiskSU] Better TTY/PTY support
|
- [MagiskSU] Better TTY/PTY support
|
||||||
|
|
||||||
|
|||||||
12
docs/faq.md
12
docs/faq.md
@@ -16,9 +16,17 @@ The following details should ensure that modules are properly disabled:
|
|||||||
|
|
||||||
Magisk no longer handles root hiding. There are plenty of Magisk/Zygisk modules available that specifically provide these functionalities, please search around 😉
|
Magisk no longer handles root hiding. There are plenty of Magisk/Zygisk modules available that specifically provide these functionalities, please search around 😉
|
||||||
|
|
||||||
### Q: After I hidden the Magisk app, the app icon is broken.
|
### Q: Magisk App shows Magisk Installed = N/A after an update but magisk su is still working.
|
||||||
|
|
||||||
When hiding the Magisk app, it will install a "stub" APK that has nothing in it. The only functionality this stub app has is downloading the full Magisk app APK into its internal storage and dynamically loading it. Due to the fact that the APK is literally _empty_, it does not contain the image resource for the app icon.
|
If upgrading with App hidden (ie. you took the 'Hide the Magisk app' option), the stub app (for hiding Magisk) may remain while a full Magisk app is also installed. This creates a conflict and the full app fails to see or access root... Uninstalling and reinstalling the full app can fix this, but not if a hidden app (stub) still exists.
|
||||||
|
|
||||||
|
The solution is to check for a hidden stub app and remove it. It may not show up normally in your launcher homescreen any longer, but should be visible from general settings, Apps. The hidden app will be named 'Settings' (default) or whatever you named it during the hiding process. Note that it is possible to have multiple obfuscated apps present. Uninstall any iterations of the hidden app you find and try opening the full app again. If necessary, uninstall it and reinstall the full app matching the binaries installed. Typing magisk -c in a terminal emulator app will show the version and version code for Magisk binaries installed (despite Installed = N/A showing).
|
||||||
|
|
||||||
|
Additionally, if a 'second space', eg. Workspace, Parallel Space etc, or another sandboxed environment, eg. a Multiple User additional profile, Island app or similar, is set up, check that no iterations of Magisk (either hidden or full apps) are running within these environments.
|
||||||
|
|
||||||
|
### Q: After I take the 'Hide the Magisk app' option the app icon is broken.
|
||||||
|
|
||||||
|
When hiding the Magisk app, it will install a "stub" APK that has nothing in it. The only functionality this stub app has is to download the full Magisk app APK data into its internal storage and dynamically load it. Due to the fact that the stub APK is literally empty, it does not contain the image resource for the app icon.
|
||||||
|
|
||||||
When you open the hidden Magisk app, it will offer you the option to create a shortcut in the homescreen (which has both the correct app name and icon) for your convenience. You can also manually ask the app to create the icon in app settings.
|
When you open the hidden Magisk app, it will offer you the option to create a shortcut in the homescreen (which has both the correct app name and icon) for your convenience. You can also manually ask the app to create the icon in app settings.
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("com.android.library")
|
|
||||||
}
|
|
||||||
|
|
||||||
setupCommon()
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "com.topjohnwu.magisk.binary"
|
|
||||||
|
|
||||||
externalNativeBuild {
|
|
||||||
ndkBuild {
|
|
||||||
path("src/Android.mk")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets.getByName("main") {
|
|
||||||
manifest.srcFile("src/AndroidManifest.xml")
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
externalNativeBuild {
|
|
||||||
ndkBuild {
|
|
||||||
// Pass arguments to ndk-build.
|
|
||||||
arguments(
|
|
||||||
"B_MAGISK=1", "B_INIT=1", "B_BOOT=1", "B_POLICY=1",
|
|
||||||
"B_PRELOAD=1", "B_PROP=1", "B_CRT0=1"
|
|
||||||
)
|
|
||||||
abiFilters("armeabi-v7a", "arm64-v8a", "x86", "x86_64", "riscv64")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -85,13 +85,11 @@ LOCAL_STATIC_LIBRARIES := \
|
|||||||
libbase \
|
libbase \
|
||||||
liblzma \
|
liblzma \
|
||||||
liblz4 \
|
liblz4 \
|
||||||
libzopfli \
|
|
||||||
libboot-rs
|
libboot-rs
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
boot/main.cpp \
|
boot/main.cpp \
|
||||||
boot/bootimg.cpp \
|
boot/bootimg.cpp \
|
||||||
boot/compress.cpp \
|
|
||||||
boot/format.cpp \
|
boot/format.cpp \
|
||||||
boot/boot-rs.cpp
|
boot/boot-rs.cpp
|
||||||
|
|
||||||
@@ -99,7 +97,7 @@ LOCAL_LDFLAGS := -static
|
|||||||
|
|
||||||
ifdef B_CRT0
|
ifdef B_CRT0
|
||||||
LOCAL_STATIC_LIBRARIES += crt0
|
LOCAL_STATIC_LIBRARIES += crt0
|
||||||
LOCAL_LDFLAGS += -lm
|
LOCAL_LDFLAGS += -lm -Wl,--defsym=vfprintf=musl_vfprintf
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
<!-- This file exists only to make Android Studio happy -->
|
|
||||||
<manifest/>
|
|
||||||
383
native/src/Cargo.lock
generated
383
native/src/Cargo.lock
generated
@@ -3,10 +3,16 @@
|
|||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle"
|
name = "adler2"
|
||||||
version = "1.0.10"
|
version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "argh"
|
name = "argh"
|
||||||
@@ -67,9 +73,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64ct"
|
name = "base64ct"
|
||||||
version = "1.7.3"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
@@ -87,19 +93,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "bitflags"
|
||||||
version = "0.11.0-rc.3"
|
version = "2.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fd016a0ddc7cb13661bf5576073ce07330a693f8608a1320b4e20561cc12cdc"
|
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.11.0-rc.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a229bfd78e4827c91b9b95784f69492c1b77c1ab75a45a8a037b139215086f94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bumpalo"
|
||||||
version = "1.22.0"
|
version = "3.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
|
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
@@ -122,34 +140,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "bzip2"
|
||||||
version = "1.2.19"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
|
||||||
|
dependencies = [
|
||||||
|
"bzip2-sys",
|
||||||
|
"libbz2-rs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bzip2-sys"
|
||||||
|
version = "0.1.13+1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.35"
|
version = "4.5.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.35"
|
version = "4.5.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
@@ -158,9 +196,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.4"
|
version = "0.7.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
@@ -208,10 +246,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-bigint"
|
name = "crc32fast"
|
||||||
version = "0.6.1"
|
version = "1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96272c2ff28b807e09250b180ad1fb7889a3258f7455759b5c3c58b719467130"
|
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-bigint"
|
||||||
|
version = "0.7.0-pre.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "edaae5fb9dac79a07260e0b2006799ff4f1d342ab243fd7d0892215113b27904"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -223,22 +270,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.2.0-rc.1"
|
version = "0.2.0-rc.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0b8ce8218c97789f16356e7896b3714f26c2ee1079b79c0b7ae7064bb9089fa"
|
checksum = "8a23fa214dea9efd4dacee5a5614646b30216ae0f05d4bb51bafb50e9da1c5be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
"rand_core",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-primes"
|
name = "crypto-primes"
|
||||||
version = "0.6.2"
|
version = "0.7.0-pre.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2acbaf157961745008b5a80ee1cc974150691304fe9177edf69747142bfd9878"
|
checksum = "ae744b9f528151f8c440cf67498f24d2d1ac0ab536b5ce7b1f87a7a5961bd1c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-bigint",
|
"crypto-bigint",
|
||||||
|
"libm",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -290,9 +336,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.8.0-rc.1"
|
version = "0.8.0-rc.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82db698b33305f0134faf590b9d1259dc171b5481ac41d5c8146c3b3ee7d4319"
|
checksum = "0c2e6107818886eff6b71fba7a2da3dd11025ebb80f0c9b94ff961168ef629f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"der_derive",
|
"der_derive",
|
||||||
@@ -303,9 +349,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der_derive"
|
name = "der_derive"
|
||||||
version = "0.8.0-rc.1"
|
version = "0.8.0-rc.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "211bea8bb45f5f61bc857104606913ef8ac8b5ec698143aa2aa96a7ffdc94991"
|
checksum = "d184a65ac0a9db9e66e0d629bea86d0402198b2a5cc01c9c16de7a6537f0ac4f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -323,9 +369,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.11.0-pre.9"
|
version = "0.11.0-rc.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf2e3d6615d99707295a9673e889bf363a04b2a466bd320c65a72536f7577379"
|
checksum = "460dd7f37e4950526b54a5a6b1f41b6c8e763c58eb9a8fc8fc05ba5c2f44ca7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"const-oid",
|
"const-oid",
|
||||||
@@ -335,9 +381,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ecdsa"
|
name = "ecdsa"
|
||||||
version = "0.17.0-pre.9"
|
version = "0.17.0-rc.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e62f2041a28c40b8884b79fbd19bc7457d76c6397767831e9ff4029fc0473a9"
|
checksum = "6ca18d8009d96ffc2a8b771c7432338233ffcfa05e4ca410ed77900a2a335a0b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"der",
|
"der",
|
||||||
"digest",
|
"digest",
|
||||||
@@ -345,20 +391,20 @@ dependencies = [
|
|||||||
"rfc6979",
|
"rfc6979",
|
||||||
"signature",
|
"signature",
|
||||||
"spki",
|
"spki",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "elliptic-curve"
|
name = "elliptic-curve"
|
||||||
version = "0.14.0-rc.1"
|
version = "0.14.0-rc.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc43715037532dc2d061e5c97e81b684c28993d52a4fa4eb7d2ce2826d78f2f2"
|
checksum = "541598dba361b5ba0321caad955ba99ae82a604f4047c4f2743724996abf62f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"crypto-bigint",
|
"crypto-bigint",
|
||||||
"digest",
|
"digest",
|
||||||
"ff",
|
"ff",
|
||||||
"group",
|
"group",
|
||||||
"hkdf",
|
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
"pem-rfc7468",
|
"pem-rfc7468",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
@@ -376,9 +422,9 @@ checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ff"
|
name = "ff"
|
||||||
version = "0.13.1"
|
version = "0.14.0-pre.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
checksum = "d42dd26f5790eda47c1a2158ea4120e32c35ddc9a7743c98a292accc01b54ef3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"subtle",
|
"subtle",
|
||||||
@@ -390,6 +436,17 @@ version = "0.4.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"
|
checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"libz-rs-sys",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foldhash"
|
name = "foldhash"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -398,49 +455,41 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
"r-efi",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "group"
|
name = "group"
|
||||||
version = "0.13.0"
|
version = "0.14.0-pre.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
checksum = "1ff6a0b2dd4b981b1ae9e3e6830ab146771f3660d31d57bafd9018805a91b0f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ff",
|
"ff",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hkdf"
|
|
||||||
version = "0.13.0-pre.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00176ff81091018d42ff82e8324f8e5adb0b7e0468d1358f653972562dbff031"
|
|
||||||
dependencies = [
|
|
||||||
"hmac",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hmac"
|
name = "hmac"
|
||||||
version = "0.13.0-pre.4"
|
version = "0.13.0-rc.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4b1fb14e4df79f9406b434b60acef9f45c26c50062cccf1346c6103b8c47d58"
|
checksum = "8dc6a2fcc35ab09136c6df2cdf9ca49790701420a3a6b5db0987dddbabc79b21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hybrid-array"
|
name = "hybrid-array"
|
||||||
version = "0.2.3"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9"
|
checksum = "891d15931895091dea5c47afa5b3c9a01ba634b311919fd4d41388fa0e3d76af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
@@ -451,21 +500,24 @@ name = "libbz2-rs-sys"
|
|||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0864a00c8d019e36216b69c2c4ce50b83b7bd966add3cf5ba554ec44f8bebcf5"
|
checksum = "0864a00c8d019e36216b69c2c4ce50b83b7bd966add3cf5ba554ec44f8bebcf5"
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.171"
|
version = "0.2.172"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libz-rs-sys"
|
name = "libz-rs-sys"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
|
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zlib-rs",
|
"zlib-rs",
|
||||||
]
|
]
|
||||||
@@ -476,6 +528,29 @@ version = "0.4.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lz4"
|
||||||
|
version = "1.28.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4"
|
||||||
|
dependencies = [
|
||||||
|
"lz4-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lz4-sys"
|
||||||
|
version = "1.11.1+lz4-1.10.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lzma-sys"
|
||||||
|
version = "0.1.20"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "magisk"
|
name = "magisk"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@@ -499,16 +574,16 @@ version = "0.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
"base",
|
"base",
|
||||||
"block-buffer",
|
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"bzip2",
|
||||||
"cxx",
|
"cxx",
|
||||||
"cxx-gen",
|
"cxx-gen",
|
||||||
"der",
|
"der",
|
||||||
"digest",
|
"digest",
|
||||||
"fdt",
|
"fdt",
|
||||||
"libbz2-rs-sys",
|
"flate2",
|
||||||
"libz-rs-sys",
|
"lz4",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"p256",
|
"p256",
|
||||||
"p384",
|
"p384",
|
||||||
@@ -516,11 +591,12 @@ dependencies = [
|
|||||||
"pb-rs",
|
"pb-rs",
|
||||||
"quick-protobuf",
|
"quick-protobuf",
|
||||||
"rsa",
|
"rsa",
|
||||||
"sec1",
|
|
||||||
"sha1",
|
"sha1",
|
||||||
"sha2",
|
"sha2",
|
||||||
"size",
|
"size",
|
||||||
"x509-cert",
|
"x509-cert",
|
||||||
|
"xz2",
|
||||||
|
"zopfli",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -555,6 +631,15 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
@@ -587,33 +672,35 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "p256"
|
name = "p256"
|
||||||
version = "0.14.0-pre.2"
|
version = "0.14.0-pre.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71f3fd64a9cad9c26ed7f734b152196d5e56376b9957c832bcca0de48a708080"
|
checksum = "b42c06f1f28ff328cb76c95cb7aebd6734a8333b98bdac393bdc124d16561dcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ecdsa",
|
"ecdsa",
|
||||||
"elliptic-curve",
|
"elliptic-curve",
|
||||||
|
"primefield",
|
||||||
"primeorder",
|
"primeorder",
|
||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "p384"
|
name = "p384"
|
||||||
version = "0.14.0-pre.2"
|
version = "0.14.0-pre.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e19554fe6ee269c860a0f231cbba714e5cbef26a927c75d8e30ac9040a4b32e"
|
checksum = "0c7594e57ef1ce505538e5a8e3485a21b930e99701bb65c8ede899a3a8213174"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ecdsa",
|
"ecdsa",
|
||||||
"elliptic-curve",
|
"elliptic-curve",
|
||||||
|
"primefield",
|
||||||
"primeorder",
|
"primeorder",
|
||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "p521"
|
name = "p521"
|
||||||
version = "0.14.0-pre.2"
|
version = "0.14.0-pre.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "957df9b5e6a7542f6430ec5187a4cb66d8498946c38b23fd14562bce6e32e6de"
|
checksum = "9396e2414ace7de7e0f3d544a5a07f129e39b28b2f08a35b3b7febdea36fd8e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"ecdsa",
|
"ecdsa",
|
||||||
@@ -635,18 +722,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pem-rfc7468"
|
name = "pem-rfc7468"
|
||||||
version = "1.0.0-rc.2"
|
version = "1.0.0-rc.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2dfbfa5c6f0906884269722c5478e72fd4d6c0e24fe600332c6d62359567ce1"
|
checksum = "a8e58fab693c712c0d4e88f8eb3087b6521d060bcaf76aeb20cb192d809115ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64ct",
|
"base64ct",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkcs1"
|
name = "pkcs1"
|
||||||
version = "0.8.0-rc.1"
|
version = "0.8.0-rc.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "226eb25e2c46c166ce498ac0f606ac623142d640064879ff445938accddff1e2"
|
checksum = "24e16d93c725fa250577ffdec06ebbff4cae3625b0e2881ac43a5427797ee8d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"der",
|
"der",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
@@ -655,34 +742,47 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkcs8"
|
name = "pkcs8"
|
||||||
version = "0.11.0-rc.2"
|
version = "0.11.0-rc.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f22636de7c995e997ed3d8d2949b7414d4faba3efa7312a6c0e75d875a14bdd4"
|
checksum = "3f1843d4345dfe1a55e487db747a04c01af50415b03e937410e0a41d8cc24ec7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"der",
|
"der",
|
||||||
"spki",
|
"spki",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "primefield"
|
name = "pkg-config"
|
||||||
version = "0.14.0-pre.0"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3f2ce0fa9cccdaf216230d151ce51a15298aef50ad76081a830128ecbc6428a"
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primefield"
|
||||||
|
version = "0.14.0-pre.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bbeb92947a0d0d4b0cab5e2e6749acc44c81461eb3b1aff4dbb7acd0eb9f0ab"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-bigint",
|
||||||
|
"ff",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "primeorder"
|
name = "primeorder"
|
||||||
version = "0.14.0-pre.2"
|
version = "0.14.0-pre.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b794117b388378d55629f78f61e64e182baa200bf59c1a8205e0c46508ce5873"
|
checksum = "979936340c6e8b108ad132b395a1682f02a0b179080ed3380320c2c888728429"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"elliptic-curve",
|
"elliptic-curve",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.94"
|
version = "1.0.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -705,19 +805,25 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "r-efi"
|
||||||
version = "0.6.4"
|
version = "5.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rfc6979"
|
name = "rfc6979"
|
||||||
version = "0.5.0-pre.4"
|
version = "0.5.0-rc.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "871ee76a3eee98b0f805e5d1caf26929f4565073c580c053a55f886fc15dea49"
|
checksum = "f53f124bf3ec90be84ae97d7f52175ba938898525554c13c9017eb8f0a604146"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hmac",
|
"hmac",
|
||||||
"subtle",
|
"subtle",
|
||||||
@@ -725,9 +831,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.10.0-pre.4"
|
version = "0.10.0-rc.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e82e90f434676d49758cab5b3ff2cc1fd8f12bf7d79b70c6088bc5a4e7c63270"
|
checksum = "f30f0ad781aea19fe741d7a901b2ad8b4271ac3516e7045b8ecff74e201968fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"crypto-bigint",
|
"crypto-bigint",
|
||||||
@@ -751,15 +857,15 @@ checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.20"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sec1"
|
name = "sec1"
|
||||||
version = "0.8.0-rc.3"
|
version = "0.8.0-rc.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d1988446eff153796413a73669dfaa4caa3f5ce8b25fac89e3821a39c611772e"
|
checksum = "e4855dd9b15e8e469fad23529698f7f7b7a6b250a81c88b1f9d7efe1abca7717"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"der",
|
"der",
|
||||||
@@ -801,9 +907,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.11.0-pre.4"
|
version = "0.11.0-rc.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9540978cef7a8498211c1b1c14e5ce920fe5bd524ea84f4a3d72d4602515ae93"
|
checksum = "6f9318facddf9ac32a33527066936837e189b3f23ced6edc1603720ead5e2b3d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
@@ -812,9 +918,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.11.0-pre.4"
|
version = "0.11.0-rc.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "540c0893cce56cdbcfebcec191ec8e0f470dd1889b6e7a0b503e310a94a168f5"
|
checksum = "aa1d2e6b3cc4e43a8258a9a3b17aa5dfd2cc5186c7024bba8a64aa65b2c71a59"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
@@ -829,14 +935,20 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signature"
|
name = "signature"
|
||||||
version = "2.3.0-pre.4"
|
version = "3.0.0-rc.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "054d71959c7051b9042c26af337f05cc930575ed2604d7d3ced3158383e59734"
|
checksum = "b8852cecbd17ba45978bbbe43061ebe36a2ae376058c5c172e09f72888f8f7de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "size"
|
name = "size"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -845,9 +957,9 @@ checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spki"
|
name = "spki"
|
||||||
version = "0.8.0-rc.1"
|
version = "0.8.0-rc.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37ac66481418fd7afdc584adcf3be9aa572cf6c2858814494dc2a01755f050bc"
|
checksum = "c2f0e2bdca9b00f5be6dd3bb6647d50fd0f24a508a95f78e3bb2fe98d0403c85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64ct",
|
"base64ct",
|
||||||
"der",
|
"der",
|
||||||
@@ -867,9 +979,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -952,9 +1064,12 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.14.2+wasi-0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
@@ -1039,10 +1154,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x509-cert"
|
name = "wit-bindgen-rt"
|
||||||
version = "0.3.0-pre.0"
|
version = "0.39.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2db382aa43c1fb5c419a960f72c3847ab0f383f635fc2e25f0bd6c5fb94371d1"
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x509-cert"
|
||||||
|
version = "0.3.0-rc.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5c645061d1dc562a65edda59c7f688f35403a4615adfc07460437442d6e8383"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"der",
|
"der",
|
||||||
@@ -1050,6 +1174,15 @@ dependencies = [
|
|||||||
"tls_codec",
|
"tls_codec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xz2"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
|
||||||
|
dependencies = [
|
||||||
|
"lzma-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -1072,6 +1205,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zlib-rs"
|
name = "zlib-rs"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
|
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zopfli"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"crc32fast",
|
||||||
|
"log",
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|||||||
@@ -10,44 +10,45 @@ edition = "2024"
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
cxx = { path = "external/cxx-rs" }
|
cxx = { path = "external/cxx-rs" }
|
||||||
cxx-gen = { path = "external/cxx-rs/gen/lib" }
|
cxx-gen = { path = "external/cxx-rs/gen/lib" }
|
||||||
libc = "0.2.171"
|
libc = "0.2.172"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.1"
|
||||||
num-traits = "0.2.19"
|
num-traits = "0.2.19"
|
||||||
num-derive = "0.4.2"
|
num-derive = "0.4.2"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
size = "0.5.0"
|
size = "0.5.0"
|
||||||
bytemuck = "1.22.0"
|
bytemuck = "1.23.1"
|
||||||
fdt = "0.1.5"
|
fdt = "0.1.5"
|
||||||
const_format = "0.2.34"
|
const_format = "0.2.34"
|
||||||
bit-set = "0.8.0"
|
bit-set = "0.8.0"
|
||||||
syn = "2.0.100"
|
syn = "2.0.102"
|
||||||
quote = "1.0.40"
|
quote = "1.0.40"
|
||||||
proc-macro2 = "1.0.94"
|
proc-macro2 = "1.0.95"
|
||||||
argh = { version = "0.1.13", default-features = false }
|
argh = { version = "0.1.13", default-features = false }
|
||||||
libz-rs-sys = { version = "0.5.0", features = ["export-symbols"] }
|
|
||||||
libbz2-rs-sys = { version = "0.1.3" }
|
|
||||||
pb-rs = { version = "0.10.0", default-features = false }
|
pb-rs = { version = "0.10.0", default-features = false }
|
||||||
quick-protobuf = "0.8.1"
|
quick-protobuf = "0.8.1"
|
||||||
|
flate2 = { version = "1.1.2", default-features = false }
|
||||||
|
bzip2 = { version = "0.5.2", default-features = false }
|
||||||
|
zopfli = "0.8.2"
|
||||||
|
lz4 = "1.28.1"
|
||||||
|
xz2 = "0.1.7"
|
||||||
|
|
||||||
# Rust crypto crates are tied together
|
# Rust crypto crates are tied together
|
||||||
sha1 = "=0.11.0-pre.4"
|
sha1 = "0.11.0-rc.0"
|
||||||
sha2 = "=0.11.0-pre.4"
|
sha2 = "0.11.0-rc.0"
|
||||||
digest = "=0.11.0-pre.9"
|
digest = "0.11.0-rc.0"
|
||||||
p256 = "0.14.0-pre.2"
|
p256 = "0.14.0-pre.5"
|
||||||
p384 = "0.14.0-pre.2"
|
p384 = "0.14.0-pre.5"
|
||||||
p521 = "0.14.0-pre.2"
|
p521 = "0.14.0-pre.5"
|
||||||
rsa = "0.10.0-pre.4"
|
rsa = "0.10.0-rc.0"
|
||||||
x509-cert = "0.3.0-pre.0"
|
x509-cert = "0.3.0-rc.0"
|
||||||
der = "0.8.0-rc.1"
|
der = "0.8.0-rc.4"
|
||||||
|
|
||||||
# Pin version to prevent cargo update breaking builds
|
|
||||||
block-buffer = "=0.11.0-rc.3"
|
|
||||||
sec1 = "=0.8.0-rc.3"
|
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
pb-rs = { git = "https://github.com/tafia/quick-protobuf.git" }
|
pb-rs = { git = "https://github.com/tafia/quick-protobuf.git" }
|
||||||
quick-protobuf = { git = "https://github.com/tafia/quick-protobuf.git" }
|
quick-protobuf = { git = "https://github.com/tafia/quick-protobuf.git" }
|
||||||
|
lz4-sys = { path = "external/lz4-sys" }
|
||||||
|
lzma-sys = { path = "external/lzma-sys" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ LOCAL_SRC_FILES := \
|
|||||||
files.cpp \
|
files.cpp \
|
||||||
misc.cpp \
|
misc.cpp \
|
||||||
logging.cpp \
|
logging.cpp \
|
||||||
stream.cpp \
|
|
||||||
base-rs.cpp \
|
base-rs.cpp \
|
||||||
../external/cxx-rs/src/cxx.cc
|
../external/cxx-rs/src/cxx.cc
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pub mod buf {
|
|||||||
|
|
||||||
// Trait definitions
|
// Trait definitions
|
||||||
|
|
||||||
pub trait Utf8CStrBuf: Write + AsRef<Utf8CStr> + Deref<Target = Utf8CStr> {
|
pub trait Utf8CStrBuf: Display + Write + AsRef<Utf8CStr> + Deref<Target = Utf8CStr> {
|
||||||
// The length of the string without the terminating null character.
|
// The length of the string without the terminating null character.
|
||||||
// assert_true(len <= capacity - 1)
|
// assert_true(len <= capacity - 1)
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
#include <base.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -182,6 +182,10 @@ impl FileAttr {
|
|||||||
pub fn is_socket(&self) -> bool {
|
pub fn is_socket(&self) -> bool {
|
||||||
self.is(libc::S_IFSOCK)
|
self.is(libc::S_IFSOCK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_whiteout(&self) -> bool {
|
||||||
|
self.is_char_device() && self.st.st_rdev == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const XATTR_NAME_SELINUX: &CStr = c"security.selinux";
|
const XATTR_NAME_SELINUX: &CStr = c"security.selinux";
|
||||||
@@ -321,12 +325,12 @@ impl Utf8CStr {
|
|||||||
|
|
||||||
pub fn set_attr<'a>(&'a self, attr: &'a FileAttr) -> OsResult<'a, ()> {
|
pub fn set_attr<'a>(&'a self, attr: &'a FileAttr) -> OsResult<'a, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if !attr.is_symlink() {
|
if !attr.is_symlink() && libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()) < 0
|
||||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).check_os_err(
|
{
|
||||||
"chmod",
|
let self_attr = self.get_attr()?;
|
||||||
Some(self),
|
if !self_attr.is_symlink() {
|
||||||
None,
|
return Err(OsError::last_os_error("chmod", Some(self), None));
|
||||||
)?;
|
}
|
||||||
}
|
}
|
||||||
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).check_os_err(
|
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).check_os_err(
|
||||||
"lchown",
|
"lchown",
|
||||||
@@ -579,7 +583,7 @@ impl<S: Utf8CStrBuf + Sized> FsPathBuilder for S {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self {
|
fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self {
|
||||||
self.write_fmt(format_args!("/{}", name)).ok();
|
self.write_fmt(format_args!("/{name}")).ok();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -591,7 +595,7 @@ impl FsPathBuilder for dyn Utf8CStrBuf + '_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self {
|
fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self {
|
||||||
self.write_fmt(format_args!("/{}", name)).ok();
|
self.write_fmt(format_args!("/{name}")).ok();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -842,7 +846,7 @@ fn parse_mount_info_line(line: &str) -> Option<MountInfo> {
|
|||||||
|
|
||||||
pub fn parse_mount_info(pid: &str) -> Vec<MountInfo> {
|
pub fn parse_mount_info(pid: &str) -> Vec<MountInfo> {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
let mut path = format!("/proc/{}/mountinfo", pid);
|
let mut path = format!("/proc/{pid}/mountinfo");
|
||||||
if let Ok(file) = Utf8CStr::from_string(&mut path).open(O_RDONLY | O_CLOEXEC) {
|
if let Ok(file) = Utf8CStr::from_string(&mut path).open(O_RDONLY | O_CLOEXEC) {
|
||||||
BufReader::new(file).foreach_lines(|line| {
|
BufReader::new(file).foreach_lines(|line| {
|
||||||
parse_mount_info_line(line)
|
parse_mount_info_line(line)
|
||||||
|
|||||||
@@ -1,129 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "../files.hpp"
|
|
||||||
|
|
||||||
#define ENABLE_IOV 0
|
|
||||||
|
|
||||||
struct out_stream {
|
|
||||||
virtual bool write(const void *buf, size_t len) = 0;
|
|
||||||
#if ENABLE_IOV
|
|
||||||
virtual ssize_t writev(const iovec *iov, int iovcnt);
|
|
||||||
#endif
|
|
||||||
virtual ~out_stream() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
using out_strm_ptr = std::unique_ptr<out_stream>;
|
|
||||||
|
|
||||||
// Delegates all operations to base stream
|
|
||||||
class filter_out_stream : public out_stream {
|
|
||||||
public:
|
|
||||||
filter_out_stream(out_strm_ptr &&base) : base(std::move(base)) {}
|
|
||||||
bool write(const void *buf, size_t len) override;
|
|
||||||
protected:
|
|
||||||
out_strm_ptr base;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Buffered output stream, writing in chunks
|
|
||||||
class chunk_out_stream : public filter_out_stream {
|
|
||||||
public:
|
|
||||||
chunk_out_stream(out_strm_ptr &&base, size_t buf_sz, size_t chunk_sz)
|
|
||||||
: filter_out_stream(std::move(base)), chunk_sz(chunk_sz), data(buf_sz) {}
|
|
||||||
|
|
||||||
chunk_out_stream(out_strm_ptr &&base, size_t buf_sz = 4096)
|
|
||||||
: chunk_out_stream(std::move(base), buf_sz, buf_sz) {}
|
|
||||||
|
|
||||||
bool write(const void *buf, size_t len) final;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Classes inheriting this class has to call finalize() in its destructor
|
|
||||||
void finalize();
|
|
||||||
virtual bool write_chunk(const void *buf, size_t len, bool final);
|
|
||||||
|
|
||||||
size_t chunk_sz;
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t buf_off = 0;
|
|
||||||
heap_data data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct in_stream {
|
|
||||||
virtual ssize_t read(void *buf, size_t len) = 0;
|
|
||||||
ssize_t readFully(void *buf, size_t len);
|
|
||||||
#if ENABLE_IOV
|
|
||||||
virtual ssize_t readv(const iovec *iov, int iovcnt);
|
|
||||||
#endif
|
|
||||||
virtual ~in_stream() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A stream is something that is writable and readable
|
|
||||||
struct stream : public out_stream, public in_stream {};
|
|
||||||
|
|
||||||
using stream_ptr = std::unique_ptr<stream>;
|
|
||||||
|
|
||||||
// Byte stream that dynamically allocates memory
|
|
||||||
class byte_stream : public stream {
|
|
||||||
public:
|
|
||||||
byte_stream(heap_data &data) : _data(data) {}
|
|
||||||
|
|
||||||
ssize_t read(void *buf, size_t len) override;
|
|
||||||
bool write(const void *buf, size_t len) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
heap_data &_data;
|
|
||||||
size_t _pos = 0;
|
|
||||||
size_t _cap = 0;
|
|
||||||
|
|
||||||
void resize(size_t new_sz, bool zero = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
class rust_vec_stream : public stream {
|
|
||||||
public:
|
|
||||||
rust_vec_stream(rust::Vec<uint8_t> &data) : _data(data) {}
|
|
||||||
|
|
||||||
ssize_t read(void *buf, size_t len) override;
|
|
||||||
bool write(const void *buf, size_t len) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
rust::Vec<uint8_t> &_data;
|
|
||||||
size_t _pos = 0;
|
|
||||||
|
|
||||||
void ensure_size(size_t sz, bool zero = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
class file_stream : public stream {
|
|
||||||
public:
|
|
||||||
bool write(const void *buf, size_t len) final;
|
|
||||||
protected:
|
|
||||||
virtual ssize_t do_write(const void *buf, size_t len) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// File stream but does not close the file descriptor at any time
|
|
||||||
class fd_stream : public file_stream {
|
|
||||||
public:
|
|
||||||
fd_stream(int fd) : fd(fd) {}
|
|
||||||
ssize_t read(void *buf, size_t len) override;
|
|
||||||
#if ENABLE_IOV
|
|
||||||
ssize_t readv(const iovec *iov, int iovcnt) override;
|
|
||||||
ssize_t writev(const iovec *iov, int iovcnt) override;
|
|
||||||
#endif
|
|
||||||
protected:
|
|
||||||
ssize_t do_write(const void *buf, size_t len) override;
|
|
||||||
private:
|
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ****************************************
|
|
||||||
* Bridge between stream class and C stdio
|
|
||||||
* ****************************************/
|
|
||||||
|
|
||||||
// stream_ptr -> sFILE
|
|
||||||
sFILE make_stream_fp(stream_ptr &&strm);
|
|
||||||
|
|
||||||
template <class T, class... Args>
|
|
||||||
sFILE make_stream_fp(Args &&... args) {
|
|
||||||
return make_stream_fp(stream_ptr(new T(std::forward<Args>(args)...)));
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
#![allow(clippy::missing_safety_doc)]
|
#![allow(clippy::missing_safety_doc)]
|
||||||
#![feature(format_args_nl)]
|
|
||||||
#![feature(io_error_more)]
|
|
||||||
|
|
||||||
pub use const_format;
|
pub use const_format;
|
||||||
pub use libc;
|
pub use libc;
|
||||||
@@ -58,7 +56,6 @@ pub mod ffi {
|
|||||||
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
||||||
fn exit_on_error(b: bool);
|
fn exit_on_error(b: bool);
|
||||||
fn cmdline_logging();
|
fn cmdline_logging();
|
||||||
fn resize_vec(vec: &mut Vec<u8>, size: usize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[namespace = "rust"]
|
#[namespace = "rust"]
|
||||||
@@ -80,12 +77,3 @@ fn set_log_level_state_cxx(level: ffi::LogLevelCxx, enabled: bool) {
|
|||||||
set_log_level_state(level, enabled)
|
set_log_level_state(level, enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_vec(vec: &mut Vec<u8>, size: usize) {
|
|
||||||
if size > vec.len() {
|
|
||||||
vec.reserve(size - vec.len());
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
vec.set_len(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Arguments;
|
|
||||||
use std::io::{Write, stderr, stdout};
|
use std::io::{Write, stderr, stdout};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
@@ -102,10 +101,6 @@ pub fn log_with_formatter<F: FnOnce(Formatter) -> fmt::Result>(level: LogLevel,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_with_args(level: LogLevel, args: Arguments) {
|
|
||||||
log_with_formatter(level, |w| w.write_fmt(args));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cmdline_logging() {
|
pub fn cmdline_logging() {
|
||||||
fn cmdline_write(level: LogLevel, msg: &Utf8CStr) {
|
fn cmdline_write(level: LogLevel, msg: &Utf8CStr) {
|
||||||
if matches!(level, LogLevel::Info) {
|
if matches!(level, LogLevel::Info) {
|
||||||
@@ -124,24 +119,31 @@ pub fn cmdline_logging() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log_with_args {
|
||||||
|
($level:expr, $($args:tt)+) => {
|
||||||
|
$crate::log_with_formatter($level, |w| writeln!(w, $($args)+))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! error {
|
macro_rules! error {
|
||||||
($($args:tt)+) => {
|
($($args:tt)+) => {
|
||||||
$crate::log_with_args($crate::LogLevel::Error, format_args_nl!($($args)+))
|
$crate::log_with_formatter($crate::LogLevel::Error, |w| writeln!(w, $($args)+))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! warn {
|
macro_rules! warn {
|
||||||
($($args:tt)+) => {
|
($($args:tt)+) => {
|
||||||
$crate::log_with_args($crate::LogLevel::Warn, format_args_nl!($($args)+))
|
$crate::log_with_formatter($crate::LogLevel::Warn, |w| writeln!(w, $($args)+))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! info {
|
macro_rules! info {
|
||||||
($($args:tt)+) => {
|
($($args:tt)+) => {
|
||||||
$crate::log_with_args($crate::LogLevel::Info, format_args_nl!($($args)+))
|
$crate::log_with_formatter($crate::LogLevel::Info, |w| writeln!(w, $($args)+))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +151,7 @@ macro_rules! info {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! debug {
|
macro_rules! debug {
|
||||||
($($args:tt)+) => {
|
($($args:tt)+) => {
|
||||||
$crate::log_with_args($crate::LogLevel::Debug, format_args_nl!($($args)+))
|
$crate::log_with_formatter($crate::LogLevel::Debug, |w| writeln!(w, $($args)+))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -186,6 +184,10 @@ int parse_int(string_view s) {
|
|||||||
return parse_num<int, 10>(s);
|
return parse_num<int, 10>(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t parse_uint32_hex(string_view s) {
|
||||||
|
return parse_num<uint32_t, 16>(s);
|
||||||
|
}
|
||||||
|
|
||||||
int switch_mnt_ns(int pid) {
|
int switch_mnt_ns(int pid) {
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int fd = syscall(__NR_pidfd_open, pid, 0);
|
int fd = syscall(__NR_pidfd_open, pid, 0);
|
||||||
|
|||||||
@@ -147,17 +147,12 @@ struct byte_data : public byte_view {
|
|||||||
rust::Vec<size_t> patch(byte_view from, byte_view to);
|
rust::Vec<size_t> patch(byte_view from, byte_view to);
|
||||||
};
|
};
|
||||||
|
|
||||||
class byte_stream;
|
|
||||||
|
|
||||||
struct heap_data : public byte_data {
|
struct heap_data : public byte_data {
|
||||||
ALLOW_MOVE_ONLY(heap_data)
|
ALLOW_MOVE_ONLY(heap_data)
|
||||||
|
|
||||||
heap_data() = default;
|
heap_data() = default;
|
||||||
explicit heap_data(size_t sz) : byte_data(calloc(sz, 1), sz) {}
|
explicit heap_data(size_t sz) : byte_data(calloc(sz, 1), sz) {}
|
||||||
~heap_data() { free(_buf); }
|
~heap_data() { free(_buf); }
|
||||||
|
|
||||||
// byte_stream needs to reallocate the internal buffer
|
|
||||||
friend byte_stream;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct owned_fd {
|
struct owned_fd {
|
||||||
@@ -180,6 +175,7 @@ rust::Vec<size_t> mut_u8_patch(
|
|||||||
rust::Slice<const uint8_t> from,
|
rust::Slice<const uint8_t> from,
|
||||||
rust::Slice<const uint8_t> to);
|
rust::Slice<const uint8_t> to);
|
||||||
|
|
||||||
|
uint32_t parse_uint32_hex(std::string_view s);
|
||||||
int parse_int(std::string_view s);
|
int parse_int(std::string_view s);
|
||||||
|
|
||||||
using thread_entry = void *(*)(void *);
|
using thread_entry = void *(*)(void *);
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ impl<T> EarlyExitExt<T> for Result<T, EarlyExit> {
|
|||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
eprintln!("{}", output);
|
eprintln!("{output}");
|
||||||
print_help_msg();
|
print_help_msg();
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
@@ -169,3 +169,61 @@ impl<T: Default> Default for AtomicArc<T> {
|
|||||||
Self::new(Default::default())
|
Self::new(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Chunker {
|
||||||
|
chunk: Box<[u8]>,
|
||||||
|
chunk_size: usize,
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Chunker {
|
||||||
|
pub fn new(chunk_size: usize) -> Self {
|
||||||
|
Chunker {
|
||||||
|
// SAFETY: all bytes will be initialized before it is used, tracked by self.pos
|
||||||
|
chunk: unsafe { Box::new_uninit_slice(chunk_size).assume_init() },
|
||||||
|
chunk_size,
|
||||||
|
pos: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_chunk_size(&mut self, chunk_size: usize) {
|
||||||
|
self.chunk_size = chunk_size;
|
||||||
|
self.pos = 0;
|
||||||
|
if self.chunk.len() < chunk_size {
|
||||||
|
self.chunk = unsafe { Box::new_uninit_slice(chunk_size).assume_init() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns (remaining buf, Option<Chunk>)
|
||||||
|
pub fn add_data<'a, 'b: 'a>(&'a mut self, mut buf: &'b [u8]) -> (&'b [u8], Option<&'a [u8]>) {
|
||||||
|
let mut chunk = None;
|
||||||
|
if self.pos > 0 {
|
||||||
|
// Try to fill the chunk
|
||||||
|
let len = std::cmp::min(self.chunk_size - self.pos, buf.len());
|
||||||
|
self.chunk[self.pos..self.pos + len].copy_from_slice(&buf[..len]);
|
||||||
|
self.pos += len;
|
||||||
|
// If the chunk is filled, consume it
|
||||||
|
if self.pos == self.chunk_size {
|
||||||
|
chunk = Some(&self.chunk[..self.chunk_size]);
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
buf = &buf[len..];
|
||||||
|
} else if buf.len() >= self.chunk_size {
|
||||||
|
// Directly consume a chunk from buf
|
||||||
|
chunk = Some(&buf[..self.chunk_size]);
|
||||||
|
buf = &buf[self.chunk_size..];
|
||||||
|
} else {
|
||||||
|
// Copy buf into chunk
|
||||||
|
self.chunk[self.pos..self.pos + buf.len()].copy_from_slice(buf);
|
||||||
|
self.pos += buf.len();
|
||||||
|
return (&[], None);
|
||||||
|
}
|
||||||
|
(buf, chunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_available(&mut self) -> &[u8] {
|
||||||
|
let chunk = &self.chunk[..self.pos];
|
||||||
|
self.pos = 0;
|
||||||
|
chunk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ use libc::c_ulong;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
impl Utf8CStr {
|
impl Utf8CStr {
|
||||||
pub fn bind_mount_to<'a>(&'a self, path: &'a Utf8CStr) -> OsResult<'a, ()> {
|
pub fn bind_mount_to<'a>(&'a self, path: &'a Utf8CStr, rec: bool) -> OsResult<'a, ()> {
|
||||||
|
let flag = if rec { libc::MS_REC } else { 0 };
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::mount(
|
libc::mount(
|
||||||
self.as_ptr(),
|
self.as_ptr(),
|
||||||
path.as_ptr(),
|
path.as_ptr(),
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
libc::MS_BIND,
|
libc::MS_BIND | flag,
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
)
|
)
|
||||||
.check_os_err("bind_mount", Some(self), Some(path))
|
.check_os_err("bind_mount", Some(self), Some(path))
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pub type LoggedResult<T> = Result<T, LoggedError>;
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! log_err {
|
macro_rules! log_err {
|
||||||
($($args:tt)+) => {{
|
($($args:tt)+) => {{
|
||||||
$crate::log_with_args($crate::LogLevel::Error, format_args_nl!($($args)+));
|
$crate::error!($($args)+);
|
||||||
$crate::LoggedError::default()
|
$crate::LoggedError::default()
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@@ -148,12 +148,9 @@ impl<T, E: Display> Loggable<T> for Result<T, E> {
|
|||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let Some(caller) = caller {
|
if let Some(caller) = caller {
|
||||||
log_with_args(
|
log_with_args!(level, "[{}:{}] {:#}", caller.file(), caller.line(), e);
|
||||||
level,
|
|
||||||
format_args_nl!("[{}:{}] {:#}", caller.file(), caller.line(), e),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
log_with_args(level, format_args_nl!("{:#}", e));
|
log_with_args!(level, "{:#}", e);
|
||||||
}
|
}
|
||||||
Err(LoggedError::default())
|
Err(LoggedError::default())
|
||||||
}
|
}
|
||||||
@@ -174,7 +171,7 @@ impl<T, E: Display> Loggable<T> for Result<T, E> {
|
|||||||
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
|
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
|
||||||
}
|
}
|
||||||
f(w)?;
|
f(w)?;
|
||||||
writeln!(w, ": {:#}", e)
|
writeln!(w, ": {e:#}")
|
||||||
});
|
});
|
||||||
Err(LoggedError::default())
|
Err(LoggedError::default())
|
||||||
}
|
}
|
||||||
@@ -186,7 +183,7 @@ impl<T, E: Display> Loggable<T> for Result<T, E> {
|
|||||||
impl<T: Display> From<T> for LoggedError {
|
impl<T: Display> From<T> for LoggedError {
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
fn from(e: T) -> Self {
|
fn from(e: T) -> Self {
|
||||||
log_with_args(LogLevel::Error, format_args_nl!("{:#}", e));
|
log_with_args!(LogLevel::Error, "{:#}", e);
|
||||||
LoggedError::default()
|
LoggedError::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,9 +191,12 @@ impl<T: Display> From<T> for LoggedError {
|
|||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn from(e: T) -> Self {
|
fn from(e: T) -> Self {
|
||||||
let caller = Location::caller();
|
let caller = Location::caller();
|
||||||
log_with_args(
|
log_with_args!(
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format_args_nl!("[{}:{}] {:#}", caller.file(), caller.line(), e),
|
"[{}:{}] {:#}",
|
||||||
|
caller.file(),
|
||||||
|
caller.line(),
|
||||||
|
e
|
||||||
);
|
);
|
||||||
LoggedError::default()
|
LoggedError::default()
|
||||||
}
|
}
|
||||||
@@ -366,7 +366,7 @@ impl Display for OsError<'_> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let error = self.as_io_error();
|
let error = self.as_io_error();
|
||||||
if self.name.is_empty() {
|
if self.name.is_empty() {
|
||||||
write!(f, "{:#}", error)
|
write!(f, "{error:#}")
|
||||||
} else {
|
} else {
|
||||||
match (self.arg1.ok(), self.arg2.ok()) {
|
match (self.arg1.ok(), self.arg2.ok()) {
|
||||||
(Some(arg1), Some(arg2)) => {
|
(Some(arg1), Some(arg2)) => {
|
||||||
|
|||||||
@@ -1,201 +0,0 @@
|
|||||||
#include <unistd.h>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
#include <stream.hpp>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static int strm_read(void *v, char *buf, int len) {
|
|
||||||
auto strm = static_cast<stream *>(v);
|
|
||||||
return strm->read(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int strm_write(void *v, const char *buf, int len) {
|
|
||||||
auto strm = static_cast<stream *>(v);
|
|
||||||
if (!strm->write(buf, len))
|
|
||||||
return -1;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int strm_close(void *v) {
|
|
||||||
auto strm = static_cast<stream *>(v);
|
|
||||||
delete strm;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sFILE make_stream_fp(stream_ptr &&strm) {
|
|
||||||
auto fp = make_file(funopen(strm.release(), strm_read, strm_write, nullptr, strm_close));
|
|
||||||
setbuf(fp.get(), nullptr);
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t in_stream::readFully(void *buf, size_t len) {
|
|
||||||
size_t read_sz = 0;
|
|
||||||
ssize_t ret;
|
|
||||||
do {
|
|
||||||
ret = read((byte *) buf + read_sz, len - read_sz);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
read_sz += ret;
|
|
||||||
} while (read_sz != len && ret != 0);
|
|
||||||
return read_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool filter_out_stream::write(const void *buf, size_t len) {
|
|
||||||
return base->write(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool chunk_out_stream::write(const void *_in, size_t len) {
|
|
||||||
auto in = static_cast<const uint8_t *>(_in);
|
|
||||||
while (len) {
|
|
||||||
if (buf_off + len >= chunk_sz) {
|
|
||||||
// Enough input for a chunk
|
|
||||||
const uint8_t *src;
|
|
||||||
if (buf_off) {
|
|
||||||
src = data.buf();
|
|
||||||
auto copy = chunk_sz - buf_off;
|
|
||||||
memcpy(data.buf() + buf_off, in, copy);
|
|
||||||
in += copy;
|
|
||||||
len -= copy;
|
|
||||||
buf_off = 0;
|
|
||||||
} else {
|
|
||||||
src = in;
|
|
||||||
in += chunk_sz;
|
|
||||||
len -= chunk_sz;
|
|
||||||
}
|
|
||||||
if (!write_chunk(src, chunk_sz, false))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// Buffer internally
|
|
||||||
memcpy(data.buf() + buf_off, in, len);
|
|
||||||
buf_off += len;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool chunk_out_stream::write_chunk(const void *buf, size_t len, bool) {
|
|
||||||
return base->write(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void chunk_out_stream::finalize() {
|
|
||||||
if (buf_off) {
|
|
||||||
if (!write_chunk(data.buf(), buf_off, true)) {
|
|
||||||
LOGE("Error in finalize, file truncated\n");
|
|
||||||
}
|
|
||||||
buf_off = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t byte_stream::read(void *buf, size_t len) {
|
|
||||||
len = std::min((size_t) len, _data._sz- _pos);
|
|
||||||
memcpy(buf, _data.buf() + _pos, len);
|
|
||||||
_pos += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool byte_stream::write(const void *buf, size_t len) {
|
|
||||||
resize(_pos + len);
|
|
||||||
memcpy(_data.buf() + _pos, buf, len);
|
|
||||||
_pos += len;
|
|
||||||
_data._sz= std::max(_data.sz(), _pos);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void byte_stream::resize(size_t new_sz, bool zero) {
|
|
||||||
bool resize = false;
|
|
||||||
size_t old_cap = _cap;
|
|
||||||
while (new_sz > _cap) {
|
|
||||||
_cap = _cap ? (_cap << 1) - (_cap >> 1) : 1 << 12;
|
|
||||||
resize = true;
|
|
||||||
}
|
|
||||||
if (resize) {
|
|
||||||
_data._buf = static_cast<uint8_t *>(::realloc(_data._buf, _cap));
|
|
||||||
if (zero)
|
|
||||||
memset(_data.buf() + old_cap, 0, _cap - old_cap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t rust_vec_stream::read(void *buf, size_t len) {
|
|
||||||
len = std::min<size_t>(len, _data.size() - _pos);
|
|
||||||
memcpy(buf, _data.data() + _pos, len);
|
|
||||||
_pos += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rust_vec_stream::write(const void *buf, size_t len) {
|
|
||||||
ensure_size(_pos + len);
|
|
||||||
memcpy(_data.data() + _pos, buf, len);
|
|
||||||
_pos += len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rust_vec_stream::ensure_size(size_t sz, bool zero) {
|
|
||||||
size_t old_sz = _data.size();
|
|
||||||
if (sz > old_sz) {
|
|
||||||
resize_vec(_data, sz);
|
|
||||||
if (zero)
|
|
||||||
memset(_data.data() + old_sz, 0, sz - old_sz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t fd_stream::read(void *buf, size_t len) {
|
|
||||||
return ::read(fd, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t fd_stream::do_write(const void *buf, size_t len) {
|
|
||||||
return ::write(fd, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_stream::write(const void *buf, size_t len) {
|
|
||||||
size_t write_sz = 0;
|
|
||||||
ssize_t ret;
|
|
||||||
do {
|
|
||||||
ret = do_write((byte *) buf + write_sz, len - write_sz);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
write_sz += ret;
|
|
||||||
} while (write_sz != len && ret != 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLE_IOV
|
|
||||||
|
|
||||||
ssize_t in_stream::readv(const iovec *iov, int iovcnt) {
|
|
||||||
size_t read_sz = 0;
|
|
||||||
for (int i = 0; i < iovcnt; ++i) {
|
|
||||||
auto ret = readFully(iov[i].iov_base, iov[i].iov_len);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
read_sz += ret;
|
|
||||||
}
|
|
||||||
return read_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t out_stream::writev(const iovec *iov, int iovcnt) {
|
|
||||||
size_t write_sz = 0;
|
|
||||||
for (int i = 0; i < iovcnt; ++i) {
|
|
||||||
if (!write(iov[i].iov_base, iov[i].iov_len))
|
|
||||||
return write_sz;
|
|
||||||
write_sz += iov[i].iov_len;
|
|
||||||
}
|
|
||||||
return write_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t fd_stream::readv(const iovec *iov, int iovcnt) {
|
|
||||||
return ::readv(fd, iov, iovcnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t fd_stream::writev(const iovec *iov, int iovcnt) {
|
|
||||||
return ::writev(fd, iov, iovcnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ENABLE_IOV
|
|
||||||
@@ -30,9 +30,8 @@ der = { workspace = true, features = ["derive", "pem"] }
|
|||||||
fdt = { workspace = true }
|
fdt = { workspace = true }
|
||||||
bytemuck = { workspace = true, features = ["derive", "min_const_generics"] }
|
bytemuck = { workspace = true, features = ["derive", "min_const_generics"] }
|
||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
libz-rs-sys = { workspace = true }
|
flate2 = { workspace = true, features = ["zlib-rs"] }
|
||||||
libbz2-rs-sys = { workspace = true }
|
bzip2 = { workspace = true, features = ["libbz2-rs-sys"] }
|
||||||
|
lz4 = { workspace = true }
|
||||||
# Pin version to prevent cargo update break builds
|
xz2 = { workspace = true }
|
||||||
block-buffer = { workspace = true }
|
zopfli = { workspace = true, features = ["gzip"] }
|
||||||
sec1 = { workspace = true }
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "boot-rs.hpp"
|
#include "boot-rs.hpp"
|
||||||
#include "bootimg.hpp"
|
#include "bootimg.hpp"
|
||||||
#include "magiskboot.hpp"
|
#include "magiskboot.hpp"
|
||||||
#include "compress.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -16,17 +15,13 @@ using namespace std;
|
|||||||
#define SHA256_DIGEST_SIZE 32
|
#define SHA256_DIGEST_SIZE 32
|
||||||
#define SHA_DIGEST_SIZE 20
|
#define SHA_DIGEST_SIZE 20
|
||||||
|
|
||||||
static void decompress(format_t type, int fd, const void *in, size_t size) {
|
static void decompress(FileFormat type, int fd, const void *in, size_t size) {
|
||||||
auto ptr = get_decoder(type, make_unique<fd_stream>(fd));
|
decompress_bytes(type, byte_view { in, size }, fd);
|
||||||
ptr->write(in, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static off_t compress(format_t type, int fd, const void *in, size_t size) {
|
static off_t compress_len(FileFormat type, byte_view in, int fd) {
|
||||||
auto prev = lseek(fd, 0, SEEK_CUR);
|
auto prev = lseek(fd, 0, SEEK_CUR);
|
||||||
{
|
compress_bytes(type, in, fd);
|
||||||
auto strm = get_encoder(type, make_unique<fd_stream>(fd));
|
|
||||||
strm->write(in, size);
|
|
||||||
}
|
|
||||||
auto now = lseek(fd, 0, SEEK_CUR);
|
auto now = lseek(fd, 0, SEEK_CUR);
|
||||||
return now - prev;
|
return now - prev;
|
||||||
}
|
}
|
||||||
@@ -48,6 +43,11 @@ static size_t restore(int fd, const char *filename) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool check_env(const char *name) {
|
||||||
|
const char *val = getenv(name);
|
||||||
|
return val != nullptr && val == "true"sv;
|
||||||
|
}
|
||||||
|
|
||||||
void dyn_img_hdr::print() const {
|
void dyn_img_hdr::print() const {
|
||||||
uint32_t ver = header_version();
|
uint32_t ver = header_version();
|
||||||
fprintf(stderr, "%-*s [%u]\n", PADDING, "HEADER_VER", ver);
|
fprintf(stderr, "%-*s [%u]\n", PADDING, "HEADER_VER", ver);
|
||||||
@@ -149,29 +149,30 @@ void dyn_img_hdr::load_hdr_file() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
boot_img::boot_img(const char *image) : map(image) {
|
boot_img::boot_img(const char *image) :
|
||||||
|
map(image), k_fmt(FileFormat::UNKNOWN), r_fmt(FileFormat::UNKNOWN), e_fmt(FileFormat::UNKNOWN) {
|
||||||
fprintf(stderr, "Parsing boot image: [%s]\n", image);
|
fprintf(stderr, "Parsing boot image: [%s]\n", image);
|
||||||
for (const uint8_t *addr = map.buf(); addr < map.buf() + map.sz(); ++addr) {
|
for (const uint8_t *addr = map.buf(); addr < map.buf() + map.sz(); ++addr) {
|
||||||
format_t fmt = check_fmt(addr, map.sz());
|
FileFormat fmt = check_fmt(addr, map.sz());
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case CHROMEOS:
|
case FileFormat::CHROMEOS:
|
||||||
// chromeos require external signing
|
// chromeos require external signing
|
||||||
flags[CHROMEOS_FLAG] = true;
|
flags[CHROMEOS_FLAG] = true;
|
||||||
addr += 65535;
|
addr += 65535;
|
||||||
break;
|
break;
|
||||||
case DHTB:
|
case FileFormat::DHTB:
|
||||||
flags[DHTB_FLAG] = true;
|
flags[DHTB_FLAG] = true;
|
||||||
flags[SEANDROID_FLAG] = true;
|
flags[SEANDROID_FLAG] = true;
|
||||||
fprintf(stderr, "DHTB_HDR\n");
|
fprintf(stderr, "DHTB_HDR\n");
|
||||||
addr += sizeof(dhtb_hdr) - 1;
|
addr += sizeof(dhtb_hdr) - 1;
|
||||||
break;
|
break;
|
||||||
case BLOB:
|
case FileFormat::BLOB:
|
||||||
flags[BLOB_FLAG] = true;
|
flags[BLOB_FLAG] = true;
|
||||||
fprintf(stderr, "TEGRA_BLOB\n");
|
fprintf(stderr, "TEGRA_BLOB\n");
|
||||||
addr += sizeof(blob_hdr) - 1;
|
addr += sizeof(blob_hdr) - 1;
|
||||||
break;
|
break;
|
||||||
case AOSP:
|
case FileFormat::AOSP:
|
||||||
case AOSP_VENDOR:
|
case FileFormat::AOSP_VENDOR:
|
||||||
if (parse_image(addr, fmt))
|
if (parse_image(addr, fmt))
|
||||||
return;
|
return;
|
||||||
// fallthrough
|
// fallthrough
|
||||||
@@ -257,9 +258,9 @@ static int find_dtb_offset(const uint8_t *buf, unsigned sz) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static format_t check_fmt_lg(const uint8_t *buf, unsigned sz) {
|
static FileFormat check_fmt_lg(const uint8_t *buf, unsigned sz) {
|
||||||
format_t fmt = check_fmt(buf, sz);
|
FileFormat fmt = check_fmt(buf, sz);
|
||||||
if (fmt == LZ4_LEGACY) {
|
if (fmt == FileFormat::LZ4_LEGACY) {
|
||||||
// We need to check if it is LZ4_LG
|
// We need to check if it is LZ4_LG
|
||||||
uint32_t off = 4;
|
uint32_t off = 4;
|
||||||
uint32_t block_sz;
|
uint32_t block_sz;
|
||||||
@@ -267,7 +268,7 @@ static format_t check_fmt_lg(const uint8_t *buf, unsigned sz) {
|
|||||||
memcpy(&block_sz, buf + off, sizeof(block_sz));
|
memcpy(&block_sz, buf + off, sizeof(block_sz));
|
||||||
off += sizeof(block_sz);
|
off += sizeof(block_sz);
|
||||||
if (off + block_sz > sz)
|
if (off + block_sz > sz)
|
||||||
return LZ4_LG;
|
return FileFormat::LZ4_LG;
|
||||||
off += block_sz;
|
off += block_sz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,8 +277,8 @@ static format_t check_fmt_lg(const uint8_t *buf, unsigned sz) {
|
|||||||
|
|
||||||
#define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s)
|
#define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s)
|
||||||
|
|
||||||
pair<const uint8_t *, dyn_img_hdr *> boot_img::create_hdr(const uint8_t *addr, format_t type) {
|
pair<const uint8_t *, dyn_img_hdr *> boot_img::create_hdr(const uint8_t *addr, FileFormat type) {
|
||||||
if (type == AOSP_VENDOR) {
|
if (type == FileFormat::AOSP_VENDOR) {
|
||||||
fprintf(stderr, "VENDOR_BOOT_HDR\n");
|
fprintf(stderr, "VENDOR_BOOT_HDR\n");
|
||||||
auto h = reinterpret_cast<const boot_img_hdr_vnd_v3*>(addr);
|
auto h = reinterpret_cast<const boot_img_hdr_vnd_v3*>(addr);
|
||||||
switch (h->header_version) {
|
switch (h->header_version) {
|
||||||
@@ -377,7 +378,7 @@ off += hdr->name##_size(); \
|
|||||||
off = align_to(off, hdr->page_size()); \
|
off = align_to(off, hdr->page_size()); \
|
||||||
assert_off();
|
assert_off();
|
||||||
|
|
||||||
bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
bool boot_img::parse_image(const uint8_t *p, FileFormat type) {
|
||||||
auto [base_addr, hdr] = create_hdr(p, type);
|
auto [base_addr, hdr] = create_hdr(p, type);
|
||||||
if (hdr == nullptr) {
|
if (hdr == nullptr) {
|
||||||
fprintf(stderr, "Invalid boot image header!\n");
|
fprintf(stderr, "Invalid boot image header!\n");
|
||||||
@@ -419,7 +420,7 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
k_fmt = check_fmt_lg(kernel, hdr->kernel_size());
|
k_fmt = check_fmt_lg(kernel, hdr->kernel_size());
|
||||||
if (k_fmt == MTK) {
|
if (k_fmt == FileFormat::MTK) {
|
||||||
fprintf(stderr, "MTK_KERNEL_HDR\n");
|
fprintf(stderr, "MTK_KERNEL_HDR\n");
|
||||||
flags[MTK_KERNEL] = true;
|
flags[MTK_KERNEL] = true;
|
||||||
k_hdr = reinterpret_cast<const mtk_hdr *>(kernel);
|
k_hdr = reinterpret_cast<const mtk_hdr *>(kernel);
|
||||||
@@ -429,14 +430,14 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
|||||||
hdr->kernel_size() -= sizeof(mtk_hdr);
|
hdr->kernel_size() -= sizeof(mtk_hdr);
|
||||||
k_fmt = check_fmt_lg(kernel, hdr->kernel_size());
|
k_fmt = check_fmt_lg(kernel, hdr->kernel_size());
|
||||||
}
|
}
|
||||||
if (k_fmt == ZIMAGE) {
|
if (k_fmt == FileFormat::ZIMAGE) {
|
||||||
z_hdr = reinterpret_cast<const zimage_hdr *>(kernel);
|
z_hdr = reinterpret_cast<const zimage_hdr *>(kernel);
|
||||||
|
|
||||||
const uint8_t* found_pos = 0;
|
const uint8_t* found_pos = 0;
|
||||||
|
|
||||||
for (const uint8_t* search_pos = kernel + 0x28; search_pos < kernel + hdr->kernel_size(); search_pos++) {
|
for (const uint8_t* search_pos = kernel + 0x28; search_pos < kernel + hdr->kernel_size(); search_pos++) {
|
||||||
// ^^^^^^ +0x28 to search after zimage header and magic
|
// ^^^^^^ +0x28 to search after zimage header and magic
|
||||||
if (check_fmt_lg(search_pos, hdr->kernel_size() - (search_pos - kernel)) != UNKNOWN) {
|
if (check_fmt_lg(search_pos, hdr->kernel_size() - (search_pos - kernel)) != FileFormat::UNKNOWN) {
|
||||||
found_pos = search_pos;
|
found_pos = search_pos;
|
||||||
search_pos = kernel + hdr->kernel_size();
|
search_pos = kernel + hdr->kernel_size();
|
||||||
}
|
}
|
||||||
@@ -488,7 +489,7 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
|||||||
reinterpret_cast<table_entry *>(vendor_ramdisk_table),
|
reinterpret_cast<table_entry *>(vendor_ramdisk_table),
|
||||||
hdr->vendor_ramdisk_table_entry_num());
|
hdr->vendor_ramdisk_table_entry_num());
|
||||||
for (auto &it : table) {
|
for (auto &it : table) {
|
||||||
format_t fmt = check_fmt_lg(ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
FileFormat fmt = check_fmt_lg(ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%-*s name=[%s] type=[%s] size=[%u] fmt=[%s]\n", PADDING, "VND_RAMDISK",
|
"%-*s name=[%s] type=[%s] size=[%u] fmt=[%s]\n", PADDING, "VND_RAMDISK",
|
||||||
it.ramdisk_name, vendor_ramdisk_type(it.ramdisk_type),
|
it.ramdisk_name, vendor_ramdisk_type(it.ramdisk_type),
|
||||||
@@ -496,7 +497,7 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
r_fmt = check_fmt_lg(ramdisk, size);
|
r_fmt = check_fmt_lg(ramdisk, size);
|
||||||
if (r_fmt == MTK) {
|
if (r_fmt == FileFormat::MTK) {
|
||||||
fprintf(stderr, "MTK_RAMDISK_HDR\n");
|
fprintf(stderr, "MTK_RAMDISK_HDR\n");
|
||||||
flags[MTK_RAMDISK] = true;
|
flags[MTK_RAMDISK] = true;
|
||||||
r_hdr = reinterpret_cast<const mtk_hdr *>(ramdisk);
|
r_hdr = reinterpret_cast<const mtk_hdr *>(ramdisk);
|
||||||
@@ -555,8 +556,8 @@ bool boot_img::verify(const char *cert) const {
|
|||||||
int split_image_dtb(const char *filename, bool skip_decomp) {
|
int split_image_dtb(const char *filename, bool skip_decomp) {
|
||||||
mmap_data img(filename);
|
mmap_data img(filename);
|
||||||
|
|
||||||
if (int off = find_dtb_offset(img.buf(), img.sz()); off > 0) {
|
if (size_t off = find_dtb_offset(img.buf(), img.sz()); off > 0) {
|
||||||
format_t fmt = check_fmt_lg(img.buf(), img.sz());
|
FileFormat fmt = check_fmt_lg(img.buf(), img.sz());
|
||||||
if (!skip_decomp && COMPRESSED(fmt)) {
|
if (!skip_decomp && COMPRESSED(fmt)) {
|
||||||
int fd = creat(KERNEL_FILE, 0644);
|
int fd = creat(KERNEL_FILE, 0644);
|
||||||
decompress(fmt, fd, img.buf(), off);
|
decompress(fmt, fd, img.buf(), off);
|
||||||
@@ -609,7 +610,7 @@ int unpack(const char *image, bool skip_decomp, bool hdr) {
|
|||||||
ssprintf(file_name, sizeof(file_name), "%s.cpio", it.ramdisk_name);
|
ssprintf(file_name, sizeof(file_name), "%s.cpio", it.ramdisk_name);
|
||||||
}
|
}
|
||||||
owned_fd fd = xopenat(dirfd, file_name, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
|
owned_fd fd = xopenat(dirfd, file_name, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
|
||||||
format_t fmt = check_fmt_lg(boot.ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
FileFormat fmt = check_fmt_lg(boot.ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
||||||
if (!skip_decomp && COMPRESSED(fmt)) {
|
if (!skip_decomp && COMPRESSED(fmt)) {
|
||||||
decompress(fmt, fd, boot.ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
decompress(fmt, fd, boot.ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
||||||
} else {
|
} else {
|
||||||
@@ -719,8 +720,8 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
|
|||||||
mmap_data m(KERNEL_FILE);
|
mmap_data m(KERNEL_FILE);
|
||||||
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(boot.k_fmt)) {
|
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(boot.k_fmt)) {
|
||||||
// Always use zopfli for zImage compression
|
// Always use zopfli for zImage compression
|
||||||
auto fmt = (boot.flags[ZIMAGE_KERNEL] && boot.k_fmt == GZIP) ? ZOPFLI : boot.k_fmt;
|
auto fmt = (boot.flags[ZIMAGE_KERNEL] && boot.k_fmt == FileFormat::GZIP) ? FileFormat::ZOPFLI : boot.k_fmt;
|
||||||
hdr->kernel_size() = compress(fmt, fd, m.buf(), m.sz());
|
hdr->kernel_size() = compress_len(fmt, m, fd);
|
||||||
} else {
|
} else {
|
||||||
hdr->kernel_size() = xwrite(fd, m.buf(), m.sz());
|
hdr->kernel_size() = xwrite(fd, m.buf(), m.sz());
|
||||||
}
|
}
|
||||||
@@ -783,10 +784,10 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
|
|||||||
ssprintf(file_name, sizeof(file_name), "%s.cpio", it.ramdisk_name);
|
ssprintf(file_name, sizeof(file_name), "%s.cpio", it.ramdisk_name);
|
||||||
}
|
}
|
||||||
mmap_data m(dirfd, file_name);
|
mmap_data m(dirfd, file_name);
|
||||||
format_t fmt = check_fmt_lg(boot.ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
FileFormat fmt = check_fmt_lg(boot.ramdisk + it.ramdisk_offset, it.ramdisk_size);
|
||||||
it.ramdisk_offset = ramdisk_offset;
|
it.ramdisk_offset = ramdisk_offset;
|
||||||
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(fmt)) {
|
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(fmt)) {
|
||||||
it.ramdisk_size = compress(fmt, fd, m.buf(), m.sz());
|
it.ramdisk_size = compress_len(fmt, m, fd);
|
||||||
} else {
|
} else {
|
||||||
it.ramdisk_size = xwrite(fd, m.buf(), m.sz());
|
it.ramdisk_size = xwrite(fd, m.buf(), m.sz());
|
||||||
}
|
}
|
||||||
@@ -798,15 +799,15 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
|
|||||||
} else if (access(RAMDISK_FILE, R_OK) == 0) {
|
} else if (access(RAMDISK_FILE, R_OK) == 0) {
|
||||||
mmap_data m(RAMDISK_FILE);
|
mmap_data m(RAMDISK_FILE);
|
||||||
auto r_fmt = boot.r_fmt;
|
auto r_fmt = boot.r_fmt;
|
||||||
if (!skip_comp && !hdr->is_vendor() && hdr->header_version() == 4 && r_fmt != LZ4_LEGACY) {
|
if (!skip_comp && !hdr->is_vendor() && hdr->header_version() == 4 && r_fmt != FileFormat::LZ4_LEGACY) {
|
||||||
// A v4 boot image ramdisk will have to be merged with other vendor ramdisks,
|
// A v4 boot image ramdisk will have to be merged with other vendor ramdisks,
|
||||||
// and they have to use the exact same compression method. v4 GKIs are required to
|
// and they have to use the exact same compression method. v4 GKIs are required to
|
||||||
// use lz4 (legacy), so hardcode the format here.
|
// use lz4 (legacy), so hardcode the format here.
|
||||||
fprintf(stderr, "RAMDISK_FMT: [%s] -> [%s]\n", fmt2name[r_fmt], fmt2name[LZ4_LEGACY]);
|
fprintf(stderr, "RAMDISK_FMT: [%s] -> [%s]\n", fmt2name[r_fmt], fmt2name[FileFormat::LZ4_LEGACY]);
|
||||||
r_fmt = LZ4_LEGACY;
|
r_fmt = FileFormat::LZ4_LEGACY;
|
||||||
}
|
}
|
||||||
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(r_fmt)) {
|
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(r_fmt)) {
|
||||||
hdr->ramdisk_size() = compress(r_fmt, fd, m.buf(), m.sz());
|
hdr->ramdisk_size() = compress_len(r_fmt, m, fd);
|
||||||
} else {
|
} else {
|
||||||
hdr->ramdisk_size() = xwrite(fd, m.buf(), m.sz());
|
hdr->ramdisk_size() = xwrite(fd, m.buf(), m.sz());
|
||||||
}
|
}
|
||||||
@@ -825,7 +826,7 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
|
|||||||
if (access(EXTRA_FILE, R_OK) == 0) {
|
if (access(EXTRA_FILE, R_OK) == 0) {
|
||||||
mmap_data m(EXTRA_FILE);
|
mmap_data m(EXTRA_FILE);
|
||||||
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(boot.e_fmt)) {
|
if (!skip_comp && !COMPRESSED_ANY(check_fmt(m.buf(), m.sz())) && COMPRESSED(boot.e_fmt)) {
|
||||||
hdr->extra_size() = compress(boot.e_fmt, fd, m.buf(), m.sz());
|
hdr->extra_size() = compress_len(boot.e_fmt, m, fd);
|
||||||
} else {
|
} else {
|
||||||
hdr->extra_size() = xwrite(fd, m.buf(), m.sz());
|
hdr->extra_size() = xwrite(fd, m.buf(), m.sz());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -610,9 +610,9 @@ struct boot_img {
|
|||||||
std::bitset<BOOT_FLAGS_MAX> flags;
|
std::bitset<BOOT_FLAGS_MAX> flags;
|
||||||
|
|
||||||
// The format of kernel, ramdisk and extra
|
// The format of kernel, ramdisk and extra
|
||||||
format_t k_fmt = UNKNOWN;
|
FileFormat k_fmt;
|
||||||
format_t r_fmt = UNKNOWN;
|
FileFormat r_fmt;
|
||||||
format_t e_fmt = UNKNOWN;
|
FileFormat e_fmt;
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Following pointers points within the read-only mmap region
|
* Following pointers points within the read-only mmap region
|
||||||
@@ -672,8 +672,8 @@ struct boot_img {
|
|||||||
boot_img(const char *);
|
boot_img(const char *);
|
||||||
~boot_img();
|
~boot_img();
|
||||||
|
|
||||||
bool parse_image(const uint8_t *addr, format_t type);
|
bool parse_image(const uint8_t *addr, FileFormat type);
|
||||||
std::pair<const uint8_t *, dyn_img_hdr *> create_hdr(const uint8_t *addr, format_t type);
|
std::pair<const uint8_t *, dyn_img_hdr *> create_hdr(const uint8_t *addr, FileFormat type);
|
||||||
|
|
||||||
// Rust FFI
|
// Rust FFI
|
||||||
rust::Slice<const uint8_t> get_payload() const { return payload; }
|
rust::Slice<const uint8_t> get_payload() const { return payload; }
|
||||||
|
|||||||
@@ -1,287 +0,0 @@
|
|||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- Public header file for the library. ---*/
|
|
||||||
/*--- bzlib.h ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
|
||||||
This file is part of bzip2/libbzip2, a program and library for
|
|
||||||
lossless, block-sorting data compression.
|
|
||||||
|
|
||||||
bzip2/libbzip2 version 1.1.0 of 6 September 2010
|
|
||||||
Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
|
|
||||||
|
|
||||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
|
||||||
README file.
|
|
||||||
|
|
||||||
This program is released under the terms of the license contained
|
|
||||||
in the file LICENSE.
|
|
||||||
------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _BZLIB_H
|
|
||||||
#define _BZLIB_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BZ_RUN 0
|
|
||||||
#define BZ_FLUSH 1
|
|
||||||
#define BZ_FINISH 2
|
|
||||||
|
|
||||||
#define BZ_OK 0
|
|
||||||
#define BZ_RUN_OK 1
|
|
||||||
#define BZ_FLUSH_OK 2
|
|
||||||
#define BZ_FINISH_OK 3
|
|
||||||
#define BZ_STREAM_END 4
|
|
||||||
#define BZ_SEQUENCE_ERROR (-1)
|
|
||||||
#define BZ_PARAM_ERROR (-2)
|
|
||||||
#define BZ_MEM_ERROR (-3)
|
|
||||||
#define BZ_DATA_ERROR (-4)
|
|
||||||
#define BZ_DATA_ERROR_MAGIC (-5)
|
|
||||||
#define BZ_IO_ERROR (-6)
|
|
||||||
#define BZ_UNEXPECTED_EOF (-7)
|
|
||||||
#define BZ_OUTBUFF_FULL (-8)
|
|
||||||
#define BZ_CONFIG_ERROR (-9)
|
|
||||||
|
|
||||||
typedef
|
|
||||||
struct {
|
|
||||||
char *next_in;
|
|
||||||
unsigned int avail_in;
|
|
||||||
unsigned int total_in_lo32;
|
|
||||||
unsigned int total_in_hi32;
|
|
||||||
|
|
||||||
char *next_out;
|
|
||||||
unsigned int avail_out;
|
|
||||||
unsigned int total_out_lo32;
|
|
||||||
unsigned int total_out_hi32;
|
|
||||||
|
|
||||||
void *state;
|
|
||||||
|
|
||||||
void *(*bzalloc)(void *,int,int);
|
|
||||||
void (*bzfree)(void *,void *);
|
|
||||||
void *opaque;
|
|
||||||
}
|
|
||||||
bz_stream;
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef BZ_IMPORT
|
|
||||||
#define BZ_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef BZ_NO_STDIO
|
|
||||||
/* Need a definitition for FILE */
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# include <windows.h>
|
|
||||||
# ifdef small
|
|
||||||
/* windows.h define small to char */
|
|
||||||
# undef small
|
|
||||||
# endif
|
|
||||||
# ifndef WINAPI
|
|
||||||
# define WINAPI
|
|
||||||
# endif
|
|
||||||
# ifdef BZ_EXPORT
|
|
||||||
# define BZ_API(func) WINAPI func
|
|
||||||
# define BZ_EXTERN extern
|
|
||||||
# else
|
|
||||||
/* import windows dll dynamically */
|
|
||||||
# define BZ_API(func) (WINAPI * func)
|
|
||||||
# define BZ_EXTERN
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define BZ_API(func) func
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef BZ_EXTERN
|
|
||||||
#define BZ_EXTERN extern
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*-- Core (low-level) library functions --*/
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
|
|
||||||
bz_stream* strm,
|
|
||||||
int blockSize100k,
|
|
||||||
int verbosity,
|
|
||||||
int workFactor
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzCompress) (
|
|
||||||
bz_stream* strm,
|
|
||||||
int action
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
|
|
||||||
bz_stream* strm
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
|
|
||||||
bz_stream *strm,
|
|
||||||
int verbosity,
|
|
||||||
int small
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
|
|
||||||
bz_stream* strm
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
|
|
||||||
bz_stream *strm
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-- High(er) level library functions --*/
|
|
||||||
|
|
||||||
#ifndef BZ_NO_STDIO
|
|
||||||
#define BZ_MAX_UNUSED 5000
|
|
||||||
|
|
||||||
typedef void BZFILE;
|
|
||||||
|
|
||||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
|
|
||||||
int* bzerror,
|
|
||||||
FILE* f,
|
|
||||||
int verbosity,
|
|
||||||
int small,
|
|
||||||
void* unused,
|
|
||||||
int nUnused
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
|
|
||||||
int* bzerror,
|
|
||||||
BZFILE* b
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
|
|
||||||
int* bzerror,
|
|
||||||
BZFILE* b,
|
|
||||||
void** unused,
|
|
||||||
int* nUnused
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzRead) (
|
|
||||||
int* bzerror,
|
|
||||||
BZFILE* b,
|
|
||||||
void* buf,
|
|
||||||
int len
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
|
|
||||||
int* bzerror,
|
|
||||||
FILE* f,
|
|
||||||
int blockSize100k,
|
|
||||||
int verbosity,
|
|
||||||
int workFactor
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN void BZ_API(BZ2_bzWrite) (
|
|
||||||
int* bzerror,
|
|
||||||
BZFILE* b,
|
|
||||||
void* buf,
|
|
||||||
int len
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
|
|
||||||
int* bzerror,
|
|
||||||
BZFILE* b,
|
|
||||||
int abandon,
|
|
||||||
unsigned int* nbytes_in,
|
|
||||||
unsigned int* nbytes_out
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
|
|
||||||
int* bzerror,
|
|
||||||
BZFILE* b,
|
|
||||||
int abandon,
|
|
||||||
unsigned int* nbytes_in_lo32,
|
|
||||||
unsigned int* nbytes_in_hi32,
|
|
||||||
unsigned int* nbytes_out_lo32,
|
|
||||||
unsigned int* nbytes_out_hi32
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*-- Utility functions --*/
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
|
|
||||||
char* dest,
|
|
||||||
unsigned int* destLen,
|
|
||||||
char* source,
|
|
||||||
unsigned int sourceLen,
|
|
||||||
int blockSize100k,
|
|
||||||
int verbosity,
|
|
||||||
int workFactor
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
|
|
||||||
char* dest,
|
|
||||||
unsigned int* destLen,
|
|
||||||
char* source,
|
|
||||||
unsigned int sourceLen,
|
|
||||||
int small,
|
|
||||||
int verbosity
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/*--
|
|
||||||
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
|
|
||||||
to support better zlib compatibility.
|
|
||||||
This code is not _officially_ part of libbzip2 (yet);
|
|
||||||
I haven't tested it, documented it, or considered the
|
|
||||||
threading-safeness of it.
|
|
||||||
If this code breaks, please contact both Yoshioka and me.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
|
|
||||||
void
|
|
||||||
);
|
|
||||||
|
|
||||||
#ifndef BZ_NO_STDIO
|
|
||||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
|
|
||||||
const char *path,
|
|
||||||
const char *mode
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
|
|
||||||
int fd,
|
|
||||||
const char *mode
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzread) (
|
|
||||||
BZFILE* b,
|
|
||||||
void* buf,
|
|
||||||
int len
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzwrite) (
|
|
||||||
BZFILE* b,
|
|
||||||
void* buf,
|
|
||||||
int len
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN int BZ_API(BZ2_bzflush) (
|
|
||||||
BZFILE* b
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN void BZ_API(BZ2_bzclose) (
|
|
||||||
BZFILE* b
|
|
||||||
);
|
|
||||||
|
|
||||||
BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
|
|
||||||
BZFILE *b,
|
|
||||||
int *errnum
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
/*--- end bzlib.h ---*/
|
|
||||||
/*-------------------------------------------------------------*/
|
|
||||||
@@ -1,762 +0,0 @@
|
|||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <zlib.h>
|
|
||||||
#include "bzlib.h"
|
|
||||||
#include <lzma.h>
|
|
||||||
#include <lz4.h>
|
|
||||||
#include <lz4frame.h>
|
|
||||||
#include <lz4hc.h>
|
|
||||||
#include <zopfli/util.h>
|
|
||||||
#include <zopfli/deflate.h>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
|
|
||||||
#include "magiskboot.hpp"
|
|
||||||
#include "compress.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#define bwrite this->base->write
|
|
||||||
|
|
||||||
constexpr size_t CHUNK = 0x40000;
|
|
||||||
constexpr size_t LZ4_UNCOMPRESSED = 0x800000;
|
|
||||||
constexpr size_t LZ4_COMPRESSED = LZ4_COMPRESSBOUND(LZ4_UNCOMPRESSED);
|
|
||||||
|
|
||||||
class gz_strm : public filter_out_stream {
|
|
||||||
public:
|
|
||||||
bool write(const void *buf, size_t len) override {
|
|
||||||
return len == 0 || do_write(buf, len, Z_NO_FLUSH);
|
|
||||||
}
|
|
||||||
|
|
||||||
~gz_strm() override {
|
|
||||||
do_write(nullptr, 0, Z_FINISH);
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
inflateEnd(&strm);
|
|
||||||
break;
|
|
||||||
case ENCODE:
|
|
||||||
deflateEnd(&strm);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum mode_t {
|
|
||||||
DECODE,
|
|
||||||
ENCODE,
|
|
||||||
WAIT,
|
|
||||||
COPY
|
|
||||||
} mode;
|
|
||||||
|
|
||||||
gz_strm(mode_t mode, out_strm_ptr &&base) :
|
|
||||||
filter_out_stream(std::move(base)), mode(mode), strm{}, outbuf{0} {
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
inflateInit2(&strm, 15 | 16);
|
|
||||||
break;
|
|
||||||
case ENCODE:
|
|
||||||
deflateInit2(&strm, 9, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
z_stream strm;
|
|
||||||
uint8_t outbuf[CHUNK];
|
|
||||||
|
|
||||||
bool do_write(const void *buf, size_t len, int flush) {
|
|
||||||
if (mode == WAIT) {
|
|
||||||
if (len == 0) return true;
|
|
||||||
Bytef b[1] = {0x1f};
|
|
||||||
if (*(Bytef *)buf == 0x8b) {
|
|
||||||
mode = DECODE;
|
|
||||||
inflateReset(&strm);
|
|
||||||
strm.next_in = b;
|
|
||||||
strm.avail_in = 1;
|
|
||||||
inflate(&strm, flush);
|
|
||||||
} else {
|
|
||||||
mode = COPY;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strm.next_in = (Bytef *) buf;
|
|
||||||
strm.avail_in = len;
|
|
||||||
do {
|
|
||||||
int code;
|
|
||||||
strm.next_out = outbuf;
|
|
||||||
strm.avail_out = sizeof(outbuf);
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
code = inflate(&strm, flush);
|
|
||||||
break;
|
|
||||||
case ENCODE:
|
|
||||||
code = deflate(&strm, flush);
|
|
||||||
break;
|
|
||||||
case COPY:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
// should have been handled
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (code == Z_STREAM_ERROR) {
|
|
||||||
LOGW("gzip %s failed (%d)\n", mode ? "encode" : "decode", code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!bwrite(outbuf, sizeof(outbuf) - strm.avail_out))
|
|
||||||
return false;
|
|
||||||
if (mode == DECODE && code == Z_STREAM_END) {
|
|
||||||
if (strm.avail_in > 1) {
|
|
||||||
if (strm.next_in[0] == 0x1f && strm.next_in[1] == 0x8b) {
|
|
||||||
// There is still data in the stream, we need to reset the stream
|
|
||||||
// and continue decoding
|
|
||||||
inflateReset(&strm);
|
|
||||||
strm.avail_out = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (strm.avail_in == 1) {
|
|
||||||
if (strm.next_in[0] == 0x1f) {
|
|
||||||
// If there is only one byte left, we need to wait for the next byte
|
|
||||||
// to determine if it is a gzip header
|
|
||||||
mode = WAIT;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// The next inflate won't consume any data but fallback
|
|
||||||
// to the previous two conditions
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// There is still data in the stream, we need to copy it
|
|
||||||
mode = COPY;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class gz_decoder : public gz_strm {
|
|
||||||
public:
|
|
||||||
explicit gz_decoder(out_strm_ptr &&base) : gz_strm(DECODE, std::move(base)) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class gz_encoder : public gz_strm {
|
|
||||||
public:
|
|
||||||
explicit gz_encoder(out_strm_ptr &&base) : gz_strm(ENCODE, std::move(base)) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class zopfli_encoder : public chunk_out_stream {
|
|
||||||
public:
|
|
||||||
explicit zopfli_encoder(out_strm_ptr &&base) :
|
|
||||||
chunk_out_stream(std::move(base), ZOPFLI_MASTER_BLOCK_SIZE),
|
|
||||||
zo{}, out(nullptr), outsize(0), crc(crc32(0L, Z_NULL, 0)), in_total(0), bp(0) {
|
|
||||||
ZopfliInitOptions(&zo);
|
|
||||||
|
|
||||||
// This config is already better than gzip -9
|
|
||||||
zo.numiterations = 1;
|
|
||||||
zo.blocksplitting = 0;
|
|
||||||
|
|
||||||
ZOPFLI_APPEND_DATA(31, &out, &outsize); /* ID1 */
|
|
||||||
ZOPFLI_APPEND_DATA(139, &out, &outsize); /* ID2 */
|
|
||||||
ZOPFLI_APPEND_DATA(8, &out, &outsize); /* CM */
|
|
||||||
ZOPFLI_APPEND_DATA(0, &out, &outsize); /* FLG */
|
|
||||||
/* MTIME */
|
|
||||||
ZOPFLI_APPEND_DATA(0, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA(0, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA(0, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA(0, &out, &outsize);
|
|
||||||
|
|
||||||
ZOPFLI_APPEND_DATA(2, &out, &outsize); /* XFL, 2 indicates best compression. */
|
|
||||||
ZOPFLI_APPEND_DATA(3, &out, &outsize); /* OS follows Unix conventions. */
|
|
||||||
}
|
|
||||||
|
|
||||||
~zopfli_encoder() override {
|
|
||||||
finalize();
|
|
||||||
|
|
||||||
/* CRC */
|
|
||||||
ZOPFLI_APPEND_DATA(crc % 256, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA((crc >> 8) % 256, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA((crc >> 16) % 256, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA((crc >> 24) % 256, &out, &outsize);
|
|
||||||
|
|
||||||
/* ISIZE */
|
|
||||||
ZOPFLI_APPEND_DATA(in_total % 256, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA((in_total >> 8) % 256, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA((in_total >> 16) % 256, &out, &outsize);
|
|
||||||
ZOPFLI_APPEND_DATA((in_total >> 24) % 256, &out, &outsize);
|
|
||||||
|
|
||||||
bwrite(out, outsize);
|
|
||||||
free(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool write_chunk(const void *buf, size_t len, bool final) override {
|
|
||||||
auto in = static_cast<const unsigned char *>(buf);
|
|
||||||
|
|
||||||
in_total += len;
|
|
||||||
crc = crc32(crc, in, len);
|
|
||||||
|
|
||||||
ZopfliDeflatePart(&zo, 2, final, in, 0, len, &bp, &out, &outsize);
|
|
||||||
|
|
||||||
// ZOPFLI_APPEND_DATA is extremely dumb, so we always preserve the
|
|
||||||
// last byte to make sure that realloc is used instead of malloc
|
|
||||||
if (!bwrite(out, outsize - 1))
|
|
||||||
return false;
|
|
||||||
out[0] = out[outsize - 1];
|
|
||||||
outsize = 1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ZopfliOptions zo;
|
|
||||||
unsigned char *out;
|
|
||||||
size_t outsize;
|
|
||||||
unsigned long crc;
|
|
||||||
uint32_t in_total;
|
|
||||||
unsigned char bp;
|
|
||||||
};
|
|
||||||
|
|
||||||
class bz_strm : public filter_out_stream {
|
|
||||||
public:
|
|
||||||
bool write(const void *buf, size_t len) override {
|
|
||||||
return len == 0 || do_write(buf, len, BZ_RUN);
|
|
||||||
}
|
|
||||||
|
|
||||||
~bz_strm() override {
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
BZ2_bzDecompressEnd(&strm);
|
|
||||||
break;
|
|
||||||
case ENCODE:
|
|
||||||
do_write(nullptr, 0, BZ_FINISH);
|
|
||||||
BZ2_bzCompressEnd(&strm);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum mode_t {
|
|
||||||
DECODE,
|
|
||||||
ENCODE
|
|
||||||
} mode;
|
|
||||||
|
|
||||||
bz_strm(mode_t mode, out_strm_ptr &&base) :
|
|
||||||
filter_out_stream(std::move(base)), mode(mode), strm{}, outbuf{0} {
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
BZ2_bzDecompressInit(&strm, 0, 0);
|
|
||||||
break;
|
|
||||||
case ENCODE:
|
|
||||||
BZ2_bzCompressInit(&strm, 9, 0, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bz_stream strm;
|
|
||||||
char outbuf[CHUNK];
|
|
||||||
|
|
||||||
bool do_write(const void *buf, size_t len, int flush) {
|
|
||||||
strm.next_in = (char *) buf;
|
|
||||||
strm.avail_in = len;
|
|
||||||
do {
|
|
||||||
int code;
|
|
||||||
strm.avail_out = sizeof(outbuf);
|
|
||||||
strm.next_out = outbuf;
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
code = BZ2_bzDecompress(&strm);
|
|
||||||
break;
|
|
||||||
case ENCODE:
|
|
||||||
code = BZ2_bzCompress(&strm, flush);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (code < 0) {
|
|
||||||
LOGW("bzip2 %s failed (%d)\n", mode ? "encode" : "decode", code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!bwrite(outbuf, sizeof(outbuf) - strm.avail_out))
|
|
||||||
return false;
|
|
||||||
if (code == BZ_STREAM_END)
|
|
||||||
return true;
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class bz_decoder : public bz_strm {
|
|
||||||
public:
|
|
||||||
explicit bz_decoder(out_strm_ptr &&base) : bz_strm(DECODE, std::move(base)) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class bz_encoder : public bz_strm {
|
|
||||||
public:
|
|
||||||
explicit bz_encoder(out_strm_ptr &&base) : bz_strm(ENCODE, std::move(base)) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class lzma_strm : public filter_out_stream {
|
|
||||||
public:
|
|
||||||
bool write(const void *buf, size_t len) override {
|
|
||||||
return len == 0 || do_write(buf, len, LZMA_RUN);
|
|
||||||
}
|
|
||||||
|
|
||||||
~lzma_strm() override {
|
|
||||||
do_write(nullptr, 0, LZMA_FINISH);
|
|
||||||
lzma_end(&strm);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum mode_t {
|
|
||||||
DECODE,
|
|
||||||
ENCODE_XZ,
|
|
||||||
ENCODE_LZMA
|
|
||||||
} mode;
|
|
||||||
|
|
||||||
lzma_strm(mode_t mode, out_strm_ptr &&base) :
|
|
||||||
filter_out_stream(std::move(base)), mode(mode), strm(LZMA_STREAM_INIT), outbuf{0} {
|
|
||||||
lzma_options_lzma opt;
|
|
||||||
|
|
||||||
// Initialize preset
|
|
||||||
lzma_lzma_preset(&opt, 9);
|
|
||||||
lzma_filter filters[] = {
|
|
||||||
{ .id = LZMA_FILTER_LZMA2, .options = &opt },
|
|
||||||
{ .id = LZMA_VLI_UNKNOWN, .options = nullptr },
|
|
||||||
};
|
|
||||||
|
|
||||||
lzma_ret code;
|
|
||||||
switch(mode) {
|
|
||||||
case DECODE:
|
|
||||||
code = lzma_auto_decoder(&strm, UINT64_MAX, 0);
|
|
||||||
break;
|
|
||||||
case ENCODE_XZ:
|
|
||||||
code = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC32);
|
|
||||||
break;
|
|
||||||
case ENCODE_LZMA:
|
|
||||||
code = lzma_alone_encoder(&strm, &opt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (code != LZMA_OK) {
|
|
||||||
LOGE("LZMA initialization failed (%d)\n", code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
lzma_stream strm;
|
|
||||||
uint8_t outbuf[CHUNK];
|
|
||||||
|
|
||||||
bool do_write(const void *buf, size_t len, lzma_action flush) {
|
|
||||||
strm.next_in = (uint8_t *) buf;
|
|
||||||
strm.avail_in = len;
|
|
||||||
do {
|
|
||||||
strm.avail_out = sizeof(outbuf);
|
|
||||||
strm.next_out = outbuf;
|
|
||||||
int code = lzma_code(&strm, flush);
|
|
||||||
if (code != LZMA_OK && code != LZMA_STREAM_END) {
|
|
||||||
LOGW("LZMA %s failed (%d)\n", mode ? "encode" : "decode", code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!bwrite(outbuf, sizeof(outbuf) - strm.avail_out))
|
|
||||||
return false;
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class lzma_decoder : public lzma_strm {
|
|
||||||
public:
|
|
||||||
explicit lzma_decoder(out_strm_ptr &&base) : lzma_strm(DECODE, std::move(base)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class xz_encoder : public lzma_strm {
|
|
||||||
public:
|
|
||||||
explicit xz_encoder(out_strm_ptr &&base) : lzma_strm(ENCODE_XZ, std::move(base)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class lzma_encoder : public lzma_strm {
|
|
||||||
public:
|
|
||||||
explicit lzma_encoder(out_strm_ptr &&base) : lzma_strm(ENCODE_LZMA, std::move(base)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LZ4F_decoder : public filter_out_stream {
|
|
||||||
public:
|
|
||||||
explicit LZ4F_decoder(out_strm_ptr &&base) :
|
|
||||||
filter_out_stream(std::move(base)), ctx(nullptr), outbuf(nullptr), outCapacity(0) {
|
|
||||||
LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
~LZ4F_decoder() override {
|
|
||||||
LZ4F_freeDecompressionContext(ctx);
|
|
||||||
delete[] outbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write(const void *buf, size_t len) override {
|
|
||||||
auto in = reinterpret_cast<const uint8_t *>(buf);
|
|
||||||
if (!outbuf) {
|
|
||||||
size_t read = len;
|
|
||||||
LZ4F_frameInfo_t info;
|
|
||||||
LZ4F_getFrameInfo(ctx, &info, in, &read);
|
|
||||||
switch (info.blockSizeID) {
|
|
||||||
case LZ4F_default:
|
|
||||||
case LZ4F_max64KB: outCapacity = 1 << 16; break;
|
|
||||||
case LZ4F_max256KB: outCapacity = 1 << 18; break;
|
|
||||||
case LZ4F_max1MB: outCapacity = 1 << 20; break;
|
|
||||||
case LZ4F_max4MB: outCapacity = 1 << 22; break;
|
|
||||||
}
|
|
||||||
outbuf = new uint8_t[outCapacity];
|
|
||||||
in += read;
|
|
||||||
len -= read;
|
|
||||||
}
|
|
||||||
size_t read, write;
|
|
||||||
LZ4F_errorCode_t code;
|
|
||||||
do {
|
|
||||||
read = len;
|
|
||||||
write = outCapacity;
|
|
||||||
code = LZ4F_decompress(ctx, outbuf, &write, in, &read, nullptr);
|
|
||||||
if (LZ4F_isError(code)) {
|
|
||||||
LOGW("LZ4F decode error: %s\n", LZ4F_getErrorName(code));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
len -= read;
|
|
||||||
in += read;
|
|
||||||
if (!bwrite(outbuf, write))
|
|
||||||
return false;
|
|
||||||
} while (len != 0 || write != 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
LZ4F_decompressionContext_t ctx;
|
|
||||||
uint8_t *outbuf;
|
|
||||||
size_t outCapacity;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LZ4F_encoder : public filter_out_stream {
|
|
||||||
public:
|
|
||||||
explicit LZ4F_encoder(out_strm_ptr &&base) :
|
|
||||||
filter_out_stream(std::move(base)), ctx(nullptr), out_buf(nullptr), outCapacity(0) {
|
|
||||||
LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write(const void *buf, size_t len) override {
|
|
||||||
if (!out_buf) {
|
|
||||||
LZ4F_preferences_t prefs {
|
|
||||||
.frameInfo = {
|
|
||||||
.blockSizeID = LZ4F_max4MB,
|
|
||||||
.blockMode = LZ4F_blockIndependent,
|
|
||||||
.contentChecksumFlag = LZ4F_contentChecksumEnabled,
|
|
||||||
.blockChecksumFlag = LZ4F_noBlockChecksum,
|
|
||||||
},
|
|
||||||
.compressionLevel = 9,
|
|
||||||
.autoFlush = 1,
|
|
||||||
};
|
|
||||||
outCapacity = LZ4F_compressBound(BLOCK_SZ, &prefs);
|
|
||||||
out_buf = new uint8_t[outCapacity];
|
|
||||||
size_t write = LZ4F_compressBegin(ctx, out_buf, outCapacity, &prefs);
|
|
||||||
if (!bwrite(out_buf, write))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (len == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
auto in = reinterpret_cast<const uint8_t *>(buf);
|
|
||||||
size_t read, write;
|
|
||||||
do {
|
|
||||||
read = len > BLOCK_SZ ? BLOCK_SZ : len;
|
|
||||||
write = LZ4F_compressUpdate(ctx, out_buf, outCapacity, in, read, nullptr);
|
|
||||||
if (LZ4F_isError(write)) {
|
|
||||||
LOGW("LZ4F encode error: %s\n", LZ4F_getErrorName(write));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
len -= read;
|
|
||||||
in += read;
|
|
||||||
if (!bwrite(out_buf, write))
|
|
||||||
return false;
|
|
||||||
} while (len != 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~LZ4F_encoder() override {
|
|
||||||
size_t len = LZ4F_compressEnd(ctx, out_buf, outCapacity, nullptr);
|
|
||||||
if (LZ4F_isError(len)) {
|
|
||||||
LOGE("LZ4F end of frame error: %s\n", LZ4F_getErrorName(len));
|
|
||||||
} else if (!bwrite(out_buf, len)) {
|
|
||||||
LOGE("LZ4F end of frame error: I/O error\n");
|
|
||||||
}
|
|
||||||
LZ4F_freeCompressionContext(ctx);
|
|
||||||
delete[] out_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
LZ4F_compressionContext_t ctx;
|
|
||||||
uint8_t *out_buf;
|
|
||||||
size_t outCapacity;
|
|
||||||
|
|
||||||
static constexpr size_t BLOCK_SZ = 1 << 22;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LZ4_decoder : public chunk_out_stream {
|
|
||||||
public:
|
|
||||||
explicit LZ4_decoder(out_strm_ptr &&base) :
|
|
||||||
chunk_out_stream(std::move(base), LZ4_COMPRESSED, sizeof(block_sz)),
|
|
||||||
out_buf(new char[LZ4_UNCOMPRESSED]), block_sz(0) {}
|
|
||||||
|
|
||||||
~LZ4_decoder() override {
|
|
||||||
finalize();
|
|
||||||
delete[] out_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool write_chunk(const void *buf, size_t len, bool) override {
|
|
||||||
// This is an error
|
|
||||||
if (len != chunk_sz)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto in = reinterpret_cast<const char *>(buf);
|
|
||||||
|
|
||||||
if (block_sz == 0) {
|
|
||||||
memcpy(&block_sz, in, sizeof(block_sz));
|
|
||||||
if (block_sz == 0x184C2102) {
|
|
||||||
// This is actually the lz4 magic, read the next 4 bytes
|
|
||||||
block_sz = 0;
|
|
||||||
chunk_sz = sizeof(block_sz);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Read the next block chunk
|
|
||||||
chunk_sz = block_sz;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
int r = LZ4_decompress_safe(in, out_buf, block_sz, LZ4_UNCOMPRESSED);
|
|
||||||
chunk_sz = sizeof(block_sz);
|
|
||||||
block_sz = 0;
|
|
||||||
if (r < 0) {
|
|
||||||
LOGW("LZ4HC decompression failure (%d)\n", r);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return bwrite(out_buf, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char *out_buf;
|
|
||||||
uint32_t block_sz;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LZ4_encoder : public chunk_out_stream {
|
|
||||||
public:
|
|
||||||
explicit LZ4_encoder(out_strm_ptr &&base, bool lg) :
|
|
||||||
chunk_out_stream(std::move(base), LZ4_UNCOMPRESSED),
|
|
||||||
out_buf(new char[LZ4_COMPRESSED]), lg(lg), in_total(0) {
|
|
||||||
bwrite("\x02\x21\x4c\x18", 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
~LZ4_encoder() override {
|
|
||||||
finalize();
|
|
||||||
if (lg)
|
|
||||||
bwrite(&in_total, sizeof(in_total));
|
|
||||||
delete[] out_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool write_chunk(const void *buf, size_t len, bool) override {
|
|
||||||
auto in = static_cast<const char *>(buf);
|
|
||||||
uint32_t block_sz = LZ4_compress_HC(in, out_buf, len, LZ4_COMPRESSED, LZ4HC_CLEVEL_MAX);
|
|
||||||
if (block_sz == 0) {
|
|
||||||
LOGW("LZ4HC compression failure\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (bwrite(&block_sz, sizeof(block_sz)) && bwrite(out_buf, block_sz)) {
|
|
||||||
in_total += len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char *out_buf;
|
|
||||||
bool lg;
|
|
||||||
uint32_t in_total;
|
|
||||||
};
|
|
||||||
|
|
||||||
out_strm_ptr get_encoder(format_t type, out_strm_ptr &&base) {
|
|
||||||
switch (type) {
|
|
||||||
case XZ:
|
|
||||||
return make_unique<xz_encoder>(std::move(base));
|
|
||||||
case LZMA:
|
|
||||||
return make_unique<lzma_encoder>(std::move(base));
|
|
||||||
case BZIP2:
|
|
||||||
return make_unique<bz_encoder>(std::move(base));
|
|
||||||
case LZ4:
|
|
||||||
return make_unique<LZ4F_encoder>(std::move(base));
|
|
||||||
case LZ4_LEGACY:
|
|
||||||
return make_unique<LZ4_encoder>(std::move(base), false);
|
|
||||||
case LZ4_LG:
|
|
||||||
return make_unique<LZ4_encoder>(std::move(base), true);
|
|
||||||
case ZOPFLI:
|
|
||||||
return make_unique<zopfli_encoder>(std::move(base));
|
|
||||||
case GZIP:
|
|
||||||
default:
|
|
||||||
return make_unique<gz_encoder>(std::move(base));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out_strm_ptr get_decoder(format_t type, out_strm_ptr &&base) {
|
|
||||||
switch (type) {
|
|
||||||
case XZ:
|
|
||||||
case LZMA:
|
|
||||||
return make_unique<lzma_decoder>(std::move(base));
|
|
||||||
case BZIP2:
|
|
||||||
return make_unique<bz_decoder>(std::move(base));
|
|
||||||
case LZ4:
|
|
||||||
return make_unique<LZ4F_decoder>(std::move(base));
|
|
||||||
case LZ4_LEGACY:
|
|
||||||
case LZ4_LG:
|
|
||||||
return make_unique<LZ4_decoder>(std::move(base));
|
|
||||||
case ZOPFLI:
|
|
||||||
case GZIP:
|
|
||||||
default:
|
|
||||||
return make_unique<gz_decoder>(std::move(base));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void decompress(char *infile, const char *outfile) {
|
|
||||||
bool in_std = infile == "-"sv;
|
|
||||||
bool rm_in = false;
|
|
||||||
|
|
||||||
int in_fd = in_std ? STDIN_FILENO : xopen(infile, O_RDONLY);
|
|
||||||
int out_fd = -1;
|
|
||||||
out_strm_ptr strm;
|
|
||||||
|
|
||||||
char buf[4096];
|
|
||||||
size_t len;
|
|
||||||
while ((len = read(in_fd, buf, sizeof(buf)))) {
|
|
||||||
if (!strm) {
|
|
||||||
format_t type = check_fmt(buf, len);
|
|
||||||
|
|
||||||
fprintf(stderr, "Detected format: [%s]\n", fmt2name[type]);
|
|
||||||
|
|
||||||
if (!COMPRESSED(type))
|
|
||||||
LOGE("Input file is not a supported compressed type!\n");
|
|
||||||
|
|
||||||
/* If user does not provide outfile, infile has to be either
|
|
||||||
* <path>.[ext], or '-'. Outfile will be either <path> or '-'.
|
|
||||||
* If the input does not have proper format, abort */
|
|
||||||
|
|
||||||
char *ext = nullptr;
|
|
||||||
if (outfile == nullptr) {
|
|
||||||
outfile = infile;
|
|
||||||
if (!in_std) {
|
|
||||||
ext = strrchr(infile, '.');
|
|
||||||
if (ext == nullptr || strcmp(ext, fmt2ext[type]) != 0)
|
|
||||||
LOGE("Input file is not a supported type!\n");
|
|
||||||
|
|
||||||
// Strip out extension and remove input
|
|
||||||
*ext = '\0';
|
|
||||||
rm_in = true;
|
|
||||||
fprintf(stderr, "Decompressing to [%s]\n", outfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out_fd = outfile == "-"sv ?
|
|
||||||
STDOUT_FILENO :
|
|
||||||
xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
||||||
strm = get_decoder(type, make_unique<fd_stream>(out_fd));
|
|
||||||
if (ext) *ext = '.';
|
|
||||||
}
|
|
||||||
if (!strm->write(buf, len))
|
|
||||||
LOGE("Decompression error!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
strm.reset(nullptr);
|
|
||||||
if (in_fd != STDIN_FILENO) close(in_fd);
|
|
||||||
if (out_fd != STDOUT_FILENO) close(out_fd);
|
|
||||||
|
|
||||||
if (rm_in)
|
|
||||||
unlink(infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compress(const char *method, const char *infile, const char *outfile) {
|
|
||||||
format_t fmt = name2fmt[method];
|
|
||||||
if (fmt == UNKNOWN)
|
|
||||||
LOGE("Unknown compression method: [%s]\n", method);
|
|
||||||
|
|
||||||
bool in_std = infile == "-"sv;
|
|
||||||
bool rm_in = false;
|
|
||||||
|
|
||||||
int in_fd = in_std ? STDIN_FILENO : xopen(infile, O_RDONLY);
|
|
||||||
int out_fd = -1;
|
|
||||||
|
|
||||||
if (outfile == nullptr) {
|
|
||||||
if (in_std) {
|
|
||||||
out_fd = STDOUT_FILENO;
|
|
||||||
} else {
|
|
||||||
/* If user does not provide outfile and infile is not
|
|
||||||
* STDIN, output to <infile>.[ext] */
|
|
||||||
string tmp(infile);
|
|
||||||
tmp += fmt2ext[fmt];
|
|
||||||
out_fd = xopen(tmp.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
||||||
fprintf(stderr, "Compressing to [%s]\n", tmp.data());
|
|
||||||
rm_in = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out_fd = outfile == "-"sv ?
|
|
||||||
STDOUT_FILENO :
|
|
||||||
xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto strm = get_encoder(fmt, make_unique<fd_stream>(out_fd));
|
|
||||||
|
|
||||||
char buf[4096];
|
|
||||||
size_t len;
|
|
||||||
while ((len = read(in_fd, buf, sizeof(buf)))) {
|
|
||||||
if (!strm->write(buf, len))
|
|
||||||
LOGE("Compression error!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
strm.reset(nullptr);
|
|
||||||
if (in_fd != STDIN_FILENO) close(in_fd);
|
|
||||||
if (out_fd != STDOUT_FILENO) close(out_fd);
|
|
||||||
|
|
||||||
if (rm_in)
|
|
||||||
unlink(infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool decompress(rust::Slice<const uint8_t> buf, int fd) {
|
|
||||||
format_t type = check_fmt(buf.data(), buf.length());
|
|
||||||
|
|
||||||
if (!COMPRESSED(type)) {
|
|
||||||
LOGE("Input file is not a supported compression format!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto strm = get_decoder(type, make_unique<fd_stream>(fd));
|
|
||||||
if (!strm->write(buf.data(), buf.length())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out) {
|
|
||||||
auto strm = get_encoder(XZ, make_unique<rust_vec_stream>(out));
|
|
||||||
if (!strm->write(buf.data(), buf.length())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out) {
|
|
||||||
format_t type = check_fmt(buf.data(), buf.length());
|
|
||||||
if (type != XZ) {
|
|
||||||
LOGE("Input file is not in xz format!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto strm = get_decoder(XZ, make_unique<rust_vec_stream>(out));
|
|
||||||
if (!strm->write(buf.data(), buf.length())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cxx.h>
|
|
||||||
#include <stream.hpp>
|
|
||||||
|
|
||||||
#include "format.hpp"
|
|
||||||
|
|
||||||
out_strm_ptr get_encoder(format_t type, out_strm_ptr &&base);
|
|
||||||
out_strm_ptr get_decoder(format_t type, out_strm_ptr &&base);
|
|
||||||
void compress(const char *method, const char *infile, const char *outfile);
|
|
||||||
void decompress(char *infile, const char *outfile);
|
|
||||||
bool decompress(rust::Slice<const uint8_t> buf, int fd);
|
|
||||||
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
|
|
||||||
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
|
|
||||||
426
native/src/boot/compress.rs
Normal file
426
native/src/boot/compress.rs
Normal file
@@ -0,0 +1,426 @@
|
|||||||
|
use crate::ffi::FileFormat;
|
||||||
|
use base::{Chunker, LoggedResult, WriteExt};
|
||||||
|
use bytemuck::bytes_of_mut;
|
||||||
|
use bzip2::{Compression as BzCompression, write::BzDecoder, write::BzEncoder};
|
||||||
|
use flate2::{Compression as GzCompression, write::GzEncoder, write::MultiGzDecoder};
|
||||||
|
use lz4::{
|
||||||
|
BlockMode, BlockSize, ContentChecksum, Encoder as LZ4FrameEncoder,
|
||||||
|
EncoderBuilder as LZ4FrameEncoderBuilder, block::CompressionMode, liblz4::BlockChecksum,
|
||||||
|
};
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Read, Write};
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::num::NonZeroU64;
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
use std::os::fd::{FromRawFd, RawFd};
|
||||||
|
use xz2::{
|
||||||
|
stream::{Check as LzmaCheck, Filters as LzmaFilters, LzmaOptions, Stream as LzmaStream},
|
||||||
|
write::{XzDecoder, XzEncoder},
|
||||||
|
};
|
||||||
|
use zopfli::{BlockType, GzipEncoder as ZopFliEncoder, Options as ZopfliOptions};
|
||||||
|
|
||||||
|
pub trait WriteFinish<W: Write>: Write {
|
||||||
|
fn finish(self: Box<Self>) -> std::io::Result<W>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boilerplate for existing types
|
||||||
|
|
||||||
|
macro_rules! finish_impl {
|
||||||
|
($($t:ty),*) => {$(
|
||||||
|
impl<W: Write> WriteFinish<W> for $t {
|
||||||
|
fn finish(self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
Self::finish(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_impl!(GzEncoder<W>, MultiGzDecoder<W>, BzEncoder<W>, XzEncoder<W>);
|
||||||
|
|
||||||
|
macro_rules! finish_impl_ref {
|
||||||
|
($($t:ty),*) => {$(
|
||||||
|
impl<W: Write> WriteFinish<W> for $t {
|
||||||
|
fn finish(mut self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
Self::finish(self.as_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_impl_ref!(BzDecoder<W>, XzDecoder<W>);
|
||||||
|
|
||||||
|
impl<W: Write> WriteFinish<W> for BufWriter<ZopFliEncoder<W>> {
|
||||||
|
fn finish(self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
let inner = self.into_inner()?;
|
||||||
|
ZopFliEncoder::finish(inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> WriteFinish<W> for LZ4FrameEncoder<W> {
|
||||||
|
fn finish(self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
let (w, r) = Self::finish(*self);
|
||||||
|
r?;
|
||||||
|
Ok(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapt Reader to Writer
|
||||||
|
|
||||||
|
// In case some decoders don't support the Write trait, instead of pushing data into the
|
||||||
|
// decoder, we have no choice but to pull data out of it. So first, we create a "fake" reader
|
||||||
|
// that does not own any data as a placeholder. In the Writer adapter struct, when data
|
||||||
|
// is fed in, we call FakeReader::set_data to forward this data as the "source" of the
|
||||||
|
// decoder. Next, we pull data out of the decoder, and finally, forward the decoded data to output.
|
||||||
|
|
||||||
|
struct FakeReader(Cell<&'static [u8]>);
|
||||||
|
|
||||||
|
impl FakeReader {
|
||||||
|
fn new() -> FakeReader {
|
||||||
|
FakeReader(Cell::new(&[]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: the lifetime of the buffer is between the invocation of
|
||||||
|
// this method and the invocation of FakeReader::clear. There is currently
|
||||||
|
// no way to represent this with Rust's lifetime marker, so we transmute all
|
||||||
|
// lifetimes away and make the users of this struct manually manage the lifetime.
|
||||||
|
// It is the responsibility of the caller to ensure the underlying reference does not
|
||||||
|
// live longer than it should.
|
||||||
|
unsafe fn set_data(&self, data: &[u8]) {
|
||||||
|
let buf: &'static [u8] = unsafe { std::mem::transmute(data) };
|
||||||
|
self.0.set(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&self) {
|
||||||
|
self.0.set(&[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for FakeReader {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
let data = self.0.get();
|
||||||
|
let len = std::cmp::min(buf.len(), data.len());
|
||||||
|
buf[..len].copy_from_slice(&data[..len]);
|
||||||
|
self.0.set(&data[len..]);
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LZ4FrameDecoder
|
||||||
|
|
||||||
|
struct LZ4FrameDecoder<W: Write> {
|
||||||
|
write: W,
|
||||||
|
decoder: lz4::Decoder<FakeReader>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> LZ4FrameDecoder<W> {
|
||||||
|
fn new(write: W) -> Self {
|
||||||
|
let fake = FakeReader::new();
|
||||||
|
let decoder = lz4::Decoder::new(fake).unwrap();
|
||||||
|
LZ4FrameDecoder { write, decoder }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> Write for LZ4FrameDecoder<W> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.write_all(buf)?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
|
||||||
|
// SAFETY: buf is removed from the reader immediately after usage
|
||||||
|
unsafe { self.decoder.reader().set_data(buf) };
|
||||||
|
std::io::copy(&mut self.decoder, &mut self.write)?;
|
||||||
|
self.decoder.reader().clear();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> WriteFinish<W> for LZ4FrameDecoder<W> {
|
||||||
|
fn finish(self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
let (_, r) = self.decoder.finish();
|
||||||
|
r?;
|
||||||
|
Ok(self.write)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LZ4BlockArchive format
|
||||||
|
//
|
||||||
|
// len: | 4 | 4 | n | ... | 4 |
|
||||||
|
// data: | magic | compressed block size | compressed block data | ... | total uncompressed size |
|
||||||
|
|
||||||
|
// LZ4BlockEncoder
|
||||||
|
|
||||||
|
const LZ4_BLOCK_SIZE: usize = 0x800000;
|
||||||
|
const LZ4HC_CLEVEL_MAX: i32 = 12;
|
||||||
|
const LZ4_MAGIC: &[u8] = b"\x02\x21\x4c\x18";
|
||||||
|
|
||||||
|
struct LZ4BlockEncoder<W: Write> {
|
||||||
|
write: W,
|
||||||
|
chunker: Chunker,
|
||||||
|
out_buf: Box<[u8]>,
|
||||||
|
total: u32,
|
||||||
|
is_lg: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> LZ4BlockEncoder<W> {
|
||||||
|
fn new(write: W, is_lg: bool) -> Self {
|
||||||
|
let out_sz = lz4::block::compress_bound(LZ4_BLOCK_SIZE).unwrap_or(LZ4_BLOCK_SIZE);
|
||||||
|
LZ4BlockEncoder {
|
||||||
|
write,
|
||||||
|
chunker: Chunker::new(LZ4_BLOCK_SIZE),
|
||||||
|
// SAFETY: all bytes will be initialized before it is used
|
||||||
|
out_buf: unsafe { Box::new_uninit_slice(out_sz).assume_init() },
|
||||||
|
total: 0,
|
||||||
|
is_lg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_block(write: &mut W, out_buf: &mut [u8], chunk: &[u8]) -> std::io::Result<()> {
|
||||||
|
let compressed_size = lz4::block::compress_to_buffer(
|
||||||
|
chunk,
|
||||||
|
Some(CompressionMode::HIGHCOMPRESSION(LZ4HC_CLEVEL_MAX)),
|
||||||
|
false,
|
||||||
|
out_buf,
|
||||||
|
)?;
|
||||||
|
let block_size = compressed_size as u32;
|
||||||
|
write.write_pod(&block_size)?;
|
||||||
|
write.write_all(&out_buf[..compressed_size])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> Write for LZ4BlockEncoder<W> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.write_all(buf)?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_all(&mut self, mut buf: &[u8]) -> std::io::Result<()> {
|
||||||
|
if self.total == 0 {
|
||||||
|
// Write header
|
||||||
|
self.write.write_all(LZ4_MAGIC)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.total += buf.len() as u32;
|
||||||
|
while !buf.is_empty() {
|
||||||
|
let (b, chunk) = self.chunker.add_data(buf);
|
||||||
|
buf = b;
|
||||||
|
if let Some(chunk) = chunk {
|
||||||
|
Self::encode_block(&mut self.write, &mut self.out_buf, chunk)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> WriteFinish<W> for LZ4BlockEncoder<W> {
|
||||||
|
fn finish(mut self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
let chunk = self.chunker.get_available();
|
||||||
|
if !chunk.is_empty() {
|
||||||
|
Self::encode_block(&mut self.write, &mut self.out_buf, chunk)?;
|
||||||
|
}
|
||||||
|
if self.is_lg {
|
||||||
|
self.write.write_pod(&self.total)?;
|
||||||
|
}
|
||||||
|
Ok(self.write)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LZ4BlockDecoder
|
||||||
|
|
||||||
|
struct LZ4BlockDecoder<W: Write> {
|
||||||
|
write: W,
|
||||||
|
chunker: Chunker,
|
||||||
|
out_buf: Box<[u8]>,
|
||||||
|
curr_block_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> LZ4BlockDecoder<W> {
|
||||||
|
fn new(write: W) -> Self {
|
||||||
|
LZ4BlockDecoder {
|
||||||
|
write,
|
||||||
|
chunker: Chunker::new(size_of::<u32>()),
|
||||||
|
// SAFETY: all bytes will be initialized before it is used
|
||||||
|
out_buf: unsafe { Box::new_uninit_slice(LZ4_BLOCK_SIZE).assume_init() },
|
||||||
|
curr_block_size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_block(write: &mut W, out_buf: &mut [u8], chunk: &[u8]) -> std::io::Result<()> {
|
||||||
|
let decompressed_size =
|
||||||
|
lz4::block::decompress_to_buffer(chunk, Some(LZ4_BLOCK_SIZE as i32), out_buf)?;
|
||||||
|
write.write_all(&out_buf[..decompressed_size])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> Write for LZ4BlockDecoder<W> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.write_all(buf)?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_all(&mut self, mut buf: &[u8]) -> std::io::Result<()> {
|
||||||
|
while !buf.is_empty() {
|
||||||
|
let (b, chunk) = self.chunker.add_data(buf);
|
||||||
|
buf = b;
|
||||||
|
if let Some(chunk) = chunk {
|
||||||
|
if chunk == LZ4_MAGIC {
|
||||||
|
// Skip magic, read next u32
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.curr_block_size == 0 {
|
||||||
|
// We haven't got the current block size yet, try read it
|
||||||
|
let mut next_u32: u32 = 0;
|
||||||
|
bytes_of_mut(&mut next_u32).copy_from_slice(chunk);
|
||||||
|
|
||||||
|
if next_u32 > lz4::block::compress_bound(LZ4_BLOCK_SIZE)? as u32 {
|
||||||
|
// This is the LG format trailer, EOF
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update chunker to read next block
|
||||||
|
self.curr_block_size = next_u32 as usize;
|
||||||
|
self.chunker.set_chunk_size(self.curr_block_size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually decode the block
|
||||||
|
Self::decode_block(&mut self.write, &mut self.out_buf, chunk)?;
|
||||||
|
|
||||||
|
// Reset for the next block
|
||||||
|
self.curr_block_size = 0;
|
||||||
|
self.chunker.set_chunk_size(size_of::<u32>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> WriteFinish<W> for LZ4BlockDecoder<W> {
|
||||||
|
fn finish(mut self: Box<Self>) -> std::io::Result<W> {
|
||||||
|
let chunk = self.chunker.get_available();
|
||||||
|
if !chunk.is_empty() {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Interrupted,
|
||||||
|
"Finish ran before end of compressed stream",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(self.write)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top-level APIs
|
||||||
|
|
||||||
|
pub fn get_encoder<'a, W: Write + 'a>(format: FileFormat, w: W) -> Box<dyn WriteFinish<W> + 'a> {
|
||||||
|
match format {
|
||||||
|
FileFormat::XZ => {
|
||||||
|
let opt = LzmaOptions::new_preset(9).unwrap();
|
||||||
|
let stream =
|
||||||
|
LzmaStream::new_stream_encoder(LzmaFilters::new().lzma2(&opt), LzmaCheck::Crc32)
|
||||||
|
.unwrap();
|
||||||
|
Box::new(XzEncoder::new_stream(w, stream))
|
||||||
|
}
|
||||||
|
FileFormat::LZMA => {
|
||||||
|
let opt = LzmaOptions::new_preset(9).unwrap();
|
||||||
|
let stream = LzmaStream::new_lzma_encoder(&opt).unwrap();
|
||||||
|
Box::new(XzEncoder::new_stream(w, stream))
|
||||||
|
}
|
||||||
|
FileFormat::BZIP2 => Box::new(BzEncoder::new(w, BzCompression::best())),
|
||||||
|
FileFormat::LZ4 => {
|
||||||
|
let encoder = LZ4FrameEncoderBuilder::new()
|
||||||
|
.block_size(BlockSize::Max4MB)
|
||||||
|
.block_mode(BlockMode::Independent)
|
||||||
|
.checksum(ContentChecksum::ChecksumEnabled)
|
||||||
|
.block_checksum(BlockChecksum::BlockChecksumEnabled)
|
||||||
|
.level(9)
|
||||||
|
.auto_flush(true)
|
||||||
|
.build(w)
|
||||||
|
.unwrap();
|
||||||
|
Box::new(encoder)
|
||||||
|
}
|
||||||
|
FileFormat::LZ4_LEGACY => Box::new(LZ4BlockEncoder::new(w, false)),
|
||||||
|
FileFormat::LZ4_LG => Box::new(LZ4BlockEncoder::new(w, true)),
|
||||||
|
FileFormat::ZOPFLI => {
|
||||||
|
// These options are already better than gzip -9
|
||||||
|
let opt = ZopfliOptions {
|
||||||
|
iteration_count: NonZeroU64::new(1).unwrap(),
|
||||||
|
maximum_block_splits: 1,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
Box::new(ZopFliEncoder::new_buffered(opt, BlockType::Dynamic, w).unwrap())
|
||||||
|
}
|
||||||
|
FileFormat::GZIP => Box::new(GzEncoder::new(w, GzCompression::best())),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_decoder<'a, W: Write + 'a>(format: FileFormat, w: W) -> Box<dyn WriteFinish<W> + 'a> {
|
||||||
|
match format {
|
||||||
|
FileFormat::XZ | FileFormat::LZMA => {
|
||||||
|
let stream = LzmaStream::new_auto_decoder(u64::MAX, 0).unwrap();
|
||||||
|
Box::new(XzDecoder::new_stream(w, stream))
|
||||||
|
}
|
||||||
|
FileFormat::BZIP2 => Box::new(BzDecoder::new(w)),
|
||||||
|
FileFormat::LZ4 => Box::new(LZ4FrameDecoder::new(w)),
|
||||||
|
FileFormat::LZ4_LG | FileFormat::LZ4_LEGACY => Box::new(LZ4BlockDecoder::new(w)),
|
||||||
|
FileFormat::ZOPFLI | FileFormat::GZIP => Box::new(MultiGzDecoder::new(w)),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// C++ FFI
|
||||||
|
|
||||||
|
pub fn compress_fd(format: FileFormat, in_fd: RawFd, out_fd: RawFd) {
|
||||||
|
let mut in_file = unsafe { ManuallyDrop::new(File::from_raw_fd(in_fd)) };
|
||||||
|
let mut out_file = unsafe { ManuallyDrop::new(File::from_raw_fd(out_fd)) };
|
||||||
|
|
||||||
|
let mut encoder = get_encoder(format, out_file.deref_mut());
|
||||||
|
let _: LoggedResult<()> = try {
|
||||||
|
std::io::copy(in_file.deref_mut(), encoder.as_mut())?;
|
||||||
|
encoder.finish()?;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decompress_bytes_fd(format: FileFormat, in_bytes: &[u8], in_fd: RawFd, out_fd: RawFd) {
|
||||||
|
let mut in_file = unsafe { ManuallyDrop::new(File::from_raw_fd(in_fd)) };
|
||||||
|
let mut out_file = unsafe { ManuallyDrop::new(File::from_raw_fd(out_fd)) };
|
||||||
|
|
||||||
|
let mut decoder = get_decoder(format, out_file.deref_mut());
|
||||||
|
let _: LoggedResult<()> = try {
|
||||||
|
decoder.write_all(in_bytes)?;
|
||||||
|
std::io::copy(in_file.deref_mut(), decoder.as_mut())?;
|
||||||
|
decoder.finish()?;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: RawFd) {
|
||||||
|
let mut out_file = unsafe { ManuallyDrop::new(File::from_raw_fd(out_fd)) };
|
||||||
|
|
||||||
|
let mut encoder = get_encoder(format, out_file.deref_mut());
|
||||||
|
let _: LoggedResult<()> = try {
|
||||||
|
encoder.write_all(in_bytes)?;
|
||||||
|
encoder.finish()?;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decompress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: RawFd) {
|
||||||
|
let mut out_file = unsafe { ManuallyDrop::new(File::from_raw_fd(out_fd)) };
|
||||||
|
|
||||||
|
let mut decoder = get_decoder(format, out_file.deref_mut());
|
||||||
|
let _: LoggedResult<()> = try {
|
||||||
|
decoder.write_all(in_bytes)?;
|
||||||
|
decoder.finish()?;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ use base::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::check_env;
|
use crate::check_env;
|
||||||
use crate::ffi::{unxz, xz};
|
use crate::compress::{get_decoder, get_encoder};
|
||||||
|
use crate::ffi::FileFormat;
|
||||||
use crate::patch::{patch_encryption, patch_verity};
|
use crate::patch::{patch_encryption, patch_verity};
|
||||||
|
|
||||||
#[derive(FromArgs)]
|
#[derive(FromArgs)]
|
||||||
@@ -268,13 +269,13 @@ impl Cpio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_from_file(path: &Utf8CStr) -> LoggedResult<Self> {
|
fn load_from_file(path: &Utf8CStr) -> LoggedResult<Self> {
|
||||||
eprintln!("Loading cpio: [{}]", path);
|
eprintln!("Loading cpio: [{path}]");
|
||||||
let file = MappedFile::open(path)?;
|
let file = MappedFile::open(path)?;
|
||||||
Self::load_from_data(file.as_ref())
|
Self::load_from_data(file.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump(&self, path: &str) -> LoggedResult<()> {
|
fn dump(&self, path: &str) -> LoggedResult<()> {
|
||||||
eprintln!("Dumping cpio: [{}]", path);
|
eprintln!("Dumping cpio: [{path}]");
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path)?;
|
||||||
let mut pos = 0usize;
|
let mut pos = 0usize;
|
||||||
let mut inode = 300000i64;
|
let mut inode = 300000i64;
|
||||||
@@ -308,7 +309,7 @@ impl Cpio {
|
|||||||
}
|
}
|
||||||
pos += file.write(
|
pos += file.write(
|
||||||
format!("070701{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}",
|
format!("070701{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}{:08x}",
|
||||||
inode, 0o755, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0
|
inode, 0o755, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0
|
||||||
).as_bytes()
|
).as_bytes()
|
||||||
)?;
|
)?;
|
||||||
pos += file.write("TRAILER!!!\0".as_bytes())?;
|
pos += file.write("TRAILER!!!\0".as_bytes())?;
|
||||||
@@ -319,13 +320,13 @@ impl Cpio {
|
|||||||
fn rm(&mut self, path: &str, recursive: bool) {
|
fn rm(&mut self, path: &str, recursive: bool) {
|
||||||
let path = norm_path(path);
|
let path = norm_path(path);
|
||||||
if self.entries.remove(&path).is_some() {
|
if self.entries.remove(&path).is_some() {
|
||||||
eprintln!("Removed entry [{}]", path);
|
eprintln!("Removed entry [{path}]");
|
||||||
}
|
}
|
||||||
if recursive {
|
if recursive {
|
||||||
let path = path + "/";
|
let path = path + "/";
|
||||||
self.entries.retain(|k, _| {
|
self.entries.retain(|k, _| {
|
||||||
if k.starts_with(&path) {
|
if k.starts_with(&path) {
|
||||||
eprintln!("Removed entry [{}]", k);
|
eprintln!("Removed entry [{k}]");
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
@@ -339,7 +340,7 @@ impl Cpio {
|
|||||||
.entries
|
.entries
|
||||||
.get(path)
|
.get(path)
|
||||||
.ok_or_else(|| log_err!("No such file"))?;
|
.ok_or_else(|| log_err!("No such file"))?;
|
||||||
eprintln!("Extracting entry [{}] to [{}]", path, out);
|
eprintln!("Extracting entry [{path}] to [{out}]");
|
||||||
|
|
||||||
let out = Utf8CStr::from_string(out);
|
let out = Utf8CStr::from_string(out);
|
||||||
|
|
||||||
@@ -434,7 +435,7 @@ impl Cpio {
|
|||||||
data: content,
|
data: content,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
eprintln!("Add file [{}] ({:04o})", path, mode);
|
eprintln!("Add file [{path}] ({mode:04o})");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +451,7 @@ impl Cpio {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
eprintln!("Create directory [{}] ({:04o})", dir, mode);
|
eprintln!("Create directory [{dir}] ({mode:04o})");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ln(&mut self, src: &str, dst: &str) {
|
fn ln(&mut self, src: &str, dst: &str) {
|
||||||
@@ -465,7 +466,7 @@ impl Cpio {
|
|||||||
data: norm_path(src).as_bytes().to_vec(),
|
data: norm_path(src).as_bytes().to_vec(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
eprintln!("Create symlink [{}] -> [{}]", dst, src);
|
eprintln!("Create symlink [{dst}] -> [{src}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mv(&mut self, from: &str, to: &str) -> LoggedResult<()> {
|
fn mv(&mut self, from: &str, to: &str) -> LoggedResult<()> {
|
||||||
@@ -474,7 +475,7 @@ impl Cpio {
|
|||||||
.remove(&norm_path(from))
|
.remove(&norm_path(from))
|
||||||
.ok_or_else(|| log_err!("no such entry {}", from))?;
|
.ok_or_else(|| log_err!("no such entry {}", from))?;
|
||||||
self.entries.insert(norm_path(to), entry);
|
self.entries.insert(norm_path(to), entry);
|
||||||
eprintln!("Move [{}] -> [{}]", from, to);
|
eprintln!("Move [{from}] -> [{to}]");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,7 +498,7 @@ impl Cpio {
|
|||||||
if !recursive && !p.is_empty() && p.matches('/').count() > 1 {
|
if !recursive && !p.is_empty() && p.matches('/').count() > 1 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
println!("{}\t{}", entry, name);
|
println!("{entry}\t{name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,8 +511,7 @@ impl Cpio {
|
|||||||
let keep_verity = check_env("KEEPVERITY");
|
let keep_verity = check_env("KEEPVERITY");
|
||||||
let keep_force_encrypt = check_env("KEEPFORCEENCRYPT");
|
let keep_force_encrypt = check_env("KEEPFORCEENCRYPT");
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Patch with flag KEEPVERITY=[{}] KEEPFORCEENCRYPT=[{}]",
|
"Patch with flag KEEPVERITY=[{keep_verity}] KEEPFORCEENCRYPT=[{keep_force_encrypt}]"
|
||||||
keep_verity, keep_force_encrypt
|
|
||||||
);
|
);
|
||||||
self.entries.retain(|name, entry| {
|
self.entries.retain(|name, entry| {
|
||||||
let fstab = (!keep_verity || !keep_force_encrypt)
|
let fstab = (!keep_verity || !keep_force_encrypt)
|
||||||
@@ -522,7 +522,7 @@ impl Cpio {
|
|||||||
&& name.starts_with("fstab");
|
&& name.starts_with("fstab");
|
||||||
if !keep_verity {
|
if !keep_verity {
|
||||||
if fstab {
|
if fstab {
|
||||||
eprintln!("Found fstab file [{}]", name);
|
eprintln!("Found fstab file [{name}]");
|
||||||
let len = patch_verity(entry.data.as_mut_slice());
|
let len = patch_verity(entry.data.as_mut_slice());
|
||||||
if len != entry.data.len() {
|
if len != entry.data.len() {
|
||||||
entry.data.resize(len, 0);
|
entry.data.resize(len, 0);
|
||||||
@@ -580,7 +580,7 @@ impl Cpio {
|
|||||||
} else {
|
} else {
|
||||||
&name[8..]
|
&name[8..]
|
||||||
};
|
};
|
||||||
eprintln!("Restore [{}] -> [{}]", name, new_name);
|
eprintln!("Restore [{name}] -> [{new_name}]");
|
||||||
backups.insert(new_name.to_string(), entry);
|
backups.insert(new_name.to_string(), entry);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -657,16 +657,16 @@ impl Cpio {
|
|||||||
match action {
|
match action {
|
||||||
Action::Backup(name, mut entry) => {
|
Action::Backup(name, mut entry) => {
|
||||||
let backup = if !skip_compress && entry.compress() {
|
let backup = if !skip_compress && entry.compress() {
|
||||||
format!(".backup/{}.xz", name)
|
format!(".backup/{name}.xz")
|
||||||
} else {
|
} else {
|
||||||
format!(".backup/{}", name)
|
format!(".backup/{name}")
|
||||||
};
|
};
|
||||||
eprintln!("Backup [{}] -> [{}]", name, backup);
|
eprintln!("Backup [{name}] -> [{backup}]");
|
||||||
backups.insert(backup, entry);
|
backups.insert(backup, entry);
|
||||||
}
|
}
|
||||||
Action::Record(name) => {
|
Action::Record(name) => {
|
||||||
eprintln!("Record new entry: [{}] -> [.backup/.rmlist]", name);
|
eprintln!("Record new entry: [{name}] -> [.backup/.rmlist]");
|
||||||
rm_list.push_str(&format!("{}\0", name));
|
rm_list.push_str(&format!("{name}\0"));
|
||||||
}
|
}
|
||||||
Action::Noop => {}
|
Action::Noop => {}
|
||||||
}
|
}
|
||||||
@@ -695,12 +695,16 @@ impl CpioEntry {
|
|||||||
if self.mode & S_IFMT != S_IFREG {
|
if self.mode & S_IFMT != S_IFREG {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let mut compressed = Vec::new();
|
let mut encoder = get_encoder(FileFormat::XZ, Vec::new());
|
||||||
if !xz(&self.data, &mut compressed) {
|
let Ok(data): std::io::Result<Vec<u8>> = (try {
|
||||||
|
encoder.write_all(&self.data)?;
|
||||||
|
encoder.finish()?
|
||||||
|
}) else {
|
||||||
eprintln!("xz compression failed");
|
eprintln!("xz compression failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
self.data = compressed;
|
|
||||||
|
self.data = data;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,12 +712,17 @@ impl CpioEntry {
|
|||||||
if self.mode & S_IFMT != S_IFREG {
|
if self.mode & S_IFMT != S_IFREG {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let mut decompressed = Vec::new();
|
|
||||||
if !unxz(&self.data, &mut decompressed) {
|
let mut decoder = get_decoder(FileFormat::XZ, Vec::new());
|
||||||
eprintln!("xz decompression failed");
|
let Ok(data): std::io::Result<Vec<u8>> = (try {
|
||||||
|
decoder.write_all(&self.data)?;
|
||||||
|
decoder.finish()?
|
||||||
|
}) else {
|
||||||
|
eprintln!("xz compression failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
self.data = decompressed;
|
|
||||||
|
self.data = data;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,9 +131,9 @@ fn print_node(node: &FdtNode) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else if size > MAX_PRINT_LEN {
|
} else if size > MAX_PRINT_LEN {
|
||||||
println!("[{}]: <bytes>({})", name, size);
|
println!("[{name}]: <bytes>({size})");
|
||||||
} else {
|
} else {
|
||||||
println!("[{}]: {:02x?}", name, value);
|
println!("[{name}]: {value:02x?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ fn for_each_fdt<F: FnMut(usize, Fdt) -> LoggedResult<()>>(
|
|||||||
rw: bool,
|
rw: bool,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
) -> LoggedResult<()> {
|
) -> LoggedResult<()> {
|
||||||
eprintln!("Loading dtbs from [{}]", file);
|
eprintln!("Loading dtbs from [{file}]");
|
||||||
let file = if rw {
|
let file = if rw {
|
||||||
MappedFile::open_rw(file)?
|
MappedFile::open_rw(file)?
|
||||||
} else {
|
} else {
|
||||||
@@ -173,7 +173,7 @@ fn for_each_fdt<F: FnMut(usize, Fdt) -> LoggedResult<()>>(
|
|||||||
}
|
}
|
||||||
let fdt = match Fdt::new(slice) {
|
let fdt = match Fdt::new(slice) {
|
||||||
Err(FdtError::BufferTooSmall) => {
|
Err(FdtError::BufferTooSmall) => {
|
||||||
eprintln!("dtb.{:04} is truncated", dtb_num);
|
eprintln!("dtb.{dtb_num:04} is truncated");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(fdt) => fdt,
|
Ok(fdt) => fdt,
|
||||||
@@ -198,11 +198,11 @@ fn dtb_print(file: &Utf8CStr, fstab: bool) -> LoggedResult<()> {
|
|||||||
for_each_fdt(file, false, |n, fdt| {
|
for_each_fdt(file, false, |n, fdt| {
|
||||||
if fstab {
|
if fstab {
|
||||||
if let Some(fstab) = find_fstab(&fdt) {
|
if let Some(fstab) = find_fstab(&fdt) {
|
||||||
eprintln!("Found fstab in dtb.{:04}", n);
|
eprintln!("Found fstab in dtb.{n:04}");
|
||||||
print_node(&fstab);
|
print_node(&fstab);
|
||||||
}
|
}
|
||||||
} else if let Some(mut root) = fdt.find_node("/") {
|
} else if let Some(mut root) = fdt.find_node("/") {
|
||||||
eprintln!("Printing dtb.{:04}", n);
|
eprintln!("Printing dtb.{n:04}");
|
||||||
if root.name.is_empty() {
|
if root.name.is_empty() {
|
||||||
root.name = "/";
|
root.name = "/";
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ fn dtb_patch(file: &Utf8CStr) -> LoggedResult<bool> {
|
|||||||
&mut *std::mem::transmute::<&[u8], &UnsafeCell<[u8]>>(w).get()
|
&mut *std::mem::transmute::<&[u8], &UnsafeCell<[u8]>>(w).get()
|
||||||
};
|
};
|
||||||
w[..=4].copy_from_slice(b"want");
|
w[..=4].copy_from_slice(b"want");
|
||||||
eprintln!("Patch [skip_initramfs] -> [want_initramfs] in dtb.{:04}", n);
|
eprintln!("Patch [skip_initramfs] -> [want_initramfs] in dtb.{n:04}");
|
||||||
patched = true;
|
patched = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "boot-rs.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
|
|
||||||
Name2Fmt name2fmt;
|
Name2Fmt name2fmt;
|
||||||
@@ -6,88 +7,88 @@ Fmt2Ext fmt2ext;
|
|||||||
|
|
||||||
#define CHECKED_MATCH(s) (len >= (sizeof(s) - 1) && BUFFER_MATCH(buf, s))
|
#define CHECKED_MATCH(s) (len >= (sizeof(s) - 1) && BUFFER_MATCH(buf, s))
|
||||||
|
|
||||||
format_t check_fmt(const void *buf, size_t len) {
|
FileFormat check_fmt(const void *buf, size_t len) {
|
||||||
if (CHECKED_MATCH(CHROMEOS_MAGIC)) {
|
if (CHECKED_MATCH(CHROMEOS_MAGIC)) {
|
||||||
return CHROMEOS;
|
return FileFormat::CHROMEOS;
|
||||||
} else if (CHECKED_MATCH(BOOT_MAGIC)) {
|
} else if (CHECKED_MATCH(BOOT_MAGIC)) {
|
||||||
return AOSP;
|
return FileFormat::AOSP;
|
||||||
} else if (CHECKED_MATCH(VENDOR_BOOT_MAGIC)) {
|
} else if (CHECKED_MATCH(VENDOR_BOOT_MAGIC)) {
|
||||||
return AOSP_VENDOR;
|
return FileFormat::AOSP_VENDOR;
|
||||||
} else if (CHECKED_MATCH(GZIP1_MAGIC) || CHECKED_MATCH(GZIP2_MAGIC)) {
|
} else if (CHECKED_MATCH(GZIP1_MAGIC) || CHECKED_MATCH(GZIP2_MAGIC)) {
|
||||||
return GZIP;
|
return FileFormat::GZIP;
|
||||||
} else if (CHECKED_MATCH(LZOP_MAGIC)) {
|
} else if (CHECKED_MATCH(LZOP_MAGIC)) {
|
||||||
return LZOP;
|
return FileFormat::LZOP;
|
||||||
} else if (CHECKED_MATCH(XZ_MAGIC)) {
|
} else if (CHECKED_MATCH(XZ_MAGIC)) {
|
||||||
return XZ;
|
return FileFormat::XZ;
|
||||||
} else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0
|
} else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0
|
||||||
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
|
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
|
||||||
return LZMA;
|
return FileFormat::LZMA;
|
||||||
} else if (CHECKED_MATCH(BZIP_MAGIC)) {
|
} else if (CHECKED_MATCH(BZIP_MAGIC)) {
|
||||||
return BZIP2;
|
return FileFormat::BZIP2;
|
||||||
} else if (CHECKED_MATCH(LZ41_MAGIC) || CHECKED_MATCH(LZ42_MAGIC)) {
|
} else if (CHECKED_MATCH(LZ41_MAGIC) || CHECKED_MATCH(LZ42_MAGIC)) {
|
||||||
return LZ4;
|
return FileFormat::LZ4;
|
||||||
} else if (CHECKED_MATCH(LZ4_LEG_MAGIC)) {
|
} else if (CHECKED_MATCH(LZ4_LEG_MAGIC)) {
|
||||||
return LZ4_LEGACY;
|
return FileFormat::LZ4_LEGACY;
|
||||||
} else if (CHECKED_MATCH(MTK_MAGIC)) {
|
} else if (CHECKED_MATCH(MTK_MAGIC)) {
|
||||||
return MTK;
|
return FileFormat::MTK;
|
||||||
} else if (CHECKED_MATCH(DTB_MAGIC)) {
|
} else if (CHECKED_MATCH(DTB_MAGIC)) {
|
||||||
return DTB;
|
return FileFormat::DTB;
|
||||||
} else if (CHECKED_MATCH(DHTB_MAGIC)) {
|
} else if (CHECKED_MATCH(DHTB_MAGIC)) {
|
||||||
return DHTB;
|
return FileFormat::DHTB;
|
||||||
} else if (CHECKED_MATCH(TEGRABLOB_MAGIC)) {
|
} else if (CHECKED_MATCH(TEGRABLOB_MAGIC)) {
|
||||||
return BLOB;
|
return FileFormat::BLOB;
|
||||||
} else if (len >= 0x28 && memcmp(&((char *)buf)[0x24], ZIMAGE_MAGIC, 4) == 0) {
|
} else if (len >= 0x28 && memcmp(&((char *)buf)[0x24], ZIMAGE_MAGIC, 4) == 0) {
|
||||||
return ZIMAGE;
|
return FileFormat::ZIMAGE;
|
||||||
} else {
|
} else {
|
||||||
return UNKNOWN;
|
return FileFormat::UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Fmt2Name::operator[](format_t fmt) {
|
const char *Fmt2Name::operator[](FileFormat fmt) {
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case GZIP:
|
case FileFormat::GZIP:
|
||||||
return "gzip";
|
return "gzip";
|
||||||
case ZOPFLI:
|
case FileFormat::ZOPFLI:
|
||||||
return "zopfli";
|
return "zopfli";
|
||||||
case LZOP:
|
case FileFormat::LZOP:
|
||||||
return "lzop";
|
return "lzop";
|
||||||
case XZ:
|
case FileFormat::XZ:
|
||||||
return "xz";
|
return "xz";
|
||||||
case LZMA:
|
case FileFormat::LZMA:
|
||||||
return "lzma";
|
return "lzma";
|
||||||
case BZIP2:
|
case FileFormat::BZIP2:
|
||||||
return "bzip2";
|
return "bzip2";
|
||||||
case LZ4:
|
case FileFormat::LZ4:
|
||||||
return "lz4";
|
return "lz4";
|
||||||
case LZ4_LEGACY:
|
case FileFormat::LZ4_LEGACY:
|
||||||
return "lz4_legacy";
|
return "lz4_legacy";
|
||||||
case LZ4_LG:
|
case FileFormat::LZ4_LG:
|
||||||
return "lz4_lg";
|
return "lz4_lg";
|
||||||
case DTB:
|
case FileFormat::DTB:
|
||||||
return "dtb";
|
return "dtb";
|
||||||
case ZIMAGE:
|
case FileFormat::ZIMAGE:
|
||||||
return "zimage";
|
return "zimage";
|
||||||
default:
|
default:
|
||||||
return "raw";
|
return "raw";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Fmt2Ext::operator[](format_t fmt) {
|
const char *Fmt2Ext::operator[](FileFormat fmt) {
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case GZIP:
|
case FileFormat::GZIP:
|
||||||
case ZOPFLI:
|
case FileFormat::ZOPFLI:
|
||||||
return ".gz";
|
return ".gz";
|
||||||
case LZOP:
|
case FileFormat::LZOP:
|
||||||
return ".lzo";
|
return ".lzo";
|
||||||
case XZ:
|
case FileFormat::XZ:
|
||||||
return ".xz";
|
return ".xz";
|
||||||
case LZMA:
|
case FileFormat::LZMA:
|
||||||
return ".lzma";
|
return ".lzma";
|
||||||
case BZIP2:
|
case FileFormat::BZIP2:
|
||||||
return ".bz2";
|
return ".bz2";
|
||||||
case LZ4:
|
case FileFormat::LZ4:
|
||||||
case LZ4_LEGACY:
|
case FileFormat::LZ4_LEGACY:
|
||||||
case LZ4_LG:
|
case FileFormat::LZ4_LG:
|
||||||
return ".lz4";
|
return ".lz4";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
@@ -96,15 +97,15 @@ const char *Fmt2Ext::operator[](format_t fmt) {
|
|||||||
|
|
||||||
#define CHECK(s, f) else if (name == s) return f;
|
#define CHECK(s, f) else if (name == s) return f;
|
||||||
|
|
||||||
format_t Name2Fmt::operator[](std::string_view name) {
|
FileFormat Name2Fmt::operator[](std::string_view name) {
|
||||||
if (0) {}
|
if (0) {}
|
||||||
CHECK("gzip", GZIP)
|
CHECK("gzip", FileFormat::GZIP)
|
||||||
CHECK("zopfli", ZOPFLI)
|
CHECK("zopfli", FileFormat::ZOPFLI)
|
||||||
CHECK("xz", XZ)
|
CHECK("xz", FileFormat::XZ)
|
||||||
CHECK("lzma", LZMA)
|
CHECK("lzma", FileFormat::LZMA)
|
||||||
CHECK("bzip2", BZIP2)
|
CHECK("bzip2", FileFormat::BZIP2)
|
||||||
CHECK("lz4", LZ4)
|
CHECK("lz4", FileFormat::LZ4)
|
||||||
CHECK("lz4_legacy", LZ4_LEGACY)
|
CHECK("lz4_legacy", FileFormat::LZ4_LEGACY)
|
||||||
CHECK("lz4_lg", LZ4_LG)
|
CHECK("lz4_lg", FileFormat::LZ4_LG)
|
||||||
else return UNKNOWN;
|
else return FileFormat::UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,33 +2,10 @@
|
|||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
typedef enum {
|
enum class FileFormat : ::std::uint8_t;
|
||||||
UNKNOWN,
|
|
||||||
/* Boot formats */
|
|
||||||
CHROMEOS,
|
|
||||||
AOSP,
|
|
||||||
AOSP_VENDOR,
|
|
||||||
DHTB,
|
|
||||||
BLOB,
|
|
||||||
/* Compression formats */
|
|
||||||
GZIP,
|
|
||||||
ZOPFLI,
|
|
||||||
XZ,
|
|
||||||
LZMA,
|
|
||||||
BZIP2,
|
|
||||||
LZ4,
|
|
||||||
LZ4_LEGACY,
|
|
||||||
LZ4_LG,
|
|
||||||
/* Unsupported compression */
|
|
||||||
LZOP,
|
|
||||||
/* Misc */
|
|
||||||
MTK,
|
|
||||||
DTB,
|
|
||||||
ZIMAGE,
|
|
||||||
} format_t;
|
|
||||||
|
|
||||||
#define COMPRESSED(fmt) ((fmt) >= GZIP && (fmt) < LZOP)
|
#define COMPRESSED(fmt) ((+fmt) >= +FileFormat::GZIP && (+fmt) < +FileFormat::LZOP)
|
||||||
#define COMPRESSED_ANY(fmt) ((fmt) >= GZIP && (fmt) <= LZOP)
|
#define COMPRESSED_ANY(fmt) ((+fmt) >= +FileFormat::GZIP && (+fmt) <= +FileFormat::LZOP)
|
||||||
|
|
||||||
#define BUFFER_MATCH(buf, s) (memcmp(buf, s, sizeof(s) - 1) == 0)
|
#define BUFFER_MATCH(buf, s) (memcmp(buf, s, sizeof(s) - 1) == 0)
|
||||||
#define BUFFER_CONTAIN(buf, sz, s) (memmem(buf, sz, s, sizeof(s) - 1) != nullptr)
|
#define BUFFER_CONTAIN(buf, sz, s) (memmem(buf, sz, s, sizeof(s) - 1) != nullptr)
|
||||||
@@ -66,20 +43,24 @@ typedef enum {
|
|||||||
|
|
||||||
class Fmt2Name {
|
class Fmt2Name {
|
||||||
public:
|
public:
|
||||||
const char *operator[](format_t fmt);
|
const char *operator[](FileFormat fmt);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Fmt2Ext {
|
class Fmt2Ext {
|
||||||
public:
|
public:
|
||||||
const char *operator[](format_t fmt);
|
const char *operator[](FileFormat fmt);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Name2Fmt {
|
class Name2Fmt {
|
||||||
public:
|
public:
|
||||||
format_t operator[](std::string_view name);
|
FileFormat operator[](std::string_view name);
|
||||||
};
|
};
|
||||||
|
|
||||||
format_t check_fmt(const void *buf, size_t len);
|
FileFormat check_fmt(const void *buf, size_t len);
|
||||||
|
|
||||||
|
static inline FileFormat check_fmt(rust::Slice<const uint8_t> bytes) {
|
||||||
|
return check_fmt(bytes.data(), bytes.size());
|
||||||
|
}
|
||||||
|
|
||||||
extern Name2Fmt name2fmt;
|
extern Name2Fmt name2fmt;
|
||||||
extern Fmt2Name fmt2name;
|
extern Fmt2Name fmt2name;
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
|
|
||||||
pub use base;
|
pub use base;
|
||||||
|
use compress::{compress_bytes, compress_fd, decompress_bytes, decompress_bytes_fd};
|
||||||
use cpio::cpio_commands;
|
use cpio::cpio_commands;
|
||||||
use dtb::dtb_commands;
|
use dtb::dtb_commands;
|
||||||
pub use libbz2_rs_sys::*;
|
|
||||||
pub use libz_rs_sys::*;
|
|
||||||
use patch::hexpatch;
|
use patch::hexpatch;
|
||||||
use payload::extract_boot_from_payload;
|
use payload::extract_boot_from_payload;
|
||||||
use sign::{SHA, get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image};
|
use sign::{SHA, get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
|
mod compress;
|
||||||
mod cpio;
|
mod cpio;
|
||||||
mod dtb;
|
mod dtb;
|
||||||
mod patch;
|
mod patch;
|
||||||
@@ -24,6 +24,31 @@ mod sign;
|
|||||||
|
|
||||||
#[cxx::bridge]
|
#[cxx::bridge]
|
||||||
pub mod ffi {
|
pub mod ffi {
|
||||||
|
enum FileFormat {
|
||||||
|
UNKNOWN,
|
||||||
|
/* Boot formats */
|
||||||
|
CHROMEOS,
|
||||||
|
AOSP,
|
||||||
|
AOSP_VENDOR,
|
||||||
|
DHTB,
|
||||||
|
BLOB,
|
||||||
|
/* Compression formats */
|
||||||
|
GZIP,
|
||||||
|
ZOPFLI,
|
||||||
|
XZ,
|
||||||
|
LZMA,
|
||||||
|
BZIP2,
|
||||||
|
LZ4,
|
||||||
|
LZ4_LEGACY,
|
||||||
|
LZ4_LG,
|
||||||
|
/* Unsupported compression */
|
||||||
|
LZOP,
|
||||||
|
/* Misc */
|
||||||
|
MTK,
|
||||||
|
DTB,
|
||||||
|
ZIMAGE,
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
include!("../base/include/base.hpp");
|
include!("../base/include/base.hpp");
|
||||||
|
|
||||||
@@ -33,10 +58,8 @@ pub mod ffi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
include!("compress.hpp");
|
include!("format.hpp");
|
||||||
fn decompress(buf: &[u8], fd: i32) -> bool;
|
fn check_fmt(buf: &[u8]) -> FileFormat;
|
||||||
fn xz(buf: &[u8], out: &mut Vec<u8>) -> bool;
|
|
||||||
fn unxz(buf: &[u8], out: &mut Vec<u8>) -> bool;
|
|
||||||
|
|
||||||
include!("bootimg.hpp");
|
include!("bootimg.hpp");
|
||||||
#[cxx_name = "boot_img"]
|
#[cxx_name = "boot_img"]
|
||||||
@@ -57,6 +80,10 @@ pub mod ffi {
|
|||||||
fn sha256_hash(data: &[u8], out: &mut [u8]);
|
fn sha256_hash(data: &[u8], out: &mut [u8]);
|
||||||
|
|
||||||
fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool;
|
fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool;
|
||||||
|
fn compress_fd(format: FileFormat, in_fd: i32, out_fd: i32);
|
||||||
|
fn compress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: i32);
|
||||||
|
fn decompress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: i32);
|
||||||
|
fn decompress_bytes_fd(format: FileFormat, in_bytes: &[u8], in_fd: i32, out_fd: i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[namespace = "rust"]
|
#[namespace = "rust"]
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
|
|
||||||
#define HEADER_FILE "header"
|
#define HEADER_FILE "header"
|
||||||
#define KERNEL_FILE "kernel"
|
#define KERNEL_FILE "kernel"
|
||||||
#define RAMDISK_FILE "ramdisk.cpio"
|
#define RAMDISK_FILE "ramdisk.cpio"
|
||||||
@@ -21,10 +17,3 @@ void repack(const char *src_img, const char *out_img, bool skip_comp = false);
|
|||||||
int verify(const char *image, const char *cert);
|
int verify(const char *image, const char *cert);
|
||||||
int sign(const char *image, const char *name, const char *cert, const char *key);
|
int sign(const char *image, const char *name, const char *cert, const char *key);
|
||||||
int split_image_dtb(const char *filename, bool skip_decomp = false);
|
int split_image_dtb(const char *filename, bool skip_decomp = false);
|
||||||
int dtb_commands(int argc, char *argv[]);
|
|
||||||
|
|
||||||
static inline bool check_env(const char *name) {
|
|
||||||
using namespace std::string_view_literals;
|
|
||||||
const char *val = getenv(name);
|
|
||||||
return val != nullptr && val == "true"sv;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,22 +2,12 @@
|
|||||||
|
|
||||||
#include "boot-rs.hpp"
|
#include "boot-rs.hpp"
|
||||||
#include "magiskboot.hpp"
|
#include "magiskboot.hpp"
|
||||||
#include "compress.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#ifdef USE_CRT0
|
|
||||||
__BEGIN_DECLS
|
|
||||||
int musl_vfprintf(FILE *stream, const char *format, va_list arg);
|
|
||||||
int vfprintf(FILE *stream, const char *format, va_list arg) {
|
|
||||||
return musl_vfprintf(stream, format, arg);
|
|
||||||
}
|
|
||||||
__END_DECLS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void print_formats() {
|
static void print_formats() {
|
||||||
for (int fmt = GZIP; fmt < LZOP; ++fmt) {
|
for (int fmt = +FileFormat::GZIP; fmt < +FileFormat::LZOP; ++fmt) {
|
||||||
fprintf(stderr, "%s ", fmt2name[(format_t) fmt]);
|
fprintf(stderr, "%s ", fmt2name[(FileFormat) fmt]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +116,93 @@ Supported actions:
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void decompress(char *infile, const char *outfile) {
|
||||||
|
bool in_std = infile == "-"sv;
|
||||||
|
bool rm_in = false;
|
||||||
|
|
||||||
|
int in_fd = in_std ? STDIN_FILENO : xopen(infile, O_RDONLY);
|
||||||
|
int out_fd = -1;
|
||||||
|
|
||||||
|
uint8_t buf[4096];
|
||||||
|
size_t len = read(in_fd, buf, sizeof(buf));
|
||||||
|
FileFormat type = check_fmt(buf, len);
|
||||||
|
|
||||||
|
fprintf(stderr, "Detected format: [%s]\n", fmt2name[type]);
|
||||||
|
|
||||||
|
if (!COMPRESSED(type))
|
||||||
|
LOGE("Input file is not a supported compressed type!\n");
|
||||||
|
|
||||||
|
// If user does not provide outfile, infile has to be either
|
||||||
|
// <path>.[ext], or '-'. Outfile will be either <path> or '-'.
|
||||||
|
// If the input does not have proper format, abort.
|
||||||
|
|
||||||
|
char *ext = nullptr;
|
||||||
|
if (outfile == nullptr) {
|
||||||
|
outfile = infile;
|
||||||
|
if (!in_std) {
|
||||||
|
ext = strrchr(infile, '.');
|
||||||
|
if (ext == nullptr || strcmp(ext, fmt2ext[type]) != 0)
|
||||||
|
LOGE("Input file is not a supported type!\n");
|
||||||
|
|
||||||
|
// Strip out extension and remove input
|
||||||
|
*ext = '\0';
|
||||||
|
rm_in = true;
|
||||||
|
fprintf(stderr, "Decompressing to [%s]\n", outfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_fd = outfile == "-"sv ?
|
||||||
|
STDOUT_FILENO :
|
||||||
|
xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
if (ext) *ext = '.';
|
||||||
|
|
||||||
|
decompress_bytes_fd(type, byte_view{ buf, len }, in_fd, out_fd);
|
||||||
|
|
||||||
|
if (in_fd != STDIN_FILENO) close(in_fd);
|
||||||
|
if (out_fd != STDOUT_FILENO) close(out_fd);
|
||||||
|
|
||||||
|
if (rm_in)
|
||||||
|
unlink(infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compress(const char *method, const char *infile, const char *outfile) {
|
||||||
|
FileFormat fmt = name2fmt[method];
|
||||||
|
if (fmt == FileFormat::UNKNOWN)
|
||||||
|
LOGE("Unknown compression method: [%s]\n", method);
|
||||||
|
|
||||||
|
bool in_std = infile == "-"sv;
|
||||||
|
bool rm_in = false;
|
||||||
|
|
||||||
|
int in_fd = in_std ? STDIN_FILENO : xopen(infile, O_RDONLY);
|
||||||
|
int out_fd = -1;
|
||||||
|
|
||||||
|
if (outfile == nullptr) {
|
||||||
|
if (in_std) {
|
||||||
|
out_fd = STDOUT_FILENO;
|
||||||
|
} else {
|
||||||
|
// If user does not provide outfile and infile is not
|
||||||
|
// STDIN, output to <infile>.[ext]
|
||||||
|
string tmp(infile);
|
||||||
|
tmp += fmt2ext[fmt];
|
||||||
|
out_fd = xopen(tmp.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
fprintf(stderr, "Compressing to [%s]\n", tmp.data());
|
||||||
|
rm_in = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out_fd = outfile == "-"sv ?
|
||||||
|
STDOUT_FILENO :
|
||||||
|
xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
}
|
||||||
|
|
||||||
|
compress_fd(fmt, in_fd, out_fd);
|
||||||
|
|
||||||
|
if (in_fd != STDIN_FILENO) close(in_fd);
|
||||||
|
if (out_fd != STDOUT_FILENO) close(out_fd);
|
||||||
|
|
||||||
|
if (rm_in)
|
||||||
|
unlink(infile);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
cmdline_logging();
|
cmdline_logging();
|
||||||
umask(0);
|
umask(0);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ fn remove_pattern(buf: &mut [u8], pattern_matcher: unsafe fn(&[u8]) -> Option<us
|
|||||||
let skipped = buf.get_unchecked(read..(read + len));
|
let skipped = buf.get_unchecked(read..(read + len));
|
||||||
// SAFETY: all matching patterns are ASCII bytes
|
// SAFETY: all matching patterns are ASCII bytes
|
||||||
let skipped = std::str::from_utf8_unchecked(skipped);
|
let skipped = std::str::from_utf8_unchecked(skipped);
|
||||||
eprintln!("Remove pattern [{}]", skipped);
|
eprintln!("Remove pattern [{skipped}]");
|
||||||
sz -= len;
|
sz -= len;
|
||||||
read += len;
|
read += len;
|
||||||
} else {
|
} else {
|
||||||
@@ -114,7 +114,7 @@ pub fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool {
|
|||||||
|
|
||||||
let v = map.patch(pattern.as_slice(), patch.as_slice());
|
let v = map.patch(pattern.as_slice(), patch.as_slice());
|
||||||
for off in &v {
|
for off in &v {
|
||||||
eprintln!("Patch @ {:#010X} [{}] -> [{}]", off, from, to);
|
eprintln!("Patch @ {off:#010X} [{from}] -> [{to}]");
|
||||||
}
|
}
|
||||||
!v.is_empty()
|
!v.is_empty()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
|
use quick_protobuf::{BytesReader, MessageRead};
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{BufReader, Read, Seek, SeekFrom, Write},
|
io::{BufReader, Read, Seek, SeekFrom, Write},
|
||||||
os::fd::{AsRawFd, FromRawFd},
|
os::fd::FromRawFd,
|
||||||
};
|
};
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use crate::compress::get_decoder;
|
||||||
use quick_protobuf::{BytesReader, MessageRead};
|
use crate::ffi::check_fmt;
|
||||||
|
use crate::proto::update_metadata::{DeltaArchiveManifest, mod_InstallOperation::Type};
|
||||||
use crate::{
|
|
||||||
ffi,
|
|
||||||
proto::update_metadata::{DeltaArchiveManifest, mod_InstallOperation::Type},
|
|
||||||
};
|
|
||||||
use base::{
|
use base::{
|
||||||
LoggedError, LoggedResult, ReadSeekExt, ResultExt, Utf8CStr, WriteExt, error, ffi::Utf8CStrRef,
|
LoggedError, LoggedResult, ReadSeekExt, ResultExt, Utf8CStr, WriteExt, error, ffi::Utf8CStrRef,
|
||||||
};
|
};
|
||||||
@@ -36,7 +34,7 @@ fn do_extract_boot_from_payload(
|
|||||||
let mut reader = BufReader::new(if in_path == "-" {
|
let mut reader = BufReader::new(if in_path == "-" {
|
||||||
unsafe { File::from_raw_fd(0) }
|
unsafe { File::from_raw_fd(0) }
|
||||||
} else {
|
} else {
|
||||||
File::open(in_path).log_with_msg(|w| write!(w, "Cannot open '{}'", in_path))?
|
File::open(in_path).log_with_msg(|w| write!(w, "Cannot open '{in_path}'"))?
|
||||||
});
|
});
|
||||||
|
|
||||||
let buf = &mut [0u8; 4];
|
let buf = &mut [0u8; 4];
|
||||||
@@ -109,7 +107,7 @@ fn do_extract_boot_from_payload(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut out_file =
|
let mut out_file =
|
||||||
File::create(out_path).log_with_msg(|w| write!(w, "Cannot write to '{}'", out_path))?;
|
File::create(out_path).log_with_msg(|w| write!(w, "Cannot write to '{out_path}'"))?;
|
||||||
|
|
||||||
// Skip the manifest signature
|
// Skip the manifest signature
|
||||||
reader.skip(manifest_sig_len as usize)?;
|
reader.skip(manifest_sig_len as usize)?;
|
||||||
@@ -168,9 +166,12 @@ fn do_extract_boot_from_payload(
|
|||||||
}
|
}
|
||||||
Type::REPLACE_BZ | Type::REPLACE_XZ => {
|
Type::REPLACE_BZ | Type::REPLACE_XZ => {
|
||||||
out_file.seek(SeekFrom::Start(out_offset))?;
|
out_file.seek(SeekFrom::Start(out_offset))?;
|
||||||
if !ffi::decompress(data, out_file.as_raw_fd()) {
|
let mut decoder = get_decoder(check_fmt(data), &mut out_file);
|
||||||
|
let Ok(_): std::io::Result<()> = (try {
|
||||||
|
decoder.write_all(data)?;
|
||||||
|
}) else {
|
||||||
return Err(bad_payload!("decompression failed"));
|
return Err(bad_payload!("decompression failed"));
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
_ => return Err(bad_payload!("unsupported operation type")),
|
_ => return Err(bad_payload!("unsupported operation type")),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ fn switch_cgroup(cgroup: &str, pid: i32) {
|
|||||||
}
|
}
|
||||||
if let Ok(mut file) = buf.open(O_WRONLY | O_APPEND | O_CLOEXEC) {
|
if let Ok(mut file) = buf.open(O_WRONLY | O_APPEND | O_CLOEXEC) {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
buf.write_fmt(format_args!("{}", pid)).ok();
|
buf.write_fmt(format_args!("{pid}")).ok();
|
||||||
file.write_all(buf.as_bytes()).log_ok();
|
file.write_all(buf.as_bytes()).log_ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
#include <consts.hpp>
|
#include <core.hpp>
|
||||||
#include <base.hpp>
|
|
||||||
|
|
||||||
#include "deny.hpp"
|
#include "deny.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <functional>
|
|
||||||
#include <map>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include <core.hpp>
|
|
||||||
|
|
||||||
#define ISOLATED_MAGIC "isolated"
|
#define ISOLATED_MAGIC "isolated"
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string>
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <base.hpp>
|
#include <core.hpp>
|
||||||
|
|
||||||
#include "deny.hpp"
|
#include "deny.hpp"
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user