allow opening symlinks pointing to folders in file manager (#156)

This commit is contained in:
Huge_Black
2026-03-09 01:17:20 +08:00
committed by GitHub
parent d48ad72fa4
commit 76c7c9e513
4 changed files with 26 additions and 11 deletions

View File

@@ -28,21 +28,30 @@ NSDictionary *vp_handle_file_command(int fd, NSDictionary *msg) {
NSMutableArray *entries = [NSMutableArray arrayWithCapacity:contents.count];
for (NSString *name in contents) {
NSString *full = [path stringByAppendingPathComponent:name];
NSDictionary *attrs = [fm attributesOfItemAtPath:full error:nil];
if (!attrs) continue;
NSString *fileType = attrs[NSFileType];
struct stat st;
if (lstat([full fileSystemRepresentation], &st) != 0) continue;
NSString *typeStr = @"file";
if ([fileType isEqualToString:NSFileTypeDirectory]) typeStr = @"dir";
else if ([fileType isEqualToString:NSFileTypeSymbolicLink]) typeStr = @"link";
if (S_ISDIR(st.st_mode)) typeStr = @"dir";
else if (S_ISLNK(st.st_mode)) typeStr = @"link";
NSNumber *size = attrs[NSFileSize] ?: @0;
NSDate *mtime = attrs[NSFileModificationDate];
NSNumber *posixPerms = attrs[NSFilePosixPermissions];
BOOL linkTargetsDirectory = NO;
if (S_ISLNK(st.st_mode)) {
struct stat resolved;
if (stat([full fileSystemRepresentation], &resolved) == 0) {
linkTargetsDirectory = S_ISDIR(resolved.st_mode);
}
}
NSNumber *size = @(st.st_size);
NSDate *mtime = [NSDate dateWithTimeIntervalSince1970:st.st_mtimespec.tv_sec];
NSNumber *posixPerms = @((unsigned long)st.st_mode & 0777);
[entries addObject:@{
@"name": name,
@"type": typeStr,
@"link_target_dir": @(linkTargetsDirectory),
@"size": size,
@"perm": [NSString stringWithFormat:@"%lo", [posixPerms unsignedLongValue]],
@"mtime": @(mtime ? [mtime timeIntervalSince1970] : 0),

View File

@@ -91,7 +91,7 @@ class VPhoneFileBrowserModel {
}
func openItem(_ file: VPhoneRemoteFile) {
if file.isDirectory {
if file.isDirectoryLike {
navigate(to: file.path)
}
}

View File

@@ -51,7 +51,7 @@ struct VPhoneFileBrowserView: View {
Table(of: VPhoneRemoteFile.self, selection: $model.selection, sortOrder: $model.sortOrder) {
TableColumn("", value: \.name) { file in
Image(systemName: file.icon)
.foregroundStyle(file.isDirectory ? .blue : .secondary)
.foregroundStyle(file.isDirectoryLike ? .blue : .secondary)
.frame(width: 20)
}
.width(28)
@@ -72,7 +72,7 @@ struct VPhoneFileBrowserView: View {
TableColumn("Size", value: \.size) { file in
Text(file.displaySize)
.font(.system(.body, design: .monospaced))
.foregroundStyle(file.isDirectory ? .secondary : .primary)
.foregroundStyle(file.isDirectoryLike ? .secondary : .primary)
}
.width(min: 50, ideal: 80, max: .infinity)

View File

@@ -7,6 +7,7 @@ struct VPhoneRemoteFile: Identifiable, Hashable {
let size: UInt64
let permissions: String
let modified: Date
let symlinkTargetsDirectory: Bool
var id: String {
path
@@ -24,6 +25,10 @@ struct VPhoneRemoteFile: Identifiable, Hashable {
type == .symbolicLink
}
var isDirectoryLike: Bool {
isDirectory || symlinkTargetsDirectory
}
var displaySize: String {
if isDirectory || isSymbolicLink { return "" }
return ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file)
@@ -86,6 +91,7 @@ extension VPhoneRemoteFile {
self.dir = dir
self.name = name
self.type = type
symlinkTargetsDirectory = entry["link_target_dir"] as? Bool ?? false
size = (entry["size"] as? NSNumber)?.uint64Value ?? 0
permissions = entry["perm"] as? String ?? "---"
modified = Date(timeIntervalSince1970: (entry["mtime"] as? Double) ?? 0)