Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

232 changes: 232 additions & 0 deletions MFuse/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -3192,6 +3192,122 @@
}
}
},
"editor.field.nfsGID" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID (optional)"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID (opcional)"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID (facultatif)"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID (opsional)"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID (facoltativo)"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID(任意)"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID(선택 사항)"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID(可选)"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "GID(選填)"
}
}
}
},
"editor.field.nfsUID" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID (optional)"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID (opcional)"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID (facultatif)"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID (opsional)"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID (facoltativo)"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID(任意)"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID(선택 사항)"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID(可选)"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "UID(選填)"
}
}
}
},
"editor.field.passphraseOptional" : {
"extractionState" : "stale",
"localizations" : {
Expand Down Expand Up @@ -3723,6 +3839,64 @@
}
}
},
"editor.footer.nfs" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFSv3 over TCP. Remote Path is the exported directory. The server sees requests from these IDs (your Mac's by default) and from a port above 1024, so a Linux export needs the insecure option."
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFSv3 sobre TCP. La ruta remota es el directorio exportado. El servidor recibe las solicitudes con estos ID (por defecto, los de tu Mac) y desde un puerto superior a 1024, por lo que una exportación de Linux necesita la opción insecure."
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFSv3 sur TCP. Le chemin distant est le répertoire exporté. Le serveur reçoit les requêtes avec ces identifiants (ceux de votre Mac par défaut) et depuis un port supérieur à 1024 : un export Linux doit donc avoir l'option insecure."
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFSv3 melalui TCP. Jalur Jarak Jauh adalah direktori yang diekspor. Server menerima permintaan dengan ID ini (secara default milik Mac Anda) dan dari port di atas 1024, sehingga ekspor Linux memerlukan opsi insecure."
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFSv3 su TCP. Il percorso remoto è la directory esportata. Il server riceve le richieste con questi ID (per impostazione predefinita quelli del Mac) e da una porta superiore a 1024, quindi un export Linux richiede l'opzione insecure."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "TCP 上の NFSv3 です。リモートパスにはエクスポートされたディレクトリを指定します。サーバにはこれらの ID(既定では Mac の ID)と 1024 より大きいポートからのリクエストとして届くため、Linux のエクスポートには insecure オプションが必要です。"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "TCP를 통한 NFSv3입니다. 원격 경로는 내보낸 디렉터리입니다. 서버는 이 ID(기본값은 Mac의 ID)와 1024보다 큰 포트에서 오는 요청으로 받으므로 Linux 내보내기에는 insecure 옵션이 필요합니다."
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "使用 TCP 上的 NFSv3。远程路径填写导出的目录。服务器收到的请求使用这里的 ID(默认是这台 Mac 的),来源端口大于 1024,所以 Linux 的 export 需要加 insecure 选项。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "使用 TCP 上的 NFSv3。遠端路徑填寫匯出的目錄。伺服器收到的請求使用這裡的 ID(預設是這台 Mac 的),來源連接埠大於 1024,所以 Linux 的 export 需要加上 insecure 選項。"
}
}
}
},
"editor.footer.s3Endpoint" : {
"localizations" : {
"en" : {
Expand Down Expand Up @@ -4489,6 +4663,64 @@
}
}
},
"editor.section.nfs" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFS Settings"
}
},
"es" : {
"stringUnit" : {
"state" : "translated",
"value" : "Configuración de NFS"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Paramètres NFS"
}
},
"id" : {
"stringUnit" : {
"state" : "translated",
"value" : "Pengaturan NFS"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Impostazioni NFS"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFS 設定"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFS 설정"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFS 设置"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "NFS 設定"
}
}
}
},
"editor.section.s3" : {
"extractionState" : "stale",
"localizations" : {
Expand Down
33 changes: 33 additions & 0 deletions MFuse/Views/ConnectionEditorSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ struct ConnectionEditorSheet: View {
@State private var webdavTLS: Bool = true
@State private var smbShare: String = ""
@State private var smbDomain: String = ""
@State private var nfsUID: String = ""
@State private var nfsGID: String = ""
@State private var ftpTLS: Bool = false
/// The user-supplied OAuth client a Google Drive mount from before the bundled client
/// was authorized against; `nil` once it is (re-)authorized against the bundled one.
Expand Down Expand Up @@ -165,6 +167,8 @@ struct ConnectionEditorSheet: View {
_webdavTLS = State(initialValue: params["tls"] != "false")
_smbShare = State(initialValue: params["share"] ?? "")
_smbDomain = State(initialValue: params["domain"] ?? "")
_nfsUID = State(initialValue: params["uid"] ?? "")
_nfsGID = State(initialValue: params["gid"] ?? "")
_ftpTLS = State(initialValue: params["tls"] == "true")
_legacyGoogleOAuthClient = State(initialValue: savedLegacyGoogleOAuthClient)
_oauthAccountName = State(initialValue: params["oauthAccountName"] ?? "")
Expand Down Expand Up @@ -316,6 +320,20 @@ struct ConnectionEditorSheet: View {
Section(AppL10n.string("editor.section.ftp", fallback: "FTP Settings")) {
Toggle(AppL10n.string("editor.field.useTLSFTPS", fallback: "Use TLS (FTPS)"), isOn: $ftpTLS)
}
case .nfs:
Section {
TextField(AppL10n.string("editor.field.nfsUID", fallback: "UID (optional)"), text: $nfsUID, prompt: Text(String(getuid())))
TextField(AppL10n.string("editor.field.nfsGID", fallback: "GID (optional)"), text: $nfsGID, prompt: Text(String(getgid())))
} header: {
Text(AppL10n.string("editor.section.nfs", fallback: "NFS Settings"))
} footer: {
Text(AppL10n.string(
"editor.footer.nfs",
fallback: "NFSv3 over TCP. Remote Path is the exported directory. The server sees requests from these IDs (your Mac's by default) and from a port above 1024, so a Linux export needs the insecure option."
))
.font(.caption)
.foregroundStyle(.secondary)
}
default:
EmptyView()
}
Expand Down Expand Up @@ -524,6 +542,9 @@ struct ConnectionEditorSheet: View {
if backendType == .googleDrive || usesBundledOAuthFlow {
return hasConnectedOAuthAccount
}
if backendType == .nfs, !Self.isValidNFSID(nfsUID) || !Self.isValidNFSID(nfsGID) {
return false
}
if backendType == .s3 {
let hasRequiredAccessKeyCredentials =
authMethod != .accessKey || (!s3AccessKeyID.isEmpty && !s3SecretAccessKey.isEmpty)
Expand All @@ -541,6 +562,15 @@ struct ConnectionEditorSheet: View {
return !backendType.requiresServerEndpoint || (!Self.isBlank(host) && hasValidPort)
}

/// An NFS uid or gid as typed: empty for the default, or a 32-bit id.
private static func nfsID(_ text: String) -> UInt32? {
UInt32(text.trimmingCharacters(in: .whitespacesAndNewlines))
}

private static func isValidNFSID(_ text: String) -> Bool {
isBlank(text) || nfsID(text) != nil
}

/// A port the backends can dial. Zero parses and is persisted, but every host-based
/// backend hands `config.port` straight to its client, where it is not an address.
private var hasValidPort: Bool {
Expand Down Expand Up @@ -1123,6 +1153,9 @@ struct ConnectionEditorSheet: View {
if !smbDomain.isEmpty { params["domain"] = smbDomain }
case .ftp:
if ftpTLS { params["tls"] = "true" }
case .nfs:
if let uid = Self.nfsID(nfsUID) { params["uid"] = String(uid) }
if let gid = Self.nfsID(nfsGID) { params["gid"] = String(gid) }
case .googleDrive:
// Kept only while the stored token still belongs to a user-supplied client,
// which is the only one it renews against. TODO: remove with
Expand Down
2 changes: 1 addition & 1 deletion MFuseProvider/FileProviderExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ public final class FileProviderExtension: NSObject, NSFileProviderReplicatedExte

private func supportsChunkedRead(for backendType: BackendType) -> Bool {
switch backendType {
case .s3, .sftp:
case .s3, .sftp, .nfs:
return true
default:
return false
Expand Down
9 changes: 9 additions & 0 deletions Packages/MFuseE2E/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Packages/MFuseE2E/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let package = Package(
.package(path: "../MFuseWebDAV"),
.package(path: "../MFuseSMB"),
.package(path: "../MFuseFTP"),
.package(path: "../MFuseNFS"),
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.37.0")
],
targets: [
Expand All @@ -30,6 +31,7 @@ let package = Package(
.product(name: "MFuseWebDAV", package: "MFuseWebDAV"),
.product(name: "MFuseSMB", package: "MFuseSMB"),
.product(name: "MFuseFTP", package: "MFuseFTP"),
.product(name: "MFuseNFS", package: "MFuseNFS"),
.product(name: "NIOSSL", package: "swift-nio-ssl")
]
)
Expand Down
Loading
Loading