aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Halter <868228+jhalter@users.noreply.github.com>2026-03-14 17:41:12 -0700
committerJeff Halter <868228+jhalter@users.noreply.github.com>2026-03-14 17:41:12 -0700
commit72c6ddc104c349a4798fddeaa8f77dbe139fe104 (patch)
treeaae0dfe993bd8ff298efd286d881ae96017105f9
parentb40b4ccdea356807f82e5a33371ca59832ecac8a (diff)
Fix Mac Roman decoding incorrectly applied to filesystem root paths
ReadPath() and HandleNewFolder decoded the entire joined path from Mac Roman, including the fileRoot prefix which is already UTF-8. This caused file listing failures when config paths or FileRoot values contained non-ASCII characters. Now only client-provided path components (subPath, fileName/folderName) are decoded before joining with fileRoot.
-rw-r--r--hotline/file_path.go18
-rw-r--r--hotline/file_path_test.go23
-rw-r--r--internal/mobius/transaction_handlers.go12
3 files changed, 46 insertions, 7 deletions
diff --git a/hotline/file_path.go b/hotline/file_path.go
index a3a13f1..c97faea 100644
--- a/hotline/file_path.go
+++ b/hotline/file_path.go
@@ -115,14 +115,22 @@ func ReadPath(fileRoot string, filePath, fileName []byte) (fullPath string, err
subPath = path.Join("/", subPath, string(pathItem.Name))
}
+ // Decode only client-provided path components from Mac Roman to UTF-8.
+ // The fileRoot is already a UTF-8 filesystem path and must not be decoded.
+ subPath, err = txtDecoder.String(subPath)
+ if err != nil {
+ return "", fmt.Errorf("invalid filepath encoding: %w", err)
+ }
+
+ decodedFileName, err := txtDecoder.String(string(fileName))
+ if err != nil {
+ return "", fmt.Errorf("invalid filename encoding: %w", err)
+ }
+
fullPath = path.Join(
fileRoot,
subPath,
- path.Join("/", string(fileName)),
+ path.Join("/", decodedFileName),
)
- fullPath, err = txtDecoder.String(fullPath)
- if err != nil {
- return "", fmt.Errorf("invalid filepath encoding: %w", err)
- }
return fullPath, nil
}
diff --git a/hotline/file_path_test.go b/hotline/file_path_test.go
index ee0cbac..c86a8d9 100644
--- a/hotline/file_path_test.go
+++ b/hotline/file_path_test.go
@@ -152,6 +152,29 @@ func Test_readPath(t *testing.T) {
},
want: "/usr/local/var/mobius/Files",
},
+ {
+ name: "when fileRoot contains non-ASCII UTF-8 characters",
+ args: args{
+ fileRoot: "/files/español",
+ filePath: nil,
+ fileName: []byte("foo"),
+ },
+ want: "/files/español/foo",
+ },
+ {
+ name: "when fileRoot contains non-ASCII and filePath has Mac Roman bytes",
+ args: args{
+ fileRoot: "/files/español",
+ filePath: []byte{
+ 0x00, 0x01,
+ 0x00, 0x00,
+ 0x06,
+ 0x63, 0x61, 0x66, 0x8e, 0x73, 0x21, // "caf\x8es!" where 0x8e is Mac Roman é
+ },
+ fileName: []byte("foo"),
+ },
+ want: "/files/español/cafés!/foo",
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/internal/mobius/transaction_handlers.go b/internal/mobius/transaction_handlers.go
index 259ac02..33af941 100644
--- a/internal/mobius/transaction_handlers.go
+++ b/internal/mobius/transaction_handlers.go
@@ -568,11 +568,19 @@ func HandleNewFolder(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotl
subPath = path.Join("/", subPath, string(pathItem.Name))
}
}
- newFolderPath := path.Join(cc.FileRoot(), subPath, folderName)
- newFolderPath, err := txtDecoder.String(newFolderPath)
+
+ // Decode only client-provided path components from Mac Roman to UTF-8.
+ // The FileRoot is already a UTF-8 filesystem path and must not be decoded.
+ subPath, err := txtDecoder.String(subPath)
if err != nil {
return res
}
+ folderName, err = txtDecoder.String(folderName)
+ if err != nil {
+ return res
+ }
+
+ newFolderPath := path.Join(cc.FileRoot(), subPath, folderName)
// TODO: check path and folder Name lengths