syncthing/walk.go

148 lines
2.6 KiB
Go
Raw Normal View History

2013-12-15 10:43:31 +00:00
package main
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
)
const BlockSize = 128 * 1024
type File struct {
Name string
Flags uint32
Modified int64
Blocks BlockList
}
func (f File) Dump() {
fmt.Printf("%s\n", f.Name)
for _, b := range f.Blocks {
fmt.Printf(" %dB @ %d: %x\n", b.Length, b.Offset, b.Hash)
}
fmt.Println()
}
2013-12-30 14:30:29 +00:00
func (f File) Size() (bytes int) {
for _, b := range f.Blocks {
bytes += int(b.Length)
}
return
}
2013-12-15 10:43:31 +00:00
func isTempName(name string) bool {
return strings.HasPrefix(path.Base(name), ".syncthing.")
}
func tempName(name string, modified int64) string {
tdir := path.Dir(name)
tname := fmt.Sprintf(".syncthing.%s.%d", path.Base(name), modified)
return path.Join(tdir, tname)
}
func genWalker(base string, res *[]File, model *Model) filepath.WalkFunc {
return func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if isTempName(p) {
return nil
}
if info.Mode()&os.ModeType == 0 {
rn, err := filepath.Rel(base, p)
if err != nil {
return err
}
fi, err := os.Stat(p)
if err != nil {
return err
}
modified := fi.ModTime().Unix()
hf, ok := model.LocalFile(rn)
if ok && hf.Modified == modified {
// No change
*res = append(*res, hf)
} else {
2013-12-18 18:36:28 +00:00
if opts.Debug.TraceFile {
2013-12-15 10:43:31 +00:00
debugf("FILE: Hash %q", p)
}
fd, err := os.Open(p)
if err != nil {
return err
}
defer fd.Close()
blocks, err := Blocks(fd, BlockSize)
if err != nil {
return err
}
f := File{
Name: rn,
Flags: uint32(info.Mode()),
Modified: modified,
Blocks: blocks,
}
*res = append(*res, f)
}
}
return nil
}
}
2013-12-15 20:20:50 +00:00
func Walk(dir string, model *Model, followSymlinks bool) []File {
2013-12-15 10:43:31 +00:00
var files []File
fn := genWalker(dir, &files, model)
err := filepath.Walk(dir, fn)
if err != nil {
warnln(err)
}
2013-12-15 20:20:50 +00:00
2013-12-18 18:36:28 +00:00
if !opts.NoSymlinks {
2013-12-15 20:20:50 +00:00
d, err := os.Open(dir)
if err != nil {
warnln(err)
return files
}
fis, err := d.Readdir(-1)
if err != nil {
warnln(err)
return files
}
d.Close()
for _, fi := range fis {
if fi.Mode()&os.ModeSymlink != 0 {
err := filepath.Walk(path.Join(dir, fi.Name())+"/", fn)
if err != nil {
warnln(err)
}
}
}
}
2013-12-15 10:43:31 +00:00
return files
}
func cleanTempFile(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.Mode()&os.ModeType == 0 && isTempName(path) {
2013-12-18 18:36:28 +00:00
if opts.Debug.TraceFile {
2013-12-15 10:43:31 +00:00
debugf("FILE: Remove %q", path)
}
os.Remove(path)
}
return nil
}
func CleanTempFiles(dir string) {
filepath.Walk(dir, cleanTempFile)
}