12345678module snapshot910import os11import src.storage1213pub struct RestoreReport {14pub:15 written int16 removed int17}1819202122232425pub fn restore_files(store &storage.Store, root string, ig Ignore, target []FileEntry, remove []string) !RestoreReport {26 mut wanted := map[string]bool{}27 for entry in target {28 wanted[entry.path] = true29 }30 mut removed := 031 for path in remove {32 full := os.join_path(root, path)33 if !os.is_file(full) || ig.matches(path, false) || path in wanted {34 continue35 }36 os.rm(full)!37 removed++38 prune_empty_dirs(root, os.dir(full))39 }40 41 42 43 for entry in target {44 full := os.join_path(root, entry.path)45 if os.is_dir(full) {46 os.rmdir(full) or {47 return error('${entry.path} is a folder of ignored files where a saved file belongs — move it, then run the command again')48 }49 }50 }51 mut written := 052 for entry in target {53 if ig.matches(entry.path, false) && os.exists(os.join_path(root, entry.path)) {54 continue55 }56 data := store.get_object(entry.hash)!57 write_file(os.join_path(root, entry.path), data, entry.executable)!58 written++59 }60 return RestoreReport{61 written: written62 removed: removed63 }64}6566fn write_file(path string, data []u8, executable bool) ! {67 os.mkdir_all(os.dir(path), os.MkdirParams{})!68 tmp := '${path}.koh-tmp-${os.getpid()}'69 os.write_file_array(tmp, data)!70 mode := if executable { 0o755 } else { 0o644 }71 os.chmod(tmp, mode)!72 os.rename(tmp, path)!73}747576fn prune_empty_dirs(root string, dir string) {77 mut current := dir78 for current.len > root.len && current.starts_with(root) {79 if (os.ls(current) or { return }).len > 0 {80 return81 }82 os.rmdir(current) or { return }83 current = os.dir(current)84 }85}