mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-24 03:47:45 +08:00
165 lines
3.3 KiB
Go
165 lines
3.3 KiB
Go
package mfs
|
|
|
|
import (
|
|
"sync"
|
|
|
|
chunk "github.com/ipfs/go-ipfs/importer/chunk"
|
|
dag "github.com/ipfs/go-ipfs/merkledag"
|
|
mod "github.com/ipfs/go-ipfs/unixfs/mod"
|
|
|
|
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
|
|
)
|
|
|
|
type File struct {
|
|
parent childCloser
|
|
|
|
name string
|
|
hasChanges bool
|
|
|
|
dserv dag.DAGService
|
|
mod *mod.DagModifier
|
|
lock sync.Mutex
|
|
}
|
|
|
|
// NewFile returns a NewFile object with the given parameters
|
|
func NewFile(name string, node *dag.Node, parent childCloser, dserv dag.DAGService) (*File, error) {
|
|
dmod, err := mod.NewDagModifier(context.Background(), node, dserv, chunk.DefaultSplitter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &File{
|
|
dserv: dserv,
|
|
parent: parent,
|
|
name: name,
|
|
mod: dmod,
|
|
}, nil
|
|
}
|
|
|
|
// Write writes the given data to the file at its current offset
|
|
func (fi *File) Write(b []byte) (int, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
fi.hasChanges = true
|
|
return fi.mod.Write(b)
|
|
}
|
|
|
|
// Read reads into the given buffer from the current offset
|
|
func (fi *File) Read(b []byte) (int, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
return fi.mod.Read(b)
|
|
}
|
|
|
|
// Read reads into the given buffer from the current offset
|
|
func (fi *File) CtxReadFull(ctx context.Context, b []byte) (int, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
return fi.mod.CtxReadFull(ctx, b)
|
|
}
|
|
|
|
// Close flushes, then propogates the modified dag node up the directory structure
|
|
// and signals a republish to occur
|
|
func (fi *File) Close() error {
|
|
fi.Lock()
|
|
if fi.hasChanges {
|
|
err := fi.mod.Sync()
|
|
if err != nil {
|
|
fi.Unlock()
|
|
return err
|
|
}
|
|
|
|
fi.hasChanges = false
|
|
|
|
// explicitly stay locked for flushUp call,
|
|
// it will manage the lock for us
|
|
return fi.flushUp()
|
|
}
|
|
fi.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// flushUp syncs the file and adds it to the dagservice
|
|
// it *must* be called with the File's lock taken
|
|
func (fi *File) flushUp() error {
|
|
nd, err := fi.mod.GetNode()
|
|
if err != nil {
|
|
fi.Unlock()
|
|
return err
|
|
}
|
|
|
|
_, err = fi.dserv.Add(nd)
|
|
if err != nil {
|
|
fi.Unlock()
|
|
return err
|
|
}
|
|
|
|
//name := fi.name
|
|
//parent := fi.parent
|
|
|
|
// explicit unlock *only* before closeChild call
|
|
fi.Unlock()
|
|
return nil
|
|
//return parent.closeChild(name, nd)
|
|
}
|
|
|
|
// Sync flushes the changes in the file to disk
|
|
func (fi *File) Sync() error {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
return fi.mod.Sync()
|
|
}
|
|
|
|
// Seek implements io.Seeker
|
|
func (fi *File) Seek(offset int64, whence int) (int64, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
return fi.mod.Seek(offset, whence)
|
|
}
|
|
|
|
// Write At writes the given bytes at the offset 'at'
|
|
func (fi *File) WriteAt(b []byte, at int64) (int, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
fi.hasChanges = true
|
|
return fi.mod.WriteAt(b, at)
|
|
}
|
|
|
|
// Size returns the size of this file
|
|
func (fi *File) Size() (int64, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
return fi.mod.Size()
|
|
}
|
|
|
|
// GetNode returns the dag node associated with this file
|
|
func (fi *File) GetNode() (*dag.Node, error) {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
return fi.mod.GetNode()
|
|
}
|
|
|
|
// Truncate truncates the file to size
|
|
func (fi *File) Truncate(size int64) error {
|
|
fi.Lock()
|
|
defer fi.Unlock()
|
|
fi.hasChanges = true
|
|
return fi.mod.Truncate(size)
|
|
}
|
|
|
|
// Type returns the type FSNode this is
|
|
func (fi *File) Type() NodeType {
|
|
return TFile
|
|
}
|
|
|
|
// Lock the file
|
|
func (fi *File) Lock() {
|
|
fi.lock.Lock()
|
|
}
|
|
|
|
// Unlock the file
|
|
func (fi *File) Unlock() {
|
|
fi.lock.Unlock()
|
|
}
|