Skip to content

Commit

Permalink
check original file if open
Browse files Browse the repository at this point in the history
  • Loading branch information
Son Roy Almerol committed Nov 14, 2024
1 parent 5e916f2 commit 2987f01
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 3 deletions.
16 changes: 16 additions & 0 deletions internal/agent/sftp/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
package sftp

import (
"os"
"regexp"
"strings"
"time"
"unicode"
)

Expand Down Expand Up @@ -121,6 +123,16 @@ func compileExcludedPaths() []*regexp.Regexp {
var excludedPathRegexes = compileExcludedPaths()

func (h *SftpHandler) skipFile(path string) bool {
stat, err := os.Lstat(path)
if err != nil {
return true
}

// skip probably opened files
if h.Snapshot.TimeStarted.Sub(stat.ModTime()) <= time.Minute {
return true
}

snapSplit := strings.Split(h.Snapshot.SnapshotPath, "\\")
snapRoot := strings.Join(snapSplit[:len(snapSplit)-1], "\\")

Expand All @@ -142,5 +154,9 @@ func (h *SftpHandler) skipFile(path string) bool {
return true
}

if isFileOpen(strings.Replace(pathWithoutSnap, "\\", ":\\", 1)) {
return true
}

return false
}
33 changes: 33 additions & 0 deletions internal/agent/sftp/windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package sftp

import (
"os"
"syscall"
"unsafe"

"golang.org/x/sys/windows"
Expand Down Expand Up @@ -58,3 +59,35 @@ func invalidAttributes(path string) (bool, error) {

return false, nil
}

const ERROR_SHARING_VIOLATION syscall.Errno = 32

func isFileOpen(path string) bool {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return false
}

// Use CreateFileW system call to open the file with read-write and exclusive access
// FILE_SHARE_NONE ensures that the file cannot be opened by any other process
h, err := syscall.CreateFile(
p,
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
0,
nil,
syscall.OPEN_EXISTING,
syscall.FILE_ATTRIBUTE_NORMAL,
0,
)

if err != nil {
// ERROR_SHARING_VIOLATION means the file is already open by another process
if errno, ok := err.(syscall.Errno); ok && errno == ERROR_SHARING_VIOLATION {
return true
}
return false
}

syscall.CloseHandle(h)
return false
}
1 change: 1 addition & 0 deletions internal/agent/snapshots/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type WinVSSSnapshot struct {
SnapshotPath string `json:"path"`
Id string `json:"vss_id"`
LastAccessed time.Time `json:"last_accessed"`
TimeStarted time.Time `json:"time_started"`
}

type KnownSnapshots struct {
Expand Down
4 changes: 4 additions & 0 deletions internal/agent/snapshots/windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func Snapshot(driveLetter string) (*WinVSSSnapshot, error) {
_ = os.Remove(snapshotPath)
}

timeStarted := time.Now()
// Attempt to create a new snapshot
err = vss.CreateLink(snapshotPath, volName)
if err != nil {
Expand All @@ -59,6 +60,8 @@ func Snapshot(driveLetter string) (*WinVSSSnapshot, error) {
} else if strings.Contains(err.Error(), "already exists") {
_ = vss.Remove(snapshotPath)
_ = os.Remove(snapshotPath)

timeStarted = time.Now()
err = vss.CreateLink(snapshotPath, volName)
if err != nil {
return nil, fmt.Errorf("Snapshot: error creating snapshot (%s to %s) -> %w", volName, snapshotPath, err)
Expand All @@ -80,6 +83,7 @@ func Snapshot(driveLetter string) (*WinVSSSnapshot, error) {
SnapshotPath: snapshotPath,
LastAccessed: time.Now(),
Id: sc.ID,
TimeStarted: timeStarted,
}
knownSnaps.Save(newSnapshot)

Expand Down
5 changes: 2 additions & 3 deletions internal/backend/mount/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ func Mount(target *store.Target) (*AgentMount, error) {
"--daemon",
"--no-seek",
"--read-only",
"--direct-io",
"--uid", "0",
"--gid", "0",
"--vfs-read-chunk-size", "0",
"--vfs-cache-mode", "minimal",
"--sftp-disable-hashcheck",
"--sftp-idle-timeout", "0",
"--sftp-key-file", privKeyFile,
Expand All @@ -75,7 +74,7 @@ func Mount(target *store.Target) (*AgentMount, error) {

agentMount.Cmd = mnt

err = mnt.Start()
err = mnt.Run()
if err != nil {
agentMount.Unmount()
return nil, fmt.Errorf("Mount: error starting rclone for sftp -> %w", err)
Expand Down

0 comments on commit 2987f01

Please sign in to comment.