// process entry of given name in current directory; recursively descend if // entry names a directory and the recursive flag is set func processInputs(entry, accumulatedPath string) { var err error var info os.FileInfo if info, err = statFunction(entry); err != nil { myerr.MyError("error: %s", err) return } // skip over non-regular files and non-directories if 0 != info.Mode()&(os.ModeSymlink|os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) { return } if info.IsDir() { if !*recursive { myerr.MyError("%s is a directory without recursive flag", accumulatedPath) return } var thisDir string if thisDir, err = os.Getwd(); err != nil { myerr.MyPanic(err) } myerr.MyPanic(os.Chdir(entry)) defer func() { myerr.MyPanic(os.Chdir(thisDir)) }() var f *os.File if f, err = os.Open("."); err != nil { myerr.MyError("error: could not open directory %s; %s", accumulatedPath, err) return } var entries_info []os.FileInfo if entries_info, err = f.Readdir(-1); err != nil { myerr.MyPanic(f.Close()) myerr.MyError("error: could not read directory %s; %s", accumulatedPath, err) return } myerr.MyPanic(f.Close()) for _, entry := range entries_info { newAccumulatedPath := fmt.Sprintf("%s%c%s", accumulatedPath, os.PathSeparator, entry.Name()) processInputs(entry.Name(), newAccumulatedPath) } } else { var f *os.File var e error if f, e = os.Open(entry); e != nil { myerr.MyError("warning: could not open %s; skipping", accumulatedPath) return } defer func() { f.Close() }() processReader(accumulatedPath, f, info.Size()) } }
func main() { defer myerr.MyDefer() var err error flag.Var(&fromBytes, "fromb", "bytes to replace; used to make sure you don't overwrite wrong data; e.g., \"-b 00ff00AA\"") flag.Var(&toBytes, "tob", "replacement bytes; e.g., \"-b 0FE32d17\"") flag.Parse() // scan the arguments list if len(*fromString) != 0 { if len(fromBytes) == 0 { fromBytes = []byte(*fromString) } else { myerr.MyFatal(status_fatal_error, "error: specified both -from and -fromb parameters") return } } if len(*toString) != 0 { if len(toBytes) == 0 { toBytes = []byte(*toString) } else { myerr.MyFatal(status_fatal_error, "error: specified both -to and -tob parameters") return } } else if len(toBytes) == 0 { myerr.MyFatal(status_fatal_error, "error: must specify either -to or -tob parameter") return } if len(fromBytes) != 0 && len(fromBytes) != len(toBytes) { myerr.MyFatal(status_fatal_error, "error: if you specify -from or -fromb it must be the same size as -to or -tob; %d is not equal to %d", len(fromBytes), len(toBytes)) return } var inFileName string positions := NewUint64Slice() gotError := false for i, arg := range flag.Args() { if i == 0 { inFileName = arg } else { var v uint64 v, err = strconv.ParseUint(arg, 10, 64) if err != nil { myerr.MyError("error: trying to parse \"%s\" as an offset; got %s", arg, err) gotError = true } else { positions = append(positions, v) } } } sort.Sort(positions) if gotError { myerr.MyFatal(status_fatal_error, "must exit due to errors") return } inFile, oe := os.Open(inFileName) if oe != nil { myerr.MyFatal(status_fatal_error, "could not open file \"%s\"; %s", inFileName, oe) } defer func() { inFile.Close() }() outFileName, outFile, oe2 := makeTempFile(inFileName, "tmp") if oe2 != nil { myerr.MyFatal(status_fatal_error, "%s", oe2) } complete := false defer func() { outFile.Close() if complete { var mode os.FileMode if fi, e := inFile.Stat(); e == nil { mode = fi.Mode() } else { myerr.MyPanic(e) } var backupName string var backupFile *os.File backupName, backupFile, err = makeTempFile(inFileName, "backup") myerr.MyPanic(err) err = backupFile.Close() myerr.MyPanic(err) err = os.Rename(inFileName, backupName) myerr.MyPanic(err) err = os.Rename(outFileName, inFileName) myerr.MyPanic(err) err = os.Chmod(inFileName, mode) myerr.MyPanic(err) } else { err = os.Remove(outFileName) } }() if _, err = io.Copy(outFile, inFile); err != nil { myerr.MyFatal(status_fatal_error, "error: %s", err) return } buffer := make([]byte, len(fromBytes), len(fromBytes)) for _, offset := range positions { skip := false if len(fromBytes) != 0 { _, err = outFile.ReadAt(buffer, int64(offset)) myerr.MyPanic(err) if !sameBytes(fromBytes, buffer) { fmt.Printf("warning: not same at offset %d; skipping\n", offset) skip = true } } if !skip { _, err = outFile.WriteAt(toBytes, int64(offset)) myerr.MyPanic(err) } } complete = true }