+/*
+goredo -- redo implementation on pure Go
+Copyright (C) 2020-2021 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
+the Free Software Foundation, version 3 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// Inode metainformation
+
+package main
+
+import (
+ "errors"
+ "os"
+ "strconv"
+
+ "go.cypherpunks.ru/recfile"
+ "golang.org/x/sys/unix"
+)
+
+type Inode struct {
+ Size int64
+ CtimeSec int64
+ CtimeNsec int64
+}
+
+func (our *Inode) Equals(their *Inode) bool {
+ return (our.Size == their.Size) &&
+ (our.CtimeSec == their.CtimeSec) &&
+ (our.CtimeNsec == their.CtimeNsec)
+}
+
+func (inode *Inode) RecfileFields() []recfile.Field {
+ return []recfile.Field{
+ {Name: "Size", Value: strconv.FormatInt(inode.Size, 10)},
+ {Name: "CtimeSec", Value: strconv.FormatInt(inode.CtimeSec, 10)},
+ {Name: "CtimeNsec", Value: strconv.FormatInt(inode.CtimeNsec, 10)},
+ }
+}
+
+func inodeFromFile(fd *os.File) (*Inode, error) {
+ var fi os.FileInfo
+ fi, err := fd.Stat()
+ if err != nil {
+ return nil, err
+ }
+ var stat unix.Stat_t
+ err = unix.Fstat(int(fd.Fd()), &stat)
+ if err != nil {
+ return nil, err
+ }
+ sec, nsec := stat.Ctim.Unix()
+ return &Inode{Size: fi.Size(), CtimeSec: sec, CtimeNsec: nsec}, nil
+}
+
+func inodeFromRec(m map[string]string) (*Inode, error) {
+ size := m["Size"]
+ ctimeSec := m["CtimeSec"]
+ ctimeNsec := m["CtimeNsec"]
+ if size == "" {
+ return nil, errors.New("Size is missing")
+ }
+ if ctimeSec == "" {
+ return nil, errors.New("CtimeSec is missing")
+ }
+ if ctimeNsec == "" {
+ return nil, errors.New("CtimeNsec is missing")
+ }
+ inode := Inode{}
+ var err error
+ inode.Size, err = strconv.ParseInt(size, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ inode.CtimeSec, err = strconv.ParseInt(ctimeSec, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ inode.CtimeNsec, err = strconv.ParseInt(ctimeNsec, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ return &inode, nil
+}