84 lines
1.8 KiB
Go
84 lines
1.8 KiB
Go
//go:build windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// packTree hands the tree under root to sink (packWorktree says why it is
|
|
// walked this way). Every name is opened through an os.Root at the tree, so
|
|
// no link, junction or name swapped in while it is packed can open a file
|
|
// outside the tree; an entry goes in only if the opened file is the plain
|
|
// file or folder that was looked at. Each left-out entry goes to sink.skip.
|
|
func packTree(sink treeSink, root string) error {
|
|
r, err := os.OpenRoot(root)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer r.Close()
|
|
return packRootFolder(sink, r, "", 0)
|
|
}
|
|
|
|
func packRootFolder(sink treeSink, r *os.Root, rel string, depth int) error {
|
|
open := rel
|
|
if open == "" {
|
|
open = "."
|
|
}
|
|
d, err := r.Open(open)
|
|
if err != nil {
|
|
return fmt.Errorf("open folder %q: %w", rel, err)
|
|
}
|
|
names, err := readTreeNames(sink, d, filepath.ToSlash(rel))
|
|
d.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := sink.folder(filepath.ToSlash(rel), names); err != nil {
|
|
return err
|
|
}
|
|
for _, name := range names {
|
|
p := filepath.Join(rel, name)
|
|
tp := filepath.ToSlash(p)
|
|
seen, err := r.Lstat(p)
|
|
if err != nil {
|
|
sink.skip(tp)
|
|
continue
|
|
}
|
|
if seen.IsDir() && name == ".git" {
|
|
continue
|
|
}
|
|
if (!seen.Mode().IsRegular() && !seen.IsDir()) || (seen.IsDir() && depth >= maxTreeDepth) {
|
|
sink.skip(tp)
|
|
continue
|
|
}
|
|
if packTreeBeforeOpen != nil {
|
|
packTreeBeforeOpen(tp)
|
|
}
|
|
f, err := r.Open(p)
|
|
if err != nil {
|
|
sink.skip(tp)
|
|
continue
|
|
}
|
|
fi, err := f.Stat()
|
|
if err != nil || fi.Mode().Type() != seen.Mode().Type() {
|
|
f.Close()
|
|
sink.skip(tp)
|
|
continue
|
|
}
|
|
err = sink.put(f, fi, tp)
|
|
f.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if fi.IsDir() {
|
|
if err := packRootFolder(sink, r, p, depth+1); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|