]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Shortened long filenames
authorSergey Matveev <stargrave@stargrave.org>
Tue, 29 Nov 2022 11:21:35 +0000 (14:21 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 13 Jan 2023 08:32:42 +0000 (11:32 +0300)
cmd/btrtrc/README
cmd/btrtrc/fifos.go
storage/file.go
storage/shortener.go [new file with mode: 0644]

index d485409d57c57f3471c8911698d24dbd02ab5c8e..8e7b15c2ee85194441a338d8a25991387183673e 100644 (file)
@@ -9,6 +9,7 @@ the file to delete. But what advantages does it have?
 * Optimized file-based storage:
   * linearized I/O operations prevent creation of huge quantity of threads
   * cached file descriptors save a lot of syscalls
+* Shortened long filenames in file-based storage
 * Ability to specify both IPv4 and IPv6 addresses to announce
 * Ability to specify DHT bootstrap nodes
 * Dynamic addition and removing of the torrents
index f9aa0117d4d32ba9a8099c09fef6348686f7a100..508f6c097df54708120a39073ec056af6c551eaa 100644 (file)
@@ -18,6 +18,7 @@ import (
        "github.com/anacrolix/dht/v2"
        "github.com/anacrolix/torrent"
        "github.com/anacrolix/torrent/metainfo"
+       "github.com/anacrolix/torrent/storage"
        "github.com/anacrolix/torrent/types/infohash"
        "github.com/dustin/go-humanize"
 )
@@ -304,7 +305,7 @@ func readLinesFromFIFO(pth string) []string {
 }
 
 func saveTorrent(t *torrent.Torrent) error {
-       pth := t.Name() + TorrentExt
+       pth := storage.PathShortener(t.Name()) + TorrentExt
        if _, err := os.Stat(pth); err == nil {
                return nil
        }
index aa67df15f486f463fd3a47554ecc83d0691009dc..6871cad31a06cbe84754dc78a848379daa3e7024 100644 (file)
@@ -115,7 +115,7 @@ func (fs fileClientImpl) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash
                        length: fileInfo.Length,
                }
                if f.length == 0 {
-                       err = CreateNativeZeroLengthFile(f.path)
+                       err = CreateNativeZeroLengthFile(PathShortener(f.path))
                        if err != nil {
                                err = fmt.Errorf("creating zero length file: %w", err)
                                return
@@ -185,10 +185,11 @@ type fileTorrentImplIO struct {
 // Returns EOF on short or missing file.
 func (fst *fileTorrentImplIO) readFileAt(file file, b []byte, off int64) (n int, err error) {
        fdRCacheM.Lock()
-       centry := fdRCache[file.path]
+       pth := PathShortener(file.path)
+       centry := fdRCache[pth]
        if centry == nil {
                var fd *os.File
-               fd, err = os.Open(file.path)
+               fd, err = os.Open(pth)
                if os.IsNotExist(err) {
                        // File missing is treated the same as a short file.
                        err = io.EOF
@@ -198,7 +199,7 @@ func (fst *fileTorrentImplIO) readFileAt(file file, b []byte, off int64) (n int,
                        return
                }
                centry = &fdCacheEntry{fd: fd}
-               fdRCache[file.path] = centry
+               fdRCache[pth] = centry
        }
        fdRCacheM.Unlock()
        // Limit the read to within the expected bounds of this file.
@@ -229,7 +230,7 @@ func (fst fileTorrentImplIO) ReadAt(b []byte, off int64) (n int, err error) {
 
 func (fst fileTorrentImplIO) WriteAt(p []byte, off int64) (n int, err error) {
        fst.fts.segmentLocater.Locate(segments.Extent{off, int64(len(p))}, func(i int, e segments.Extent) bool {
-               name := fst.fts.files[i].path
+               name := PathShortener(fst.fts.files[i].path)
                _, ok := fdMkdirAllCache[filepath.Dir(name)]
                if !ok {
                        os.MkdirAll(filepath.Dir(name), 0o777)
diff --git a/storage/shortener.go b/storage/shortener.go
new file mode 100644 (file)
index 0000000..e3ed5df
--- /dev/null
@@ -0,0 +1,30 @@
+package storage
+
+import (
+       "crypto/sha1"
+       "encoding/hex"
+       "path"
+       "strings"
+       "unicode/utf8"
+)
+
+const MaxFilenameLen = 200
+
+func PathShortener(pth string) string {
+       parts := strings.Split(pth, "/")
+       for i, part := range parts {
+               if len(part) <= MaxFilenameLen {
+                       continue
+               }
+               n := 0
+               var short []rune
+               for (n < len(part)) && (len(string(short)) <= MaxFilenameLen) {
+                       r, w := utf8.DecodeRuneInString(part[n:])
+                       n += w
+                       short = append(short, r)
+               }
+               h := sha1.Sum([]byte(part))
+               parts[i] = string(short[:len(short)-1]) + "-" + hex.EncodeToString(h[:])
+       }
+       return path.Join(parts...)
+}