From 44906f1f3b91b9def7e1424fec18a3237b1a02f0 Mon Sep 17 00:00:00 2001 From: Konstantin Lebedev <9497591+kmlebedev@users.noreply.github.com> Date: Wed, 27 Sep 2023 17:40:51 +0500 Subject: [PATCH] fix: avoid error file name too long when writing a file (#4876) --- weed/command/filer_replication.go | 2 +- weed/replication/sink/localsink/local_sink.go | 2 +- weed/util/file_util.go | 21 ++++++++++++++++-- weed/util/file_util_test.go | 22 +++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 weed/util/file_util_test.go diff --git a/weed/command/filer_replication.go b/weed/command/filer_replication.go index ec965a5e3..4fca8158a 100644 --- a/weed/command/filer_replication.go +++ b/weed/command/filer_replication.go @@ -99,7 +99,7 @@ func runFilerReplicate(cmd *Command, args []string) bool { if m.OldEntry != nil && m.NewEntry == nil { glog.V(1).Infof("delete: %s", key) } else if m.OldEntry == nil && m.NewEntry != nil { - glog.V(1).Infof(" add: %s", key) + glog.V(1).Infof("add: %s", key) } else { glog.V(1).Infof("modify: %s", key) } diff --git a/weed/replication/sink/localsink/local_sink.go b/weed/replication/sink/localsink/local_sink.go index 70f5cfc9d..134d3985a 100644 --- a/weed/replication/sink/localsink/local_sink.go +++ b/weed/replication/sink/localsink/local_sink.go @@ -90,7 +90,7 @@ func (localsink *LocalSink) CreateEntry(key string, entry *filer_pb.Entry, signa return os.Mkdir(key, os.FileMode(entry.Attributes.FileMode)) } - dstFile, err := os.OpenFile(key, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(entry.Attributes.FileMode)) + dstFile, err := os.OpenFile(util.ToShortFileName(key), os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(entry.Attributes.FileMode)) if err != nil { return err } diff --git a/weed/util/file_util.go b/weed/util/file_util.go index 346de76db..430b6bc86 100644 --- a/weed/util/file_util.go +++ b/weed/util/file_util.go @@ -1,16 +1,20 @@ package util import ( + "bytes" + "crypto/sha256" "errors" + "fmt" + "github.com/seaweedfs/seaweedfs/weed/glog" "os" "os/user" "path/filepath" "strings" "time" - - "github.com/seaweedfs/seaweedfs/weed/glog" ) +const maxFilenameLength = 255 + func TestFolderWritable(folder string) (err error) { fileInfo, err := os.Stat(folder) if err != nil { @@ -106,6 +110,19 @@ func FileNameBase(filename string) string { return filename[:lastDotIndex] } +func ToShortFileName(path string) string { + fileName := filepath.Base(path) + if fileNameBytes := []byte(fileName); len(fileNameBytes) > maxFilenameLength { + shaStr := fmt.Sprintf("%x", sha256.Sum256(fileNameBytes)) + fileNameBase := FileNameBase(fileName) + fileExt := fileName[len(fileNameBase):] + fileNameBaseBates := bytes.ToValidUTF8([]byte(fileNameBase)[:maxFilenameLength-len([]byte(fileExt))-8], []byte{}) + shortFileName := string(fileNameBaseBates) + shaStr[len(shaStr)-8:] + return filepath.Join(filepath.Dir(path), shortFileName) + fileExt + } + return path +} + // Copied from os.WriteFile(), adding file sync. // see https://github.com/golang/go/issues/20599 func WriteFile(name string, data []byte, perm os.FileMode) error { diff --git a/weed/util/file_util_test.go b/weed/util/file_util_test.go new file mode 100644 index 000000000..a1f924fed --- /dev/null +++ b/weed/util/file_util_test.go @@ -0,0 +1,22 @@ +package util + +import ( + "testing" +) + +func TestToShortFileName(t *testing.T) { + tests := []struct { + in string + value string + }{ + {"/data/a/b/c/d.txt", "/data/a/b/c/d.txt"}, + {"/data/a/b/c/очень_длинное_имя_файла_c_подробным_указанием_наименования_и_содержания_стандартизованных_форм_за_анварь_-_июнь_2023_года(РОГА_И_КОПЫТА_ООО).txt", "/data/a/b/c/очень_длинное_имя_файла_c_подробным_указанием_наименования_и_содержания_стандартизованных_форм_за_анварь_-_июнь_2023_года(РОГА_И_КОПЫТ354fcaf4.txt"}, + {"/data/a/b/c/очень_длинное_имя_файла_c_подробным_указанием_наименования_и_содержания_стандартизованных_форм_за_анварь_-_июнь_2023_года(РОГА_И_КОПЫТА_ООО)_without_extension", "/data/a/b/c/очень_длинное_имя_файла_c_подробным_указанием_наименования_и_содержания_стандартизованных_форм_за_анварь_-_июнь_2023_года(РОГА_И_КОПЫТА_О21a6e47a"}, + } + for _, p := range tests { + got := ToShortFileName(p.in) + if got != p.value { + t.Errorf("failed to test: got %v, want %v", got, p.value) + } + } +}