From a9f0659f2f4bf910f82b652fd27a864074ec7ab8 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 29 Dec 2017 21:23:06 +0000 Subject: [PATCH] lib/fs: Handle deduplicated files on NTFS (fixes #1845) These files always have the symlink bit set, because they are reparse points. Nonetheless they are not symlinks, and Lstat reports a size for them. We use this fact to disambiguate, and hope fervently that nothing else matches this description so it comes back to bite us... GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4622 --- lib/fs/basicfs.go | 12 +++++------- lib/fs/filesystem.go | 2 ++ lib/fs/fsfileinfo_unix.go | 13 +++++++++++++ lib/fs/fsfileinfo_windows.go | 21 +++++++++++++++++++++ 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 lib/fs/fsfileinfo_unix.go create mode 100644 lib/fs/fsfileinfo_windows.go diff --git a/lib/fs/basicfs.go b/lib/fs/basicfs.go index 4a0dc0919..8736d621b 100644 --- a/lib/fs/basicfs.go +++ b/lib/fs/basicfs.go @@ -322,14 +322,12 @@ type fsFileInfo struct { os.FileInfo } -func (e fsFileInfo) Mode() FileMode { - return FileMode(e.FileInfo.Mode()) +func (e fsFileInfo) IsSymlink() bool { + // Must use fsFileInfo.Mode() because it may apply magic. + return e.Mode()&ModeSymlink != 0 } func (e fsFileInfo) IsRegular() bool { - return e.FileInfo.Mode().IsRegular() -} - -func (e fsFileInfo) IsSymlink() bool { - return e.FileInfo.Mode()&os.ModeSymlink == os.ModeSymlink + // Must use fsFileInfo.Mode() because it may apply magic. + return e.Mode()&ModeType == 0 } diff --git a/lib/fs/filesystem.go b/lib/fs/filesystem.go index fe267ac00..346dd2548 100644 --- a/lib/fs/filesystem.go +++ b/lib/fs/filesystem.go @@ -126,6 +126,8 @@ const ModePerm = FileMode(os.ModePerm) const ModeSetgid = FileMode(os.ModeSetgid) const ModeSetuid = FileMode(os.ModeSetuid) const ModeSticky = FileMode(os.ModeSticky) +const ModeSymlink = FileMode(os.ModeSymlink) +const ModeType = FileMode(os.ModeType) const PathSeparator = os.PathSeparator const OptAppend = os.O_APPEND const OptCreate = os.O_CREATE diff --git a/lib/fs/fsfileinfo_unix.go b/lib/fs/fsfileinfo_unix.go new file mode 100644 index 000000000..96b1a392f --- /dev/null +++ b/lib/fs/fsfileinfo_unix.go @@ -0,0 +1,13 @@ +// Copyright (C) 2017 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +// +build !windows + +package fs + +func (e fsFileInfo) Mode() FileMode { + return FileMode(e.FileInfo.Mode()) +} diff --git a/lib/fs/fsfileinfo_windows.go b/lib/fs/fsfileinfo_windows.go new file mode 100644 index 000000000..fdd524d1c --- /dev/null +++ b/lib/fs/fsfileinfo_windows.go @@ -0,0 +1,21 @@ +// Copyright (C) 2017 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +package fs + +import ( + "os" +) + +func (e fsFileInfo) Mode() FileMode { + m := e.FileInfo.Mode() + if m&os.ModeSymlink != 0 && e.Size() > 0 { + // "Symlinks" with nonzero size are in fact "hard" links, such as + // NTFS deduped files. Remove the symlink bit. + m &^= os.ModeSymlink + } + return FileMode(m) +}