Skip to content

Commit d7ac68b

Browse files
committed
feat: android implementation for hardlinks and symlinks
1 parent 350b69a commit d7ac68b

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

android/src/main/java/com/alpha0010/fs/FileAccessModule.kt

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import java.io.OutputStream
2525
import java.lang.ref.WeakReference
2626
import java.security.MessageDigest
2727
import java.util.zip.ZipInputStream
28+
import java.nio.file.Files
2829

2930
class FileAccessModule internal constructor(context: ReactApplicationContext) :
3031
FileAccessSpec(context) {
@@ -275,6 +276,40 @@ class FileAccessModule internal constructor(context: ReactApplicationContext) :
275276
promise.reject("ERR", "App group unavailable on Android.")
276277
}
277278

279+
@ReactMethod
280+
override fun hardlink(source: String, target: String, promise: Promise) {
281+
ioScope.launch {
282+
try {
283+
if (source.isContentUri() || target.isContentUri()) {
284+
promise.reject("ERR", "Hard links are not supported for content URIs")
285+
return@launch
286+
}
287+
288+
val sourceFile = parsePathToFile(source)
289+
val targetFile = parsePathToFile(target)
290+
291+
if (!sourceFile.exists()) {
292+
promise.reject("ENOENT", "Source file '$source' does not exist")
293+
return@launch
294+
}
295+
296+
if (targetFile.exists()) {
297+
promise.reject("EEXIST", "Target file '$target' already exists")
298+
return@launch
299+
}
300+
301+
try {
302+
Files.createLink(targetFile.toPath(), sourceFile.toPath())
303+
promise.resolve(null)
304+
} catch (e: IOException) {
305+
promise.reject("ERR", "Failed to create hard link: ${e.message}")
306+
}
307+
} catch (e: Throwable) {
308+
promise.reject(e)
309+
}
310+
}
311+
}
312+
278313
@ReactMethod
279314
override fun hash(path: String, algorithm: String, promise: Promise) {
280315
ioScope.launch {
@@ -455,6 +490,40 @@ class FileAccessModule internal constructor(context: ReactApplicationContext) :
455490
}
456491
}
457492

493+
@ReactMethod
494+
override fun symlink(source: String, target: String, promise: Promise) {
495+
ioScope.launch {
496+
try {
497+
if (source.isContentUri() || target.isContentUri()) {
498+
promise.reject("ERR", "Symbolic links are not supported for content URIs")
499+
return@launch
500+
}
501+
502+
val sourceFile = parsePathToFile(source)
503+
val targetFile = parsePathToFile(target)
504+
505+
if (!sourceFile.exists()) {
506+
promise.reject("ENOENT", "Source file '$source' does not exist")
507+
return@launch
508+
}
509+
510+
if (targetFile.exists()) {
511+
promise.reject("EEXIST", "Target file '$target' already exists")
512+
return@launch
513+
}
514+
515+
try {
516+
Files.createSymbolicLink(targetFile.toPath(), sourceFile.toPath())
517+
promise.resolve(null)
518+
} catch (e: IOException) {
519+
promise.reject("ERR", "Failed to create symbolic link: ${e.message}")
520+
}
521+
} catch (e: Throwable) {
522+
promise.reject(e)
523+
}
524+
}
525+
}
526+
458527
@ReactMethod
459528
override fun unlink(path: String, promise: Promise) {
460529
ioScope.launch {

android/src/oldarch/FileAccessSpec.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ abstract class FileAccessSpec internal constructor(context: ReactApplicationCont
2424
abstract fun exists(path: String, promise: Promise)
2525
abstract fun fetch(requestId: Double, resource: String, init: ReadableMap)
2626
abstract fun getAppGroupDir(groupName: String, promise: Promise)
27+
abstract fun hardlink(source: String, target: String, promise: Promise)
2728
abstract fun hash(path: String, algorithm: String, promise: Promise)
2829
abstract fun isDir(path: String, promise: Promise)
2930
abstract fun ls(path: String, promise: Promise)
@@ -33,6 +34,7 @@ abstract class FileAccessSpec internal constructor(context: ReactApplicationCont
3334
abstract fun readFileChunk(path: String, offset: Double, length: Double, encoding: String, promise: Promise)
3435
abstract fun stat(path: String, promise: Promise)
3536
abstract fun statDir(path: String, promise: Promise)
37+
abstract fun symlink(source: String, target: String, promise: Promise)
3638
abstract fun unlink(path: String, promise: Promise)
3739
abstract fun unzip(source: String, target: String, promise: Promise)
3840
abstract fun writeFile(path: String, data: String, encoding: String, promise: Promise)

0 commit comments

Comments
 (0)