/*
goredo -- djb's redo implementation on pure Go
-Copyright (C) 2020-2022 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2020-2023 Sergey Matveev <stargrave@stargrave.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
package main
import (
+ "bytes"
+ "encoding/hex"
"errors"
"io"
+ "io/fs"
"os"
"path"
"strings"
tracef(CDebug, "depfix: entering %s", root)
dir, err := os.Open(root)
if err != nil {
- return err
+ return ErrLine(err)
}
defer dir.Close()
for {
- fis, err := dir.Readdir(1 << 10)
+ entries, err := dir.ReadDir(1 << 10)
if err != nil {
if err == io.EOF {
break
}
- return err
+ return ErrLine(err)
}
- for _, fi := range fis {
- if fi.IsDir() {
- if err = depFix(path.Join(root, fi.Name())); err != nil {
+ for _, entry := range entries {
+ if entry.IsDir() {
+ if err = depFix(path.Join(root, entry.Name())); err != nil {
return err
}
}
redoDir := path.Join(root, RedoDir)
dir, err = os.Open(redoDir)
if err != nil {
- if os.IsNotExist(err) {
+ if errors.Is(err, fs.ErrNotExist) {
return nil
}
- return err
+ return ErrLine(err)
}
defer dir.Close()
redoDirChanged := false
for {
- fis, err := dir.Readdir(1 << 10)
+ entries, err := dir.ReadDir(1 << 10)
if err != nil {
if err == io.EOF {
break
}
- return err
+ return ErrLine(err)
}
- for _, fi := range fis {
- if !strings.HasSuffix(fi.Name(), DepSuffix) {
+ for _, entry := range entries {
+ if !strings.HasSuffix(entry.Name(), DepSuffix) {
continue
}
- tracef(CDebug, "depfix: checking %s/%s", root, fi.Name())
- fdDepPath := path.Join(redoDir, fi.Name())
+ tracef(CDebug, "depfix: checking %s/%s", root, entry.Name())
+ fdDepPath := path.Join(redoDir, entry.Name())
fdDep, err := os.Open(fdDepPath)
if err != nil {
- return err
+ return ErrLine(err)
}
defer fdDep.Close()
r := recfile.NewReader(fdDep)
if errors.Is(err, io.EOF) {
break
}
- return err
+ return ErrLine(err)
}
fieldses = append(fieldses, fields)
m := make(map[string]string, len(fields))
if dep == "" {
return ErrMissingTarget
}
- tracef(CDebug, "depfix: checking %s/%s -> %s", root, fi.Name(), dep)
+ tracef(CDebug, "depfix: checking %s/%s -> %s", root, entry.Name(), dep)
theirInode, err := inodeFromRec(m)
if err != nil {
- return err
+ return ErrLine(err)
}
- theirHsh := m["Hash"]
+ theirHsh := mustHexDecode(m["Hash"])
fd, err := os.Open(path.Join(root, dep))
if err != nil {
- if os.IsNotExist(err) {
+ if errors.Is(err, fs.ErrNotExist) {
tracef(
CDebug, "depfix: %s/%s -> %s: not exists",
- root, fi.Name(), dep,
+ root, entry.Name(), dep,
)
continue
}
- return err
+ return ErrLine(err)
}
- inode, err := inodeFromFileByFd(fd)
+ inode, _, err := inodeFromFileByFd(fd)
if err != nil {
fd.Close()
- return err
+ return ErrLine(err)
}
if inode.Size != theirInode.Size {
tracef(
CDebug, "depfix: %s/%s -> %s: size differs",
- root, fi.Name(), dep,
+ root, entry.Name(), dep,
)
fd.Close()
continue
if inode.Equals(theirInode) {
tracef(
CDebug, "depfix: %s/%s -> %s: inode is equal",
- root, fi.Name(), dep,
+ root, entry.Name(), dep,
)
fd.Close()
continue
hsh, err := fileHash(fd)
fd.Close()
if err != nil {
- return err
+ return ErrLine(err)
}
- if hsh != theirHsh {
+ if !bytes.Equal(hsh, theirHsh) {
tracef(
CDebug, "depfix: %s/%s -> %s: hash differs",
- root, fi.Name(), dep,
+ root, entry.Name(), dep,
)
continue
}
fields = []recfile.Field{
{Name: "Type", Value: DepTypeIfchange},
{Name: "Target", Value: dep},
- {Name: "Hash", Value: hsh},
+ {Name: "Hash", Value: hex.EncodeToString(hsh)},
}
fields = append(fields, inode.RecfileFields()...)
fieldses[len(fieldses)-1] = fields
tracef(
CDebug, "depfix: %s/%s -> %s: inode updated",
- root, fi.Name(), dep,
+ root, entry.Name(), dep,
)
depChanged = true
}
continue
}
redoDirChanged = true
- fdDep, err = tempfile(redoDir, fi.Name())
+ fdDep, err = tempfile(redoDir, entry.Name())
if err != nil {
- return err
+ return ErrLine(err)
}
defer fdDep.Close()
tracef(
CDebug, "depfix: %s/%s: tmp %s",
- root, fi.Name(), fdDep.Name(),
+ root, entry.Name(), fdDep.Name(),
)
w := recfile.NewWriter(fdDep)
if _, err := w.WriteFields(fieldses[0]...); err != nil {
- return err
+ return ErrLine(err)
}
fieldses = fieldses[1:]
for _, fields := range fieldses {
if _, err := w.RecordStart(); err != nil {
- return err
+ return ErrLine(err)
}
if _, err := w.WriteFields(fields...); err != nil {
- return err
+ return ErrLine(err)
}
}
if !NoSync {
if err = fdDep.Sync(); err != nil {
- return err
+ return ErrLine(err)
}
}
fdDep.Close()
if err = os.Rename(fdDep.Name(), fdDepPath); err != nil {
- return err
+ return ErrLine(err)
}
tracef(CRedo, "%s", fdDepPath)
}
}
if redoDirChanged && !NoSync {
if err = syncDir(redoDir); err != nil {
- return nil
+ return err
}
}
return nil