From 77eb169736483b126b092d995fecfc0e66d48ae1 Mon Sep 17 00:00:00 2001 From: zekaifeng <37854724+dormanze@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:24:09 +0800 Subject: [PATCH 1/2] fix:mc cp exec failed when the length of file name is 255 characters The cp and mirror commands fails to be executed when the length of the file name is 255 characters. --- cmd/client-fs.go | 58 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/cmd/client-fs.go b/cmd/client-fs.go index a7375e2657..7bdfa911e7 100644 --- a/cmd/client-fs.go +++ b/cmd/client-fs.go @@ -32,6 +32,8 @@ import ( "syscall" "time" + "github.com/google/uuid" + "github.com/pkg/xattr" "github.com/rjeczalik/notify" @@ -301,8 +303,12 @@ func (f *fsClient) put(_ context.Context, reader io.Reader, size int64, progress objectPath := f.PathURL.Path - // Write to a temporary file "object.part.minio" before commit. - objectPartPath := objectPath + partSuffix + if err := checkPathLength(objectPath); err != nil { + return 0, err + } + + // Write to a temporary file "objectpath/uuid" before commit. + objectPartPath := filepath.Join(filepath.Dir(objectPath), uuid.NewString()) // We cannot resume this operation, then we // should remove any partial download if any. @@ -393,6 +399,46 @@ func (f *fsClient) Put(ctx context.Context, reader io.Reader, size int64, progre return f.put(ctx, reader, size, progress, opts) } +// checkPathLength - returns error if given path name length more than 255 +func checkPathLength(pathName string) *probe.Error { + // Apple OS X path length is limited to 1016 + if runtime.GOOS == "darwin" && len(pathName) > 1016 { + return probe.NewError(errors.New("file name too long")) + } + + // Disallow more than 1024 characters on windows, there + // are no known name_max limits on Windows. + if runtime.GOOS == "windows" && len(pathName) > 1024 { + return probe.NewError(errors.New("file name too long")) + } + + // On Unix we reject paths if they are just '.', '..' or '/' + if pathName == "." || pathName == ".." || pathName == "/" { + return probe.NewError(errors.New("file access denied")) + } + + // Check each path segment length is > 255 on all Unix + // platforms, look for this value as NAME_MAX in + // /usr/include/linux/limits.h + var count int64 + for _, p := range pathName { + switch p { + case '/': + count = 0 // Reset + case '\\': + if runtime.GOOS == "windows" { + count = 0 + } + default: + count++ + if count > 255 { + return probe.NewError(errors.New("file name too long")) + } + } + } // Success. + return nil +} + func (f *fsClient) putN(_ context.Context, reader io.Reader, size int64, progress io.Reader, opts PutOptions) (int64, *probe.Error) { // ContentType is not handled on purpose. // For filesystem this is a redundant information. @@ -415,8 +461,12 @@ func (f *fsClient) putN(_ context.Context, reader io.Reader, size int64, progres objectPath := f.PathURL.Path - // Write to a temporary file "object.part.minio" before commit. - objectPartPath := objectPath + partSuffix + if err := checkPathLength(objectPath); err != nil { + return 0, err + } + + // Write to a temporary file ""objectpath/uuid"" before commit. + objectPartPath := filepath.Join(filepath.Dir(objectPath), uuid.NewString()) // We cannot resume this operation, then we // should remove any partial download if any. From 33f6e68488fe78007d386188868da9883637e107 Mon Sep 17 00:00:00 2001 From: zekaifeng <37854724+dormanze@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:26:57 +0800 Subject: [PATCH 2/2] Resolve review comments --- cmd/client-fs.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cmd/client-fs.go b/cmd/client-fs.go index 7bdfa911e7..031d24392c 100644 --- a/cmd/client-fs.go +++ b/cmd/client-fs.go @@ -406,9 +406,10 @@ func checkPathLength(pathName string) *probe.Error { return probe.NewError(errors.New("file name too long")) } - // Disallow more than 1024 characters on windows, there + // Disallow more than 32,767 characters on windows, there // are no known name_max limits on Windows. - if runtime.GOOS == "windows" && len(pathName) > 1024 { + // Refer: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry + if runtime.GOOS == "windows" && len(pathName) > 32767 { return probe.NewError(errors.New("file name too long")) } @@ -428,12 +429,14 @@ func checkPathLength(pathName string) *probe.Error { case '\\': if runtime.GOOS == "windows" { count = 0 + } else { + count++ } default: count++ - if count > 255 { - return probe.NewError(errors.New("file name too long")) - } + } + if count > 255 { + return probe.NewError(errors.New("file name too long")) } } // Success. return nil