diff --git a/ipld/unixfs/unixfs.go b/ipld/unixfs/unixfs.go index bdc54518f..fb2c9bbf2 100644 --- a/ipld/unixfs/unixfs.go +++ b/ipld/unixfs/unixfs.go @@ -36,6 +36,7 @@ const ( // Common errors var ( ErrMalformedFileFormat = errors.New("malformed data in file format") + ErrNotProtoNode = errors.New("expected a ProtoNode as internal node") ErrUnrecognizedType = errors.New("unrecognized node type") ) @@ -544,7 +545,7 @@ func ReadUnixFSNodeData(node ipld.Node) (data []byte, err error) { func ExtractFSNode(node ipld.Node) (*FSNode, error) { protoNode, ok := node.(*dag.ProtoNode) if !ok { - return nil, errors.New("expected a ProtoNode as internal node") + return nil, ErrNotProtoNode } fsNode, err := FSNodeFromBytes(protoNode.Data()) diff --git a/mfs/file.go b/mfs/file.go index ef8ce5dfa..834fbc4be 100644 --- a/mfs/file.go +++ b/mfs/file.go @@ -185,14 +185,14 @@ func (fi *File) Mode() (os.FileMode, error) { defer fi.nodeLock.RUnlock() nd, err := fi.GetNode() - if err == nil { - fsn, err := ft.ExtractFSNode(nd) - if err == nil { - return fsn.Mode() & 0xFFF, nil - } + if err != nil { + return 0, err } - - return 0, err + fsn, err := ft.ExtractFSNode(nd) + if err != nil { + return 0, err + } + return fsn.Mode() & 0xFFF, nil } func (fi *File) SetMode(mode os.FileMode) error { @@ -203,6 +203,11 @@ func (fi *File) SetMode(mode os.FileMode) error { fsn, err := ft.ExtractFSNode(nd) if err != nil { + if errors.Is(err, ft.ErrNotProtoNode) { + // Wrap raw node in protonode. + data := nd.RawData() + return fi.setNodeData(ft.FilePBDataWithStat(data, uint64(len(data)), mode, time.Time{})) + } return err } @@ -221,14 +226,14 @@ func (fi *File) ModTime() (time.Time, error) { defer fi.nodeLock.RUnlock() nd, err := fi.GetNode() - if err == nil { - fsn, err := ft.ExtractFSNode(nd) - if err == nil { - return fsn.ModTime(), nil - } + if err != nil { + return time.Time{}, err } - - return time.Time{}, err + fsn, err := ft.ExtractFSNode(nd) + if err != nil { + return time.Time{}, err + } + return fsn.ModTime(), nil } // SetModTime sets the files' last modification time @@ -240,6 +245,11 @@ func (fi *File) SetModTime(ts time.Time) error { fsn, err := ft.ExtractFSNode(nd) if err != nil { + if errors.Is(err, ft.ErrNotProtoNode) { + // Wrap raw node in protonode. + data := nd.RawData() + return fi.setNodeData(ft.FilePBDataWithStat(data, uint64(len(data)), 0, ts)) + } return err } @@ -267,3 +277,8 @@ func (fi *File) setNodeData(data []byte) error { return parent.updateChildEntry(child{name, fi.node}) } + +func (fi *File) replaceRawNodeWithStatNode(data []byte, mode os.FileMode, mtime time.Time) error { + data = ft.FilePBDataWithStat(data, uint64(len(data)), mode, mtime) + return fi.setNodeData(data) +}