@@ -2589,7 +2589,7 @@ func (m *dbMeta) doReaddir(ctx Context, inode Ino, plus uint8, entries *[]*Entry
25892589func recordDeletionStats (
25902590 n * node ,
25912591 entrySpace int64 ,
2592- spaceDelta int64 ,
2592+ spaceDelta int64 ,
25932593 totalLength * int64 ,
25942594 totalSpace * int64 ,
25952595 totalInodes * int64 ,
@@ -2623,12 +2623,12 @@ func (m *dbMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length
26232623 }
26242624
26252625 type entryInfo struct {
2626- e edge
2627- n node
2628- opened bool
2629- trash Ino
2630- trashName string
2631- lastLink bool
2626+ e edge
2627+ n node
2628+ opened bool
2629+ trash Ino
2630+ trashName string
2631+ lastLink bool
26322632 }
26332633 var entryInfos []entryInfo
26342634 var totalLength , totalSpace , totalInodes int64
@@ -2647,6 +2647,11 @@ func (m *dbMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length
26472647 if pn .Type != TypeDirectory {
26482648 return syscall .ENOTDIR
26492649 }
2650+ var pattr Attr
2651+ m .parseAttr (& pn , & pattr )
2652+ if st := m .Access (ctx , parent , MODE_MASK_W | MODE_MASK_X , & pattr ); st != 0 {
2653+ return st
2654+ }
26502655 if (pn .Flags & FlagAppend != 0 ) || (pn .Flags & FlagImmutable ) != 0 {
26512656 return syscall .EPERM
26522657 }
@@ -2655,25 +2660,25 @@ func (m *dbMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length
26552660 now := time .Now ().UnixNano ()
26562661
26572662 inodes := make ([]Ino , 0 , len (entries ))
2658- inodeToEntry := make (map [Ino ][] int ) // inode -> indices in entries
2659- for i , entry := range entries {
2663+ inodeM := make (map [Ino ]struct {} ) // filter hardlinks
2664+ for _ , entry := range entries {
26602665 e := edge {Parent : parent , Name : entry .Name , Inode : entry .Inode }
26612666 if entry .Attr != nil {
26622667 e .Type = entry .Attr .Typ
26632668 }
2664- info := entryInfo {e : e , trash : trash }
2665- entryInfos = append ( entryInfos , info )
2666- if _ , exists := inodeToEntry [entry .Inode ]; ! exists {
2669+ entryInfos = append ( entryInfos , entryInfo {e : e , trash : trash })
2670+ if _ , exists := inodeM [ entry . Inode ]; ! exists {
2671+ inodeM [entry .Inode ] = struct {}{}
26672672 inodes = append (inodes , entry .Inode )
26682673 }
2669- inodeToEntry [entry .Inode ] = append (inodeToEntry [entry .Inode ], i )
26702674 }
26712675
26722676 if len (inodes ) > 0 {
26732677 var nodes []node
26742678 if err := s .ForUpdate ().In ("inode" , inodes ).Find (& nodes ); err != nil {
26752679 return err
26762680 }
2681+ // some inodes may not exist
26772682 nodeMap := make (map [Ino ]* node , len (nodes ))
26782683 for i := range nodes {
26792684 nodeMap [nodes [i ].Inode ] = & nodes [i ]
@@ -2919,7 +2924,7 @@ func (m *dbMeta) doBatchUnlink(ctx Context, parent Ino, entries []Entry, length
29192924
29202925 if trash == 0 {
29212926 for _ , info := range entryInfos {
2922- if info .n .Type == TypeFile && info .lastLink {
2927+ if info .n .Type == TypeFile && info .lastLink {
29232928 isTrash := parent .IsTrash ()
29242929 m .fileDeleted (info .opened , isTrash , info .e .Inode , info .n .Length )
29252930 }
0 commit comments