Skip to content

Commit d519e1c

Browse files
committed
sysdep: add support for darwin & windows
1 parent 4494092 commit d519e1c

7 files changed

Lines changed: 138 additions & 10 deletions

File tree

cmd/mypan/sync.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import (
1212
"path/filepath"
1313
"sort"
1414
"strings"
15-
"syscall"
1615

1716
"mypan/pkg/client"
1817
"mypan/pkg/config"
1918
"mypan/pkg/store"
19+
"mypan/pkg/sysdep"
2020
"mypan/pkg/util"
2121

2222
"github.com/golang/glog"
@@ -609,9 +609,10 @@ func (su *Sync) getOrSetSrcCacheEntry(ctx context.Context, srcAbsPath string) Sr
609609
if err != nil {
610610
return nil
611611
}
612-
var ino uint64
613-
if stat, ok := fi.Sys().(*syscall.Stat_t); ok {
614-
ino = stat.Ino
612+
ino, err := sysdep.FileIdByPath(srcAbsPath)
613+
if err != nil {
614+
glog.Warningf("fetch file id %s: %v", srcAbsPath, err)
615+
return nil
615616
}
616617

617618
// cache hit?

pkg/client/upload.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
"net/url"
1010
"os"
1111
"strconv"
12-
"syscall"
1312

13+
"mypan/pkg/sysdep"
1414
"mypan/pkg/util"
1515

1616
"github.com/pkg/errors"
@@ -54,11 +54,11 @@ func (client *Client) Upload(
5454
Size: fi.Size(),
5555
Mtime: fi.ModTime().Unix(),
5656
}
57-
switch fiSys := fi.Sys().(type) {
58-
case *syscall.Stat_t:
59-
statopt.Ctime = fiSys.Ctim.Sec
60-
default:
61-
client.vlog().Infof("unexpected stat type: %T", fiSys)
57+
ctime := sysdep.FileInfoGetCtime(fi)
58+
if ctime >= 0 {
59+
statopt.Ctime = ctime
60+
} else {
61+
client.vlog().Infof("fetch ctime failed, stat source: %T", fi.Sys())
6262
}
6363
if statopt.Size < MIN_SIZE_MULTIPART_UPLOAD {
6464
return client.uploadSingle(ctx, f, dst)

pkg/sysdep/stat.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2023 Yousong Zhou
3+
package sysdep
4+
5+
import "os"
6+
7+
func FileInfoGetCtime(fi os.FileInfo) int64 {
8+
sys := fi.Sys()
9+
sec := fiSysGetCtime(sys)
10+
return sec
11+
}
12+
13+
func FileIdByPath(p string) (uint64, error) {
14+
return fileIdByPath(p)
15+
}

pkg/sysdep/stat_darwin.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2023 Yousong Zhou
3+
package sysdep
4+
5+
import "syscall"
6+
7+
func fiSysGetCtime(sys any) int64 {
8+
st, ok := sys.(*syscall.Stat_t)
9+
if !ok {
10+
return -1
11+
}
12+
if st.Birthtimespec.Sec != 0 || st.Birthtimespec.Nsec != 0 {
13+
return st.Birthtimespec.Sec
14+
}
15+
return st.Ctimespec.Sec
16+
}

pkg/sysdep/stat_linux.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2023 Yousong Zhou
3+
4+
//go:build unix
5+
6+
package sysdep
7+
8+
import (
9+
"syscall"
10+
)
11+
12+
func fiSysGetCtime(sys any) int64 {
13+
st, ok := sys.(*syscall.Stat_t)
14+
if !ok {
15+
return -1
16+
}
17+
return int64(st.Ctim.Sec)
18+
}

pkg/sysdep/stat_unix.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2023 Yousong Zhou
3+
4+
//go:build unix
5+
6+
package sysdep
7+
8+
import (
9+
"fmt"
10+
"os"
11+
"syscall"
12+
)
13+
14+
func fileIdByPath(p string) (uint64, error) {
15+
fi, err := os.Stat(p)
16+
if err != nil {
17+
return 0, err
18+
}
19+
sys := fi.Sys()
20+
if stat, ok := sys.(*syscall.Stat_t); ok {
21+
return stat.Ino, nil
22+
} else {
23+
return 0, fmt.Errorf("unknown stat type: %T", sys)
24+
}
25+
}

pkg/sysdep/stat_windows.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2023 Yousong Zhou
3+
package sysdep
4+
5+
import (
6+
"syscall"
7+
)
8+
9+
func fiSysGetCtime(sys any) int64 {
10+
attr, ok := sys.(*syscall.Win32FileAttributeData)
11+
if !ok {
12+
return -1
13+
}
14+
nsec := attr.CreationTime.Nanoseconds()
15+
sec := nsec / (1e9)
16+
return sec
17+
}
18+
19+
func fileIdByPath(p string) (uint64, error) {
20+
pathp, err := syscall.UTF16PtrFromString(p)
21+
if err != nil {
22+
return 0, err
23+
}
24+
25+
// Per https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-points-and-file-operations,
26+
// “Applications that use the CreateFile function should specify the
27+
// FILE_FLAG_OPEN_REPARSE_POINT flag when opening the file if it is a reparse
28+
// point.”
29+
//
30+
// And per https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew,
31+
// “If the file is not a reparse point, then this flag is ignored.”
32+
//
33+
// So we set FILE_FLAG_OPEN_REPARSE_POINT unconditionally, since we want
34+
// information about the reparse point itself.
35+
//
36+
// If the file is a symlink, the symlink target should have already been
37+
// resolved when the fileStat was created, so we don't need to worry about
38+
// resolving symlink reparse points again here.
39+
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT)
40+
41+
h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
42+
if err != nil {
43+
return 0, err
44+
}
45+
defer syscall.CloseHandle(h)
46+
var i syscall.ByHandleFileInformation
47+
err = syscall.GetFileInformationByHandle(h, &i)
48+
if err != nil {
49+
return 0, err
50+
}
51+
fileIndex := (uint64(i.FileIndexHigh) << 32) | uint64(i.FileIndexLow)
52+
return fileIndex, nil
53+
}

0 commit comments

Comments
 (0)