package main import ( "flag" "log" "os" "path" "path/filepath" "strings" "syscall" ) var TmpDir string type Ent struct { name []string mtime int64 size int64 } func (ent *Ent) IsDir() bool { return IsDir(ent.name[len(ent.name)-1]) } func dbCommit(dbPath string, tmp *os.File) { umask := syscall.Umask(0) syscall.Umask(umask) if err := os.Chmod(tmp.Name(), os.FileMode(0666&^umask)); err != nil { log.Fatalln(err) } if err := os.Rename(tmp.Name(), dbPath); err != nil { log.Fatalln(err) } } func main() { dbPath := flag.String("db", "glocate.db", "Path to database") doIndex := flag.Bool("index", false, "Perform indexing") doUpdate := flag.String("update", "", "Update database") showMachine := flag.Bool("machine", false, "Show machine friendly") showTree := flag.Bool("tree", false, "Show human-friendly tree") dryRun := flag.Bool("n", false, "Dry run, do not overwrite database") rootPath := flag.String("root", "", "Search only that part of tree") flag.Parse() log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile) var err error TmpDir, err = filepath.Abs(*dbPath) if err != nil { panic(err) } TmpDir = path.Dir(TmpDir) if *doIndex { tmp := index() tmp.Close() if !*dryRun { dbCommit(*dbPath, tmp) } return } if *doUpdate != "" { tmp := updateWithDiff(*dbPath, *doUpdate) tmp.Close() if !*dryRun { dbCommit(*dbPath, tmp) } return } db, err := os.Open(*dbPath) if err != nil { log.Fatalln(err) } entsReader := make(chan Ent, 1<<10) go reader(db, entsReader) entsPrinter := make(chan Ent, 1<<10) printerJob := make(chan struct{}) go func() { if *showMachine { printerMachine(entsPrinter) } else if *showTree { printerTree(entsPrinter) } else { printerSimple(entsPrinter) } close(printerJob) }() var root []string if *rootPath != "" { root = strings.Split("./"+*rootPath, "/") } var pat string if len(flag.Args()) > 0 { pat = "*" + flag.Arg(0) + "*" } rootMet := false var matched bool var namePrev []string var i int for ent := range entsReader { if hasPrefix(ent.name, root) { rootMet = true if pat == "" { entsPrinter <- ent continue } for i = 0; i < len(ent.name); i++ { if i == len(namePrev) || ent.name[i] != namePrev[i] { break } } for ; i < len(ent.name); i++ { matched, err = path.Match(pat, strings.ToLower(strings.TrimSuffix(ent.name[i], "/"))) if err != nil { log.Fatalln(err) } } if matched { entsPrinter <- ent } namePrev = ent.name } else if rootMet { break } } close(entsPrinter) <-printerJob }