func BlockHandler(store fs.LocalStore) http.HandlerFunc { return func(resp http.ResponseWriter, req *http.Request) { setBinaryResp(resp) strong, hasVar := mux.Vars(req)["strong"] if !hasVar { writeResponseError(resp, http.StatusInternalServerError, "Missing parameter: strong") return } if !hasVar { resp.WriteHeader(http.StatusNotFound) return } buf, err := store.ReadBlock(strong) if err != nil { writeResponseError(resp, http.StatusInternalServerError, err.String()) return } resp.Write(buf) } }
func FileHandler(store fs.LocalStore) http.HandlerFunc { return func(resp http.ResponseWriter, req *http.Request) { setBinaryResp(resp) strong, hasStrong := mux.Vars(req)["strong"] if !hasStrong { writeResponseError(resp, http.StatusInternalServerError, "Missing parameter: strong") return } offsetStr, hasOffset := mux.Vars(req)["offset"] if !hasOffset { writeResponseError(resp, http.StatusInternalServerError, "Missing parameter: offset") return } offset, err := strconv.Atoi64(offsetStr) if err != nil { writeResponseError(resp, http.StatusInternalServerError, fmt.Sprintf("Invalid format for length: %s", offsetStr)) return } lengthStr, hasLength := mux.Vars(req)["length"] if !hasLength { writeResponseError(resp, http.StatusInternalServerError, "Missing parameter: length") return } length, err := strconv.Atoi64(lengthStr) if err != nil { writeResponseError(resp, http.StatusInternalServerError, fmt.Sprintf("Invalid format for length: %s", lengthStr)) return } buffer := bytes.NewBuffer([]byte{}) n, err := store.ReadInto(strong, offset, length, buffer) if err != nil { writeResponseError(resp, http.StatusInternalServerError, err.String()) return } if n < length { writeResponseError(resp, http.StatusInternalServerError, io.ErrShortWrite.String()) } resp.Write(buffer.Bytes()) } }
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.Repo().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.Repo().Root(), func(srcNode fs.Node) bool { // Ignore non-FsNodes srcFsNode, isSrcFsNode := srcNode.(fs.FsNode) if !isSrcFsNode { return false } // log.Printf("In src: %s", fs.RelPath(srcFsNode)) srcFile, isSrcFile := srcNode.(fs.File) srcPath := fs.RelPath(srcFsNode) // Remove this srcPath from dst unmatched, if it was present plan.dstFileUnmatch[srcPath] = nil, false var srcStrong string if isSrcFile { srcStrong = srcFile.Info().Strong } else if srcDir, isSrcDir := srcNode.(fs.Dir); isSrcDir { srcStrong = srcDir.Info().Strong } var dstNode fs.FsNode var hasDstNode bool dstNode, hasDstNode = dstStore.Repo().File(srcStrong) if !hasDstNode { dstNode, hasDstNode = dstStore.Repo().Dir(srcStrong) } isDstFile := false if hasDstNode { _, isDstFile = dstNode.(fs.File) } dstFilePath := dstStore.Resolve(srcPath) dstFileInfo, _ := os.Stat(dstFilePath) // 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 // log.Printf("srcPath=%s dstPath=%s", srcPath, dstPath) 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 }