@@ -883,7 +883,13 @@ func (fs *FileSystem) Rm(p string) error {
883883// If path is a file, it will remove the file.
884884// Will not remove any parents.
885885// Error if the file does not exist or is not an empty directory
886+ //
887+ //nolint:gocyclo // yes, this has high cyclomatic complexity, but we can accept it
886888func (fs * FileSystem ) Remove (p string ) error {
889+ gdtBlock := 1
890+ if fs .superblock .blockSize == 1024 {
891+ gdtBlock = 2
892+ }
887893 parentDir , entry , err := fs .getEntryAndParent (p )
888894 if err != nil {
889895 return err
@@ -923,15 +929,12 @@ func (fs *FileSystem) Remove(p string) error {
923929 if err != nil {
924930 return fmt .Errorf ("could not read extents for inode %d for %s: %v" , entry .inode , p , err )
925931 }
926- // clear the inode from the inode bitmap
927- inodeBG := blockGroupForInode (int (entry .inode ), fs .superblock .inodesPerGroup )
928- inodeBitmap , err := fs .readInodeBitmap (inodeBG )
929- if err != nil {
930- return fmt .Errorf ("could not read inode bitmap: %v" , err )
931- }
932932 // clear up the blocks from the block bitmap. We are not clearing the block content, just the bitmap.
933933 // keep a cache of bitmaps, so we do not have to read them again and again
934934 blockBitmaps := make (map [int ]* bitmap.Bitmap )
935+ freedByBG := make (map [int ]uint32 )
936+ var totalFreed uint64
937+
935938 for _ , e := range extents {
936939 for i := e .startingBlock ; i < e .startingBlock + uint64 (e .count ); i ++ {
937940 // determine what block group this block is in, and read the bitmap for that blockgroup
@@ -949,12 +952,22 @@ func (fs *FileSystem) Remove(p string) error {
949952 if err := dataBlockBitmap .Clear (blockInBG ); err != nil {
950953 return fmt .Errorf ("could not clear block bitmap for block %d: %v" , i , err )
951954 }
955+ freedByBG [bg ]++
956+ totalFreed ++
952957 }
953958 }
954959 for bg , dataBlockBitmap := range blockBitmaps {
955960 if err := fs .writeBlockBitmap (dataBlockBitmap , bg ); err != nil {
956961 return fmt .Errorf ("could not write block bitmap back to disk: %v" , err )
957962 }
963+ gd := fs .groupDescriptors .descriptors [bg ]
964+ // Increment free blocks by actual filesystem blocks we just cleared in THIS group
965+ gd .freeBlocks += freedByBG [bg ]
966+ gd .blockBitmapChecksum = bitmapChecksum (dataBlockBitmap .ToBytes (), fs .superblock .checksumSeed )
967+ gdBytes := gd .toBytes (fs .superblock .gdtChecksumType (), fs .superblock .checksumSeed )
968+ if _ , err := writableFile .WriteAt (gdBytes , fs .start + int64 (gdtBlock )* int64 (fs .superblock .blockSize )+ int64 (gd .number )* int64 (fs .superblock .groupDescriptorSize )); err != nil {
969+ return fmt .Errorf ("could not write Group Descriptor bytes to file: %v" , err )
970+ }
958971 }
959972
960973 // remove the directory entry from the parent
@@ -967,7 +980,10 @@ func (fs *FileSystem) Remove(p string) error {
967980 }
968981 parentDir .entries = newEntries
969982 // write the parent directory back
970- dirBytes := parentDir .toBytes (fs .superblock .blockSize , directoryChecksumAppender (fs .superblock .checksumSeed , parentDir .inode , 0 ))
983+ dirBytes := parentDir .toBytes (
984+ fs .superblock .blockSize ,
985+ directoryChecksumAppender (fs .superblock .checksumSeed , parentDir .inode , 0 ),
986+ )
971987 parentInode , err := fs .readInode (parentDir .inode )
972988 if err != nil {
973989 return fmt .Errorf ("could not read inode %d for %s: %v" , entry .inode , path .Base (p ), err )
@@ -976,38 +992,68 @@ func (fs *FileSystem) Remove(p string) error {
976992 if err != nil {
977993 return fmt .Errorf ("could not read extents for inode %d for %s: %v" , entry .inode , path .Base (p ), err )
978994 }
995+ // write the directory bytes back to the blocks, ensure block-aligned
996+ bs := int (fs .superblock .blockSize )
997+ written := 0
979998 for _ , e := range extents {
980999 for i := 0 ; i < int (e .count ); i ++ {
981- b := dirBytes [i :fs .superblock .blockSize ]
982- if _ , err := writableFile .WriteAt (b , (int64 (i )+ int64 (e .startingBlock ))* int64 (fs .superblock .blockSize )); err != nil {
1000+ if written >= len (dirBytes ) {
1001+ break
1002+ }
1003+ start := written
1004+ end := start + bs
1005+ if end > len (dirBytes ) {
1006+ end = len (dirBytes )
1007+ }
1008+ b := dirBytes [start :end ]
1009+
1010+ fileOff := fs .start + (int64 (e .startingBlock )+ int64 (i ))* int64 (bs )
1011+
1012+ if _ , err := writableFile .WriteAt (b , fileOff ); err != nil {
9831013 return fmt .Errorf ("could not write inode bitmap back to disk: %v" , err )
9841014 }
1015+ // If the last block is short, zero-pad the remainder up to block size
1016+ if len (b ) < bs {
1017+ zeros := make ([]byte , bs - len (b ))
1018+ if _ , err := writableFile .WriteAt (zeros , fileOff + int64 (len (b ))); err != nil {
1019+ return fmt .Errorf ("could not pad directory block: %w" , err )
1020+ }
1021+ }
1022+ written += bs
9851023 }
9861024 }
9871025
1026+ // clear the inode from the inode bitmap
1027+ inodeBG := blockGroupForInode (int (entry .inode ), fs .superblock .inodesPerGroup )
1028+ inodeBitmap , err := fs .readInodeBitmap (inodeBG )
1029+ if err != nil {
1030+ return fmt .Errorf ("could not read inode bitmap: %v" , err )
1031+ }
1032+
9881033 // remove the inode from the bitmap and write the inode bitmap back
9891034 // inode is absolute, but bitmap is relative to block group
9901035 inodeInBG := int (entry .inode ) - int (fs .superblock .inodesPerGroup )* inodeBG
9911036 if err := inodeBitmap .Clear (inodeInBG ); err != nil {
9921037 return fmt .Errorf ("could not clear inode bitmap for inode %d: %v" , entry .inode , err )
9931038 }
994-
9951039 // write the inode bitmap back
9961040 if err := fs .writeInodeBitmap (inodeBitmap , inodeBG ); err != nil {
9971041 return fmt .Errorf ("could not write inode bitmap back to disk: %v" , err )
9981042 }
999- // update the group descriptor
1043+
1044+ // Update the group descriptor: free inode count, free block count, used directory count; recompute checksums, and write GD
10001045 gd := fs .groupDescriptors .descriptors [inodeBG ]
10011046
10021047 // update the group descriptor inodes and blocks
10031048 gd .freeInodes ++
10041049 gd .freeBlocks += uint32 (removedInode .blocks )
1005- // write the group descriptor back
1006- gdBytes := gd .toBytes (fs .superblock .gdtChecksumType (), fs .superblock .uuid .ID ())
1007- gdtBlock := 1
1008- if fs .superblock .blockSize == 1024 {
1009- gdtBlock = 2
1050+ if entry .fileType == dirFileTypeDirectory {
1051+ gd .usedDirectories --
10101052 }
1053+ gd .inodeBitmapChecksum = bitmapChecksum (inodeBitmap .ToBytes (), fs .superblock .checksumSeed )
1054+
1055+ // write the group descriptor back
1056+ gdBytes := gd .toBytes (fs .superblock .gdtChecksumType (), fs .superblock .checksumSeed )
10111057 if _ , err := writableFile .WriteAt (gdBytes , fs .start + int64 (gdtBlock )* int64 (fs .superblock .blockSize )+ int64 (gd .number )* int64 (fs .superblock .groupDescriptorSize )); err != nil {
10121058 return fmt .Errorf ("could not write Group Descriptor bytes to file: %v" , err )
10131059 }
@@ -1594,7 +1640,7 @@ func (fs *FileSystem) allocateInode(parent uint32) (uint32, error) {
15941640 gd .freeInodes --
15951641
15961642 // get the group descriptor as bytes
1597- gdBytes := gd .toBytes (fs .superblock .gdtChecksumType (), fs .superblock .uuid . ID () )
1643+ gdBytes := gd .toBytes (fs .superblock .gdtChecksumType (), fs .superblock .checksumSeed )
15981644
15991645 // write the group descriptor bytes
16001646 // gdt starts in block 1 of any redundant copies, specifically in BG 0
0 commit comments