Skip to content

Commit

Permalink
lib/memfs: re-scan directory content on Node's Update
Browse files Browse the repository at this point in the history
Previously, only node content get updated.
In case in the MemFS, user set "Options.TryDirect" to true, the directory
content should be updated too on "MemFS.Get".
  • Loading branch information
shuLhan committed Nov 5, 2023
1 parent 3dbed6f commit cdf63b6
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 9 deletions.
7 changes: 2 additions & 5 deletions lib/memfs/dirwatcher_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,14 @@ func ExampleDirWatcher() {
fmt.Println(`--`, ns.State, ns.Node.Path)

// Create the root directory back with sub directory
// This will trigger two FileStateCreated events, one for "/" and one
// for "/assets".
// This will trigger one FileStateCreated event, for "/".
fmt.Println(`Re-create root directory with sub-directory:`)
var dirAssets = filepath.Join(rootDir, `assets`)
err = os.MkdirAll(dirAssets, 0770)
if err != nil {
log.Fatal(err)
}
ns = <-dw.C
fmt.Println(`--`, ns.State, ns.Node.Path)

ns = <-dw.C
fmt.Println(`--`, ns.State, ns.Node.Path)

Expand Down Expand Up @@ -149,7 +147,6 @@ func ExampleDirWatcher() {
//-- FileStateDeleted /
//Re-create root directory with sub-directory:
//-- FileStateCreated /
//-- FileStateCreated /assets
//Chmod on root directory:
//-- FileStateUpdateMode / drwx------
//Create new file on root directory: /new.adoc
Expand Down
99 changes: 95 additions & 4 deletions lib/memfs/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"os"
"path"
"path/filepath"
"sort"
"time"

"github.com/shuLhan/share/lib/ascii"
Expand Down Expand Up @@ -492,17 +493,31 @@ func (node *Node) Update(newInfo os.FileInfo, maxFileSize int64) (err error) {
return nil
}

var doUpdate = false
if newInfo.ModTime().After(node.modTime) {
doUpdate = true
} else if !newInfo.IsDir() {
if newInfo.Size() != node.size {
doUpdate = true
}
}

if !doUpdate {
return nil
}

node.modTime = newInfo.ModTime()
node.size = newInfo.Size()

if newInfo.IsDir() {
return nil
err = node.updateDir(maxFileSize)
} else {
err = node.updateContent(maxFileSize)
}

err = node.updateContent(maxFileSize)
if err != nil {
return fmt.Errorf("%s %s: %w", logp, node.SysPath, err)
}

return nil
}

Expand All @@ -511,7 +526,8 @@ func (node *Node) updateContent(maxFileSize int64) (err error) {
if maxFileSize < 0 {
// Negative maxFileSize means content will not be read.
return nil
} else if maxFileSize == 0 {
}
if maxFileSize == 0 {
maxFileSize = defaultMaxFileSize
}
if node.size > maxFileSize {
Expand All @@ -533,6 +549,81 @@ func (node *Node) updateContent(maxFileSize int64) (err error) {
return nil
}

// updateDir update the childs node by reading content of directory.
func (node *Node) updateDir(maxFileSize int64) (err error) {
var (
currChilds = make(map[string]*Node, len(node.Childs))
child *Node
)

// Store the current childs as map first so we can use it later.
for _, child = range node.Childs {
currChilds[child.name] = child
}

var dir *os.File

dir, err = os.Open(node.SysPath)
if err != nil {
if os.IsPermission(err) {
// Ignore error due to permission.
return nil
}
return fmt.Errorf(`%q: %w`, node.SysPath, err)
}

var fis []os.FileInfo

fis, err = dir.Readdir(0)
if err != nil {
return fmt.Errorf(`%q: %w`, node.SysPath, err)
}

sort.SliceStable(fis, func(x, y int) bool {
return fis[x].Name() < fis[y].Name()
})

var fi os.FileInfo

node.Childs = nil
for _, fi = range fis {
child = currChilds[fi.Name()]
if child == nil {
// New node found in directory.
child, err = NewNode(node, fi, maxFileSize)
if err != nil {
if os.IsPermission(err) {
// Ignore error due to permission.
continue
}
return err
}

child.SysPath = filepath.Join(node.SysPath, child.name)
} else {
delete(currChilds, fi.Name())
}

node.Childs = append(node.Childs, child)

if !child.IsDir() {
continue
}

// If node exist and its a directory, try to update their
// childs too.
err = child.Update(nil, maxFileSize)
if err != nil {
if os.IsPermission(err) {
// Ignore error due to permission.
continue
}
return err
}
}
return nil
}

func (node *Node) updateContentType() error {
node.ContentType = mime.TypeByExtension(path.Ext(node.name))
if len(node.ContentType) > 0 {
Expand Down

0 comments on commit cdf63b6

Please sign in to comment.