func TreeHandler(store fs.LocalStore) http.HandlerFunc { return func(resp http.ResponseWriter, req *http.Request) { setBinaryResp(resp) // gob the root buffer := bytes.NewBuffer([]byte{}) encoder := gob.NewEncoder(buffer) err := encoder.Encode(store.Root()) if err != nil { writeResponseError(resp, http.StatusInternalServerError, err.String()) return } rootGob := buffer.Bytes() resp.Write(rootGob) } }
func NewPatchPlan(srcStore fs.BlockStore, dstStore *fs.LocalStore) *PatchPlan { plan := &PatchPlan{srcStore: srcStore, dstStore: dstStore} plan.dstFileUnmatch = make(map[string]*fs.File) fs.Walk(dstStore.Root(), func(dstNode fs.Node) bool { dstFile, isDstFile := dstNode.(*fs.File) if isDstFile { plan.dstFileUnmatch[fs.RelPath(dstFile)] = dstFile } return !isDstFile }) relocRefs := make(map[string]int) // Find all the FsNode matches fs.Walk(srcStore.Root(), func(srcNode fs.Node) bool { // Ignore non-FsNodes srcFsNode, isSrcFsNode := srcNode.(fs.FsNode) if !isSrcFsNode { return false } srcFile, isSrcFile := srcNode.(*fs.File) srcPath := fs.RelPath(srcFsNode) // Remove this srcPath from dst unmatched, if it was present delete(plan.dstFileUnmatch, srcPath) dstNode, hasDstNode := dstStore.Index().StrongFsNode(srcNode.Strong()) isDstFile := false if hasDstNode { _, isDstFile = dstNode.(*fs.File) } dstFilePath := dstStore.Resolve(srcPath) dstFileInfo, _ := os.Stat(dstFilePath) // fmt.Printf("srcPath=%s hasDstNode=%v isDstFsNode=%v isSrcFile=%v, isDstFile=%v\n%v\n\n", // srcPath, hasDstNode, isDstFsNode, isSrcFile, isDstFile, dstNode) // Resolve dst node that matches strong checksum with source if hasDstNode && isSrcFile == isDstFile { dstPath := fs.RelPath(dstNode) relocRefs[dstPath]++ // dstPath will be used in this cmd, inc ref count if srcPath != dstPath { // Local dst file needs to be renamed or copied to src path from := &LocalPath{LocalStore: dstStore, RelPath: dstPath} to := &LocalPath{LocalStore: dstStore, RelPath: srcPath} plan.Cmds = append(plan.Cmds, &Transfer{From: from, To: to, relocRefs: relocRefs}) } else { // Same path, keep it where it is plan.Cmds = append(plan.Cmds, &Keep{ Path: &LocalPath{LocalStore: dstStore, RelPath: srcPath}}) } // If its a file, figure out what to do with it } else if isSrcFile { switch { // Destination is not a file, so get rid of whatever is there first case dstFileInfo != nil && !dstFileInfo.IsRegular(): plan.Cmds = append(plan.Cmds, &Conflict{ Path: &LocalPath{LocalStore: dstStore, RelPath: srcPath}, FileInfo: dstFileInfo}) fallthrough // Destination file does not exist, so full source copy needed case dstFileInfo == nil: plan.Cmds = append(plan.Cmds, &SrcFileDownload{ SrcFile: srcFile, Path: &LocalPath{LocalStore: dstStore, RelPath: srcPath}}) break // Destination file exists, add block-level commands default: plan.appendFilePlan(srcFile, srcPath) break } // If its a directory, check for conflicting files of same name } else { if dstFileInfo != nil && !dstFileInfo.IsDirectory() { plan.Cmds = append(plan.Cmds, &Conflict{ Path: &LocalPath{LocalStore: dstStore, RelPath: dstFilePath}, FileInfo: dstFileInfo}) } } return !isSrcFile }) return plan }