func restoreFiles(inputDir string, outputDir string) { doc, err := readIndex(getExistingIndexFilename(inputDir)) utils.PanicIfErr(err) if len(*restorePattern) != 0 { utils.Info.Printf("using restore pattern %s", *restorePattern) } out := []string{ "@echo off", "", "chcp 65001 >NUL", "", } restoreCommands, noFiles := getRestorePathsCommands(inputDir, outputDir, doc) out = append(out, restoreCommands...) if len(*restorePattern) == 0 { utils.Info.Printf("restored %d files", len(doc.Files)) } else { utils.Info.Printf("restored %d out of %d files", noFiles, len(doc.Files)) } out = append(out, "pause") err = os.MkdirAll(outputDir, 0700) utils.PanicIfErr(err) data := []byte(strings.Join(out, "\r\n")) utils.MustWriteFile(filepath.Join(outputDir, outputScriptfile), data) utils.MustWriteFile(filepath.Join(outputDir, passwordFile), []byte(doc.KeyUnencrypted)) }
func saveIndex(filename string, doc *models.Document) { utils.Info.Println("writing to index") encryptIndexKey(doc, getPassword()) data, err := json.MarshalIndent(doc, "", "\t") utils.PanicIfErr(err) if !*noIndexZip { data = utils.CompressData(data) } if !*noIndexEnc { data = utils.EncryptData(data, getPassword()) } tempFilename := filename + utils.TmpSuffix utils.MustWriteFile(tempFilename, data) utils.Info.Println("validating index") err = validateIndex(tempFilename, doc) utils.PanicIfErr(err) err = os.Rename(tempFilename, filename) utils.PanicIfErr(err) }
func pruneFiles(inputDir string, pruneRangeStr string) { doc, err := readIndex(getExistingIndexFilename(inputDir)) utils.PanicIfErr(err) pruneRange, err := utils.ParseHumanRange(pruneRangeStr) utils.PanicIfErr(err) pruneThreshold := time.Now().Add(-pruneRange) utils.Info.Printf("pruning files that were found to be deleted before %s (%s ago)\n", pruneThreshold, pruneRange) var prunedFiles uint64 for shortPath, versions := range doc.DeletedFiles { newVersions := []models.File{} for _, file := range versions { if file.DeletedAt == nil { utils.Error.Printf("%s is marked deleted but has no delete date, setting to now\n", shortPath) file.DeletedAt = &models.JSONTime{Time: time.Now()} } if file.DeletedAt.Time.After(pruneThreshold) { newVersions = append(newVersions, file) continue } prunedFiles++ } if len(newVersions) > 0 { doc.DeletedFiles[shortPath] = newVersions } else { delete(doc.DeletedFiles, shortPath) } } utils.Info.Printf("pruned %d files\n", prunedFiles) saveIndex(getIndexFilename(inputDir), doc) }
func getUnusedChunks(chunkIndex chunkIndexMap, directory string) []string { unusedChunks := []string{} encryptedIndexName := databaseFilename + EncSuffix walkFn := func(fullPath string, fileInfo os.FileInfo, err error) error { if fileInfo.IsDir() { return nil } filename := fileInfo.Name() if !strings.HasSuffix(filename, EncSuffix) { return nil } if filename == encryptedIndexName { return nil } chunkName := filename[:len(filename)-len(EncSuffix)] _, exists := chunkIndex[chunkName] if exists { return nil } relativePath, err := filepath.Rel(directory, fullPath) utils.PanicIfErr(err) unusedChunks = append(unusedChunks, relativePath) return nil } err := filepath.Walk(directory, walkFn) utils.PanicIfErr(err) return unusedChunks }
func garbageCollect(inputDir string) { doc, err := readIndex(getExistingIndexFilename(inputDir)) utils.PanicIfErr(err) utils.Info.Println("checking for unused chunks") chunkIndex := getChunkIndexMap(doc) unusedChunks := getUnusedChunks(chunkIndex, inputDir) createUnusedChunksDeleteBatch(unusedChunks, inputDir) if len(unusedChunks) > 0 { utils.Info.Printf("found %d unused chunks", len(unusedChunks)) } else { utils.Info.Printf("no unused chunks") } }