Skip to content

Commit ede7af4

Browse files
committed
buffer: Store potential resolved symlinks as AbsPath
Otherwise we can't identify if we have the same file open multiple times via different symlinks. Additionally this will also store the buffer backup and serialized buffer for the same target file just once.
1 parent 3a7403b commit ede7af4

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

internal/buffer/buffer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ func NewBuffer(r io.Reader, size int64, path string, btype BufType, cmd Command)
360360
absPath = path
361361
}
362362

363+
// Ignore the returned error, since the checks are already performed in
364+
// NewBufferFromFileWithCommand()
365+
absPath, _ = util.ResolveSymlinks(absPath)
366+
363367
b := new(Buffer)
364368

365369
found := false

internal/buffer/save.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,9 @@ func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error
336336
}
337337

338338
b.Path = filename
339-
b.AbsPath = absFilename
339+
// Ignore the returned error, since the checks are already performed in
340+
// above
341+
b.AbsPath, _ = util.ResolveSymlinks(absFilename)
340342
b.isModified = false
341343
b.UpdateModTime()
342344

internal/util/util.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,36 @@ func HttpRequest(method string, url string, headers []string) (resp *http.Respon
662662
return client.Do(req)
663663
}
664664

665+
func ResolveSymlinks(filename string) (string, error) {
666+
// We use Stat() as trick to let the OS do symlink loop detection for us,
667+
// since we are lazy to do it ourselves
668+
fileInfo, err := os.Stat(filename)
669+
if errors.Is(err, fs.ErrNotExist) {
670+
return filename, nil
671+
}
672+
if err != nil {
673+
return filename, err
674+
}
675+
676+
for {
677+
fileInfo, err = os.Lstat(filename)
678+
if err != nil {
679+
return filename, err
680+
}
681+
if fileInfo.Mode()&os.ModeSymlink != 0 {
682+
dstFilename, err := os.Readlink(filename)
683+
if err != nil {
684+
return filename, err
685+
}
686+
if !filepath.IsAbs(dstFilename) {
687+
filename = filepath.Join(filepath.Dir(filename), dstFilename)
688+
continue
689+
}
690+
}
691+
return filename, nil
692+
}
693+
}
694+
665695
// SafeWrite writes bytes to a file in a "safe" way, preventing loss of the
666696
// contents of the file if it fails to write the new contents.
667697
// This means that the file is not overwritten directly but by writing to a

0 commit comments

Comments
 (0)