Skip to content

Commit ee801f9

Browse files
committed
fix(android): remove published attachment stage namespace
1 parent 931fecb commit ee801f9

10 files changed

Lines changed: 1801 additions & 21 deletions

File tree

.github/workflows/native-platform-ci.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,20 @@ jobs:
254254
-o "$RUNNER_TEMP/file-compat-lock-test"
255255
"$RUNNER_TEMP/file-compat-lock-test"
256256
257+
- name: Run Android exact-directory retirement regression
258+
run: |
259+
set -euo pipefail
260+
c++ \
261+
-std=c++17 \
262+
-Wall \
263+
-Wextra \
264+
-Werror \
265+
-I apps/mobile/modules/attachment-file-installer/android/src/main/cpp \
266+
apps/mobile/modules/attachment-file-installer/android/src/main/cpp/exact_directory_retirement.cpp \
267+
apps/mobile/modules/attachment-file-installer/android/src/test/cpp/exact_directory_retirement_test.cpp \
268+
-o "$RUNNER_TEMP/exact-directory-retirement-test"
269+
"$RUNNER_TEMP/exact-directory-retirement-test"
270+
257271
- name: Generate Android native project
258272
working-directory: apps/mobile
259273
env:
@@ -276,6 +290,7 @@ jobs:
276290
./gradlew \
277291
:app:compileDebugKotlin \
278292
:app:compileDebugJavaWithJavac \
293+
:attachment-file-installer:assembleDebug \
279294
:sync-file-lock:assembleDebug \
280295
--no-daemon \
281296
-PreactNativeArchitectures=arm64-v8a
@@ -296,6 +311,25 @@ jobs:
296311
readelf --dyn-syms --wide "$RUNNER_TEMP/libsync-file-lock.so" \
297312
| grep -F 'Java_tech_dongdongbh_mindwtr_syncfilelock_StableRootLockNative_tryOfdLock'
298313
314+
- name: Verify packaged Android attachment JNI symbols
315+
working-directory: apps/mobile/android
316+
run: |
317+
set -euo pipefail
318+
ATTACHMENT_AAR="$(find ../modules/attachment-file-installer/android/build/outputs/aar -name '*debug.aar' -print -quit)"
319+
if [ -z "${ATTACHMENT_AAR:-}" ]; then
320+
echo "::error::attachment-file-installer debug AAR was not produced"
321+
exit 1
322+
fi
323+
unzip -l "$ATTACHMENT_AAR" | grep -F 'jni/arm64-v8a/libattachment-file-installer.so'
324+
unzip -p "$ATTACHMENT_AAR" jni/arm64-v8a/libattachment-file-installer.so \
325+
> "$RUNNER_TEMP/libattachment-file-installer.so"
326+
readelf --dyn-syms --wide "$RUNNER_TEMP/libattachment-file-installer.so" \
327+
| grep -F 'Java_tech_dongdongbh_mindwtr_attachmentfileinstaller_ExactAttachmentPublisherNative_publishRelativeNoReplace'
328+
readelf --dyn-syms --wide "$RUNNER_TEMP/libattachment-file-installer.so" \
329+
| grep -F 'Java_tech_dongdongbh_mindwtr_attachmentfileinstaller_ExactAttachmentPublisherNative_retireEmptyDirectoryIfIdentity'
330+
readelf --dyn-syms --wide "$RUNNER_TEMP/libattachment-file-installer.so" \
331+
| grep -F 'Java_tech_dongdongbh_mindwtr_attachmentfileinstaller_ExactAttachmentPublisherNative_retireReservedPrivateStage'
332+
299333
- name: Run Android native recovery tests
300334
working-directory: apps/mobile/android
301335
run: ./gradlew :attachment-file-installer:testDebugUnitTest :sync-file-lock:testDebugUnitTest --no-daemon

apps/mobile/modules/attachment-file-installer/android/src/main/cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ project(attachment_file_installer LANGUAGES CXX)
55
add_library(
66
attachment-file-installer
77
SHARED
8+
exact_directory_retirement.cpp
89
exact_attachment_publisher.cpp
910
)

apps/mobile/modules/attachment-file-installer/android/src/main/cpp/exact_attachment_publisher.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#include <jni.h>
22

3+
#include "exact_directory_retirement.h"
4+
35
#include <cerrno>
6+
#include <cstdlib>
47
#include <cstring>
58
#include <fcntl.h>
69
#include <linux/fs.h>
@@ -39,6 +42,35 @@ bool matches_identity(const struct stat& value, const char* expected) {
3942
+ std::to_string(static_cast<unsigned long long>(value.st_ino))) == expected;
4043
}
4144

45+
bool parse_identity(
46+
const char* encoded,
47+
mindwtr::attachment_file_installer::DirectoryIdentity* output) {
48+
if (encoded == nullptr || output == nullptr) return false;
49+
const std::string value(encoded);
50+
const size_t separator = value.find(':');
51+
if (
52+
separator == std::string::npos
53+
|| separator == 0
54+
|| separator + 1 >= value.size()
55+
|| value.find(':', separator + 1) != std::string::npos) {
56+
return false;
57+
}
58+
const std::string device_text = value.substr(0, separator);
59+
const std::string inode_text = value.substr(separator + 1);
60+
char* device_end = nullptr;
61+
char* inode_end = nullptr;
62+
errno = 0;
63+
const unsigned long long device = strtoull(device_text.c_str(), &device_end, 10);
64+
if (errno != 0 || device_end == nullptr || *device_end != '\0') return false;
65+
errno = 0;
66+
const unsigned long long inode = strtoull(inode_text.c_str(), &inode_end, 10);
67+
if (errno != 0 || inode_end == nullptr || *inode_end != '\0') return false;
68+
*output = {
69+
static_cast<uint64_t>(device),
70+
static_cast<uint64_t>(inode)};
71+
return true;
72+
}
73+
4274
constexpr bool rename_noreplace_needs_exact_handle_fallback(int error) {
4375
return error == ENOSYS || error == EOPNOTSUPP || error == EINVAL;
4476
}
@@ -159,3 +191,111 @@ Java_tech_dongdongbh_mindwtr_attachmentfileinstaller_ExactAttachmentPublisherNat
159191
}
160192
return JNI_TRUE;
161193
}
194+
195+
extern "C" JNIEXPORT jint JNICALL
196+
Java_tech_dongdongbh_mindwtr_attachmentfileinstaller_ExactAttachmentPublisherNative_retireEmptyDirectoryIfIdentity(
197+
JNIEnv* env,
198+
jobject,
199+
jstring parent_directory_path,
200+
jstring directory_name,
201+
jstring expected_directory_identity,
202+
jstring expected_parent_identity) {
203+
ScopedUtfChars parent_path(env, parent_directory_path);
204+
ScopedUtfChars directory_leaf(env, directory_name);
205+
ScopedUtfChars expected_directory(env, expected_directory_identity);
206+
ScopedUtfChars expected_parent(env, expected_parent_identity);
207+
if (parent_path.get() == nullptr || directory_leaf.get() == nullptr
208+
|| expected_directory.get() == nullptr || expected_parent.get() == nullptr) {
209+
return static_cast<jint>(
210+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
211+
}
212+
const std::string directory_leaf_value(directory_leaf.get());
213+
if (directory_leaf_value.empty() || directory_leaf_value == "." || directory_leaf_value == ".."
214+
|| directory_leaf_value.find('/') != std::string::npos) {
215+
throw_io_exception(env, "Attachment publication directory name is invalid");
216+
return static_cast<jint>(
217+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
218+
}
219+
mindwtr::attachment_file_installer::DirectoryIdentity directory_identity{};
220+
mindwtr::attachment_file_installer::DirectoryIdentity parent_identity{};
221+
if (
222+
!parse_identity(expected_directory.get(), &directory_identity)
223+
|| !parse_identity(expected_parent.get(), &parent_identity)) {
224+
throw_io_exception(env, "Attachment publication directory identity is invalid");
225+
return static_cast<jint>(
226+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
227+
}
228+
229+
const int parent_fd = open(
230+
parent_path.get(),
231+
O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
232+
if (parent_fd < 0) {
233+
throw_io_exception(
234+
env,
235+
std::string("Could not retain attachment publication parent: ") + strerror(errno));
236+
return static_cast<jint>(
237+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
238+
}
239+
int error_number = 0;
240+
const auto result = mindwtr::attachment_file_installer::retire_empty_directory_if_identity(
241+
parent_fd,
242+
directory_leaf.get(),
243+
directory_identity,
244+
parent_identity,
245+
nullptr,
246+
nullptr,
247+
&error_number);
248+
close(parent_fd);
249+
if (result == mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError) {
250+
throw_io_exception(
251+
env,
252+
std::string("Could not retire private attachment publication directory: ")
253+
+ strerror(error_number));
254+
}
255+
return static_cast<jint>(result);
256+
}
257+
258+
extern "C" JNIEXPORT jint JNICALL
259+
Java_tech_dongdongbh_mindwtr_attachmentfileinstaller_ExactAttachmentPublisherNative_retireReservedPrivateStage(
260+
JNIEnv* env,
261+
jobject,
262+
jstring parent_directory_path,
263+
jstring directory_name) {
264+
ScopedUtfChars parent_path(env, parent_directory_path);
265+
ScopedUtfChars directory_leaf(env, directory_name);
266+
if (parent_path.get() == nullptr || directory_leaf.get() == nullptr) {
267+
return static_cast<jint>(
268+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
269+
}
270+
const std::string directory_leaf_value(directory_leaf.get());
271+
if (directory_leaf_value.empty() || directory_leaf_value == "." || directory_leaf_value == ".."
272+
|| directory_leaf_value.find('/') != std::string::npos) {
273+
throw_io_exception(env, "Attachment publication directory name is invalid");
274+
return static_cast<jint>(
275+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
276+
}
277+
278+
const int parent_fd = open(
279+
parent_path.get(),
280+
O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
281+
if (parent_fd < 0) {
282+
throw_io_exception(
283+
env,
284+
std::string("Could not retain reserved attachment publication parent: ") + strerror(errno));
285+
return static_cast<jint>(
286+
mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError);
287+
}
288+
int error_number = 0;
289+
const auto result = mindwtr::attachment_file_installer::retire_reserved_private_stage(
290+
parent_fd,
291+
directory_leaf.get(),
292+
&error_number);
293+
close(parent_fd);
294+
if (result == mindwtr::attachment_file_installer::DirectoryRetirementResult::kIoError) {
295+
throw_io_exception(
296+
env,
297+
std::string("Could not retire reserved private attachment stage: ")
298+
+ strerror(error_number));
299+
}
300+
return static_cast<jint>(result);
301+
}

0 commit comments

Comments
 (0)