diff options
68 files changed, 406 insertions, 166 deletions
diff --git a/.golangci.yml b/.golangci.yml index 38d53ee..ba58f21 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -7,7 +7,7 @@ linters: disable: # Deprecated - deadcode # deprecated, replaced by 'unused' - - exhaustivestruct # deprecated, replaced by 'exhauststruct' + - exhaustivestruct # deprecated, replaced by 'exhaustruct' - golint # deprecated, replaced by 'revive' - ifshort # deprecated - interfacer # deprecated @@ -19,7 +19,6 @@ linters: # Don't support Go 1.18 generics yet - rowserrcheck - - sqlclosecheck - wastedassign - ireturn # golangci-lint doesn't claim it doesn't, but it doesn't @@ -48,7 +47,6 @@ linters: - exhaustruct - gochecknoglobals - gochecknoinits - - revive - testpackage - thelper - varnamelen @@ -86,13 +84,38 @@ linters-settings: require-specific: true allow-no-explanation: - dupword + revive: + enable-all-rules: true + rules: + - { name: call-to-gc, disabled: true } + - { name: exported, disabled: true } # TODO: Add doc comments to exported identifiers + - { name: file-header, disabled: true } # TODO: This might actually be useful for copyright + - { name: flag-parameter, disabled: true } + - { name: modifies-value-receiver, disabled: true } + - { name: unexported-return, disabled: true } + # Style. + - { name: banned-characters, disabled: true } + - { name: line-length-limit, disabled: true } + - { name: nested-structs, disabled: true } + - { name: var-naming, disabled: true } + # Complexity; sometimes code is just complex. + - { name: argument-limit, disabled: true } + - { name: cognitive-complexity, disabled: true } + - { name: cyclomatic, disabled: true } + - { name: function-length, disabled: true } + - { name: function-result-limit, disabled: true } + - { name: max-public-structs, disabled: true } + # Duplicates. + - { name: add-constant, disabled: true } # duplicates gomnd + - { name: receiver-naming, disabled: true } # duplicates stylecheck ST1016 + - { name: unhandled-error, disabled: true } # duplicates errcheck + # Buggy. + - { name: confusing-naming, disabled: true } # false positive on methods implementing interfaces + - { name: import-shadowing, disabled: true } # false positive on methods stylecheck: checks: - "all" - "-ST1003" # CONST_VAL names for consistency with other btrfs code - - "-ST1000" # TODO: get this to pass - - "-ST1020" # TODO: get this to pass - - "-ST1021" # TODO: get this to pass tagliatelle: case: use-field-name: true diff --git a/cmd/btrfs-rec/inspect/dumptrees/print_tree.go b/cmd/btrfs-rec/inspect/dumptrees/print_tree.go index a0a3d46..a8c2adf 100644 --- a/cmd/btrfs-rec/inspect/dumptrees/print_tree.go +++ b/cmd/btrfs-rec/inspect/dumptrees/print_tree.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package dumptrees is the guts of the `btrfs-rec inspect dump-trees` +// command, which is a clone of `btrfs inspect-internal dump-tree`. package dumptrees import ( diff --git a/cmd/btrfs-rec/inspect/mount/mount.go b/cmd/btrfs-rec/inspect/mount/mount.go index da0bbb6..0e8faf1 100644 --- a/cmd/btrfs-rec/inspect/mount/mount.go +++ b/cmd/btrfs-rec/inspect/mount/mount.go @@ -2,6 +2,9 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package mount is the guts of the `btrfs-rec inspect mount` command, +// which mounts the filesystem read-only using FUSE; providing better +// tolerance of filesystem corruption than the in-kernel btrfs driver. package mount import ( @@ -479,4 +482,4 @@ func (sv *subvolume) GetXattr(_ context.Context, op *fuseops.GetXattrOp) error { return nil } -func (sv *subvolume) Destroy() {} +func (*subvolume) Destroy() {} diff --git a/cmd/btrfs-rec/inspect/rebuildmappings/process.go b/cmd/btrfs-rec/inspect/rebuildmappings/process.go index 7ce3748..a93b697 100644 --- a/cmd/btrfs-rec/inspect/rebuildmappings/process.go +++ b/cmd/btrfs-rec/inspect/rebuildmappings/process.go @@ -2,6 +2,9 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package rebuildmappings is the guts of the `btrfs-rec inspect +// rebuild-mappings` command, which rebuilds broken +// chunk/dev-extent/blockgroup trees. package rebuildmappings import ( diff --git a/cmd/btrfs-rec/inspect/rebuildmappings/scan.go b/cmd/btrfs-rec/inspect/rebuildmappings/scan.go index f9c3bf3..b88f01c 100644 --- a/cmd/btrfs-rec/inspect/rebuildmappings/scan.go +++ b/cmd/btrfs-rec/inspect/rebuildmappings/scan.go @@ -103,7 +103,7 @@ func (scanner *deviceScanner) ScanStats() scanStats { } } -func newDeviceScanner(ctx context.Context, sb btrfstree.Superblock, numBytes btrfsvol.PhysicalAddr, numSectors int) btrfsutil.DeviceScanner[scanStats, ScanOneDeviceResult] { +func newDeviceScanner(_ context.Context, sb btrfstree.Superblock, _ btrfsvol.PhysicalAddr, numSectors int) btrfsutil.DeviceScanner[scanStats, ScanOneDeviceResult] { scanner := new(deviceScanner) scanner.alg = sb.ChecksumType scanner.result.FoundNodes = make(map[btrfsvol.LogicalAddr][]btrfsvol.PhysicalAddr) @@ -112,7 +112,7 @@ func newDeviceScanner(ctx context.Context, sb btrfstree.Superblock, numBytes btr return scanner } -func (scanner *deviceScanner) ScanSector(ctx context.Context, dev *btrfs.Device, paddr btrfsvol.PhysicalAddr) error { +func (scanner *deviceScanner) ScanSector(_ context.Context, dev *btrfs.Device, paddr btrfsvol.PhysicalAddr) error { sum, err := btrfs.ChecksumPhysical(dev, scanner.alg, paddr) if err != nil { return err @@ -190,7 +190,7 @@ func (scanner *deviceScanner) ScanNode(ctx context.Context, nodeRef *diskio.Ref[ return nil } -func (scanner *deviceScanner) ScanDone(ctx context.Context) (ScanOneDeviceResult, error) { +func (scanner *deviceScanner) ScanDone(_ context.Context) (ScanOneDeviceResult, error) { scanner.result.Checksums.Sums = btrfssum.ShortSum(scanner.sums.String()) return scanner.result, nil } diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go index 708b504..ca1ce8c 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go @@ -2,6 +2,10 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package rebuildtrees is the guts of the `btrfs-rec inspect +// rebuild-trees` command, which rebuilds broken trees, but requires +// already-functioning chunk/dev-extent/blockgroup trees. +// chunk/dev-extent/blockgroup trees. package rebuildtrees import ( @@ -282,7 +286,7 @@ func (o *rebuilder) processSettledItemQueue(ctx context.Context) error { ctx := dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.rebuild.process.item", item.keyAndTree) o.curKey.TreeID = item.TreeID o.curKey.Key.Val = item.Key - btrfscheck.HandleItem(o, ctx, item.TreeID, btrfstree.Item{ + btrfscheck.HandleItem(ctx, o, item.TreeID, btrfstree.Item{ Key: item.Key, Body: item.Body, }) diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go index e6a0777..a422a47 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go @@ -14,7 +14,7 @@ import ( ) // AddedItem implements btrfsutil.RebuiltForrestCallbacks. -func (o *rebuilder) AddedItem(ctx context.Context, tree btrfsprim.ObjID, key btrfsprim.Key) { +func (o *rebuilder) AddedItem(_ context.Context, tree btrfsprim.ObjID, key btrfsprim.Key) { o.addedItemQueue.Insert(keyAndTree{ TreeID: tree, Key: key, @@ -22,7 +22,7 @@ func (o *rebuilder) AddedItem(ctx context.Context, tree btrfsprim.ObjID, key btr } // AddedRoot implements btrfsutil.RebuiltForrestCallbacks. -func (o *rebuilder) AddedRoot(ctx context.Context, tree btrfsprim.ObjID, root btrfsvol.LogicalAddr) { +func (o *rebuilder) AddedRoot(_ context.Context, tree btrfsprim.ObjID, _ btrfsvol.LogicalAddr) { if retries := o.retryItemQueue[tree]; retries != nil { o.addedItemQueue.InsertFrom(retries) } diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go index 4a5029e..704f4ee 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go @@ -20,7 +20,7 @@ import ( ) // FSErr implements btrfscheck.GraphCallbacks. -func (o *rebuilder) FSErr(ctx context.Context, e error) { +func (*rebuilder) FSErr(ctx context.Context, e error) { dlog.Errorf(ctx, "filesystem error: %v", e) } diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go index 4aab669..8fe8a49 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go @@ -23,8 +23,9 @@ const ( offsetName ) -// TODO(lukeshu): Delete the 'Want' type in favor of btrfstree.Search. type Want struct { + // TODO(lukeshu): Delete the 'Want' type in favor of + // btrfstree.Search. ObjectID btrfsprim.ObjID ItemType btrfsprim.ItemType OffsetType wantOffsetType diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index 15f1964..e433654 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Command btrfs-rec is used to recover (data from) a broken btrfs +// filesystem. package main import ( diff --git a/lib/binstruct/binutil/binutil.go b/lib/binstruct/binutil/binutil.go index 684237f..a5c65b5 100644 --- a/lib/binstruct/binutil/binutil.go +++ b/lib/binstruct/binutil/binutil.go @@ -1,7 +1,9 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later +// Package binutil provides utilities for implementing the interfaces +// consumed by binstruct. package binutil import ( diff --git a/lib/binstruct/unmarshal.go b/lib/binstruct/unmarshal.go index eae4b84..41aab9c 100644 --- a/lib/binstruct/unmarshal.go +++ b/lib/binstruct/unmarshal.go @@ -2,6 +2,9 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package binstruct implements simple struct-tag-based conversion +// between Go structures and binary on-disk representations of that +// data. package binstruct import ( diff --git a/lib/btrfs/btrfsitem/item_blockgroup.go b/lib/btrfs/btrfsitem/item_blockgroup.go index ae0ca12..dc561bd 100644 --- a/lib/btrfs/btrfsitem/item_blockgroup.go +++ b/lib/btrfs/btrfsitem/item_blockgroup.go @@ -10,8 +10,20 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = logical_addr -// key.offset = size of chunk +// A BlockGroup tracks allocation of the logical address space. +// +// Compare with: +// - DevExtents, which track allocation of the physical address space. +// - Chunks, which map logical addresses to physical addresses. +// +// The relationship between the three is +// +// DevExtent---[many:one]---Chunk---[one:one]---BlockGroup +// +// Key: +// +// key.objectid = logical_addr +// key.offset = size of chunk type BlockGroup struct { // trivial BLOCK_GROUP_ITEM=192 Used int64 `bin:"off=0, siz=8"` ChunkObjectID btrfsprim.ObjID `bin:"off=8, siz=8"` // always FIRST_CHUNK_TREE_OBJECTID diff --git a/lib/btrfs/btrfsitem/item_chunk.go b/lib/btrfs/btrfsitem/item_chunk.go index 2280a0b..607df75 100644 --- a/lib/btrfs/btrfsitem/item_chunk.go +++ b/lib/btrfs/btrfsitem/item_chunk.go @@ -11,10 +11,20 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/containers" ) -// Maps logical address to physical. +// A Chunk maps logical addresses to physical addresses. // -// key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID -// key.offset = logical_addr +// Compare with: +// - DevExtents, which track allocation of the physical address space. +// - BlockGroups, which track allocation of the logical address space. +// +// The relationship between the three is +// +// DevExtent---[many:one]---Chunk---[one:one]---BlockGroup +// +// Key: +// +// key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID +// key.offset = logical_addr type Chunk struct { // complex CHUNK_ITEM=228 Head ChunkHeader Stripes []ChunkStripe diff --git a/lib/btrfs/btrfsitem/item_dev.go b/lib/btrfs/btrfsitem/item_dev.go index 188711e..7fd6833 100644 --- a/lib/btrfs/btrfsitem/item_dev.go +++ b/lib/btrfs/btrfsitem/item_dev.go @@ -10,8 +10,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = BTRFS_DEV_ITEMS_OBJECTID -// key.offset = device_id (starting at 1) +// A Dev describes a physical volume that is part of the filesystem. +// +// Key: +// +// key.objectid = BTRFS_DEV_ITEMS_OBJECTID +// key.offset = device_id (starting at 1) type Dev struct { // trivial DEV_ITEM=216 DevID btrfsvol.DeviceID `bin:"off=0x0, siz=0x8"` diff --git a/lib/btrfs/btrfsitem/item_devextent.go b/lib/btrfs/btrfsitem/item_devextent.go index cade165..6998277 100644 --- a/lib/btrfs/btrfsitem/item_devextent.go +++ b/lib/btrfs/btrfsitem/item_devextent.go @@ -10,8 +10,23 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = device_id -// key.offset = physical_addr +// A DevExtent tracks allocation of the physical address space. +// +// Compare with: +// - BlockGroups, which track allocation of the logical address space. +// - Chunks, which map logical addresses to physical addresses. +// +// The relationship between the three is +// +// DevExtent---[many:one]---Chunk---[one:one]---BlockGroup +// +// The device ID identifies which Dev item describes the physical +// volume that the DevExtent is on. +// +// Key: +// +// key.objectid = device_id +// key.offset = physical_addr type DevExtent struct { // trivial DEV_EXTENT=204 ChunkTree btrfsprim.ObjID `bin:"off=0, siz=8"` // always CHUNK_TREE_OBJECTID ChunkObjectID btrfsprim.ObjID `bin:"off=8, siz=8"` // which chunk within .ChunkTree owns this extent, always FIRST_CHUNK_TREE_OBJECTID diff --git a/lib/btrfs/btrfsitem/item_dir.go b/lib/btrfs/btrfsitem/item_dir.go index c1b3c09..cd16d57 100644 --- a/lib/btrfs/btrfsitem/item_dir.go +++ b/lib/btrfs/btrfsitem/item_dir.go @@ -19,10 +19,14 @@ func NameHash(dat []byte) uint64 { return uint64(^crc32.Update(1, crc32.MakeTable(crc32.Castagnoli), dat)) } -// key.objectid = inode of directory containing this entry -// key.offset = -// - for DIR_ITEM and XATTR_ITEM = NameHash(name) -// - for DIR_INDEX = index id in the directory (starting at 2, because "." and "..") +// A DirEntry is an member of a directory. +// +// Key: +// +// key.objectid = inode of directory containing this entry +// key.offset = one of: +// - for DIR_ITEM and XATTR_ITEM = NameHash(name) +// - for DIR_INDEX = index id in the directory (starting at 2, because of "." and "..") type DirEntry struct { // complex DIR_ITEM=84 DIR_INDEX=96 XATTR_ITEM=24 Location btrfsprim.Key `bin:"off=0x0, siz=0x11"` TransID int64 `bin:"off=0x11, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_extent.go b/lib/btrfs/btrfsitem/item_extent.go index 871ed90..edfef7c 100644 --- a/lib/btrfs/btrfsitem/item_extent.go +++ b/lib/btrfs/btrfsitem/item_extent.go @@ -13,8 +13,22 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = laddr of the extent -// key.offset = length of the extent +// Extent items map from regions in the logical address space to +// regions in a file. +// +// Compare with: +// +// - Metadata, which are like Extents but without .Info. +// - FileExtents, which map from regions in a file to regions in the +// logical address space. +// +// An Extent may contain (inline or not) several ExtentDataRef items +// and/or ShareDataRef items. +// +// Key: +// +// key.objectid = laddr of the extent +// key.offset = length of the extent type Extent struct { // complex EXTENT_ITEM=168 Head ExtentHeader Info TreeBlockInfo // only if .Head.Flags.Has(EXTENT_FLAG_TREE_BLOCK) diff --git a/lib/btrfs/btrfsitem/item_extentcsum.go b/lib/btrfs/btrfsitem/item_extentcsum.go index dfa166d..a963c16 100644 --- a/lib/btrfs/btrfsitem/item_extentcsum.go +++ b/lib/btrfs/btrfsitem/item_extentcsum.go @@ -11,8 +11,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = BTRFS_EXTENT_CSUM_OBJECTID -// key.offset = laddr of checksummed region +// An ExtentCSum checksums regions of the logical address space. +// +// Key: +// +// key.objectid = BTRFS_EXTENT_CSUM_OBJECTID +// key.offset = laddr of checksummed region type ExtentCSum struct { // trivial EXTENT_CSUM=128 // Checksum of each sector starting at key.offset btrfssum.SumRun[btrfsvol.LogicalAddr] diff --git a/lib/btrfs/btrfsitem/item_extentdataref.go b/lib/btrfs/btrfsitem/item_extentdataref.go index 6f2257b..bd7bb04 100644 --- a/lib/btrfs/btrfsitem/item_extentdataref.go +++ b/lib/btrfs/btrfsitem/item_extentdataref.go @@ -9,8 +9,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// key.objectid = laddr of the extent being referenced -// key.offset = crc32c([root,objectid,offset]) +// ExtentDataRef is part of an Extent. +// +// Key: +// +// key.objectid = laddr of the extent being referenced +// key.offset = crc32c([root,objectid,offset]) type ExtentDataRef struct { // trivial EXTENT_DATA_REF=178 Root btrfsprim.ObjID `bin:"off=0, siz=8"` // subvolume tree ID that references this extent ObjectID btrfsprim.ObjID `bin:"off=8, siz=8"` // inode number that references this extent within the .Root subvolume diff --git a/lib/btrfs/btrfsitem/item_fileextent.go b/lib/btrfs/btrfsitem/item_fileextent.go index 6b08897..df3d371 100644 --- a/lib/btrfs/btrfsitem/item_fileextent.go +++ b/lib/btrfs/btrfsitem/item_fileextent.go @@ -12,8 +12,19 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = inode -// key.offset = offset within file +// FileExtent items map from regions in a file to regions in the +// logical address space. +// +// Compare with: +// +// - Extents, which map from regions in the logical address space to +// regions in a file. +// - Metadata, which are like Extents but without .Info. +// +// Key: +// +// key.objectid = inode +// key.offset = offset within file type FileExtent struct { // complex EXTENT_DATA=108 Generation btrfsprim.Generation `bin:"off=0x0, siz=0x8"` // transaction ID that created this extent RAMBytes int64 `bin:"off=0x8, siz=0x8"` // upper bound of what compressed data will decompress to diff --git a/lib/btrfs/btrfsitem/item_freespacebitmap.go b/lib/btrfs/btrfsitem/item_freespacebitmap.go index ebc00e4..d70a2b5 100644 --- a/lib/btrfs/btrfsitem/item_freespacebitmap.go +++ b/lib/btrfs/btrfsitem/item_freespacebitmap.go @@ -4,8 +4,13 @@ package btrfsitem -// key.objectid = object ID of the FreeSpaceInfo (logical_addr) -// key.offset = offset of the FreeSpaceInfo (size) +// FreeSpaceBitmap is used in conjunction with FreeSpaceInfo for +// highly-fragmented blockgroups. +// +// Key: +// +// key.objectid = object ID of the FreeSpaceInfo (logical_addr) +// key.offset = offset of the FreeSpaceInfo (size) type FreeSpaceBitmap struct { // complex FREE_SPACE_BITMAP=200 Bitmap []byte } diff --git a/lib/btrfs/btrfsitem/item_freespaceinfo.go b/lib/btrfs/btrfsitem/item_freespaceinfo.go index 9b886af..7782d27 100644 --- a/lib/btrfs/btrfsitem/item_freespaceinfo.go +++ b/lib/btrfs/btrfsitem/item_freespaceinfo.go @@ -9,8 +9,14 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = object ID of the BlockGroup (logical_addr) -// key.offset = offset of the BlockGroup (size) +// FreeSpaceInfo is the main way (v2) that free space is tracked in a +// BlockGroup. For highly-fragmented blockgorups, it may be augmented +// by a FreeSpaceBitmap. +// +// Key: +// +// key.objectid = object ID of the BlockGroup (logical_addr) +// key.offset = offset of the BlockGroup (size) type FreeSpaceInfo struct { // trivial FREE_SPACE_INFO=198 ExtentCount int32 `bin:"off=0, siz=4"` Flags FreeSpaceFlags `bin:"off=4, siz=4"` diff --git a/lib/btrfs/btrfsitem/item_inode.go b/lib/btrfs/btrfsitem/item_inode.go index 6951c76..0b6a1c2 100644 --- a/lib/btrfs/btrfsitem/item_inode.go +++ b/lib/btrfs/btrfsitem/item_inode.go @@ -10,8 +10,10 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = inode number -// key.offset = 0 +// Inode is a file/dir/whatever in the filesystem. +// +// key.objectid = inode number +// key.offset = 0 type Inode struct { // trivial INODE_ITEM=1 Generation btrfsprim.Generation `bin:"off=0x00, siz=0x08"` TransID int64 `bin:"off=0x08, siz=0x08"` diff --git a/lib/btrfs/btrfsitem/item_inoderef.go b/lib/btrfs/btrfsitem/item_inoderef.go index 074b26d..f38295d 100644 --- a/lib/btrfs/btrfsitem/item_inoderef.go +++ b/lib/btrfs/btrfsitem/item_inoderef.go @@ -12,11 +12,16 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/containers" ) -// key.objectid = inode number of the file -// key.offset = inode number of the parent directory +// An InodeRefs item is a set of back-references that point to a given +// Inode. // -// Might have multiple entries if the same file has multiple hardlinks -// in the same directory. +// Key: +// +// key.objectid = inode number of the file +// key.offset = inode number of the parent directory +// +// There might be multiple back-references in a single InodeRef item +// if the same file has multiple hardlinks in the same directory. type InodeRefs struct { // complex INODE_REF=12 Refs []InodeRef } diff --git a/lib/btrfs/btrfsitem/item_metadata.go b/lib/btrfs/btrfsitem/item_metadata.go index db2315e..10ae994 100644 --- a/lib/btrfs/btrfsitem/item_metadata.go +++ b/lib/btrfs/btrfsitem/item_metadata.go @@ -8,7 +8,22 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/binstruct" ) +// Metadata items map from regions in the logical address space to +// regions in a file. +// // Metadata is like Extent, but doesn't have .Info. +// +// Compare with: +// +// - Extents, which are the same as Metadata, but have an extra +// .Info member. +// - FileExtents, which map from regions in a file to regions in the +// logical address space. +// +// Key: +// +// key.objectid = laddr of the extent +// key.offset = length of the extent type Metadata struct { // complex METADATA_ITEM=169 Head ExtentHeader Refs []ExtentInlineRef diff --git a/lib/btrfs/btrfsitem/item_qgroupinfo.go b/lib/btrfs/btrfsitem/item_qgroupinfo.go index 6699030..2bf38f6 100644 --- a/lib/btrfs/btrfsitem/item_qgroupinfo.go +++ b/lib/btrfs/btrfsitem/item_qgroupinfo.go @@ -9,8 +9,13 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// key.objectid = 0 -// key.offset = ID of the qgroup +// QGroupInfo tracks the amount of space used by a given qgroup in the +// containing subvolume. +// +// Key: +// +// key.objectid = 0 +// key.offset = ID of the qgroup type QGroupInfo struct { // trivial QGROUP_INFO=242 Generation btrfsprim.Generation `bin:"off=0, siz=8"` ReferencedBytes uint64 `bin:"off=8, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_qgrouplimit.go b/lib/btrfs/btrfsitem/item_qgrouplimit.go index 47f7eca..e303b04 100644 --- a/lib/btrfs/btrfsitem/item_qgrouplimit.go +++ b/lib/btrfs/btrfsitem/item_qgrouplimit.go @@ -34,8 +34,14 @@ func (f QGroupLimitFlags) String() string { return fmtutil.BitfieldString(f, qgroupLimitFlagNames, fmtutil.HexNone) } -// key.objectid = 0 -// key.offset = ID of the qgroup +// QGroupLimit configures the maximum permissible amount of space that +// a given qgroup can consume (tracked in a QGroupInfo item) on the +// containing subvolume. +// +// Key: +// +// key.objectid = 0 +// key.offset = ID of the qgroup type QGroupLimit struct { // trivial QGROUP_LIMIT=244 Flags QGroupLimitFlags `bin:"off=0, siz=8"` MaxReferenced uint64 `bin:"off=8, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_qgroupstatus.go b/lib/btrfs/btrfsitem/item_qgroupstatus.go index 346c913..b140371 100644 --- a/lib/btrfs/btrfsitem/item_qgroupstatus.go +++ b/lib/btrfs/btrfsitem/item_qgroupstatus.go @@ -32,8 +32,14 @@ func (f QGroupStatusFlags) String() string { const QGroupStatusVersion uint64 = 1 -// key.objectid = 0 -// key.offset = 0 +// A QGroupStatus holds the qgroup state of a subvolume (I think that +// implies that the QGroupStatus goes in the subvolume tree that it is +// describing?). +// +// Key: +// +// key.objectid = 0 +// key.offset = 0 type QGroupStatus struct { // trivial QGROUP_STATUS=240 Version uint64 `bin:"off=0, siz=8"` Generation btrfsprim.Generation `bin:"off=8, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_root.go b/lib/btrfs/btrfsitem/item_root.go index d39bd70..4ffad9a 100644 --- a/lib/btrfs/btrfsitem/item_root.go +++ b/lib/btrfs/btrfsitem/item_root.go @@ -11,10 +11,17 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = tree ID -// key.offset = either -// - 0 if objectid is one of the BTRFS_*_TREE_OBJECTID defines or a non-snapshot volume; or -// - transaction_id of when this snapshot was created +// A Root goes in the ROOT_TREE and defines one of the other trees in +// the filesystem. All trees have a Root item describing them, except +// for the ROOT_TREE, CHUNK_TREE, TREE_LOG, and BLOCK_GROUP_TREE, +// which are defined directly in the superblock. +// +// Key: +// +// key.objectid = tree ID +// key.offset = one of: +// - 0 if objectid is one of the BTRFS_*_TREE_OBJECTID defines or a non-snapshot volume; or +// - transaction_id of when this snapshot was created type Root struct { // trivial ROOT_ITEM=132 Inode Inode `bin:"off=0x000, siz=0xa0"` // ??? Generation btrfsprim.Generation `bin:"off=0x0a0, siz=0x08"` diff --git a/lib/btrfs/btrfsitem/item_rootref.go b/lib/btrfs/btrfsitem/item_rootref.go index 4179890..e40b278 100644 --- a/lib/btrfs/btrfsitem/item_rootref.go +++ b/lib/btrfs/btrfsitem/item_rootref.go @@ -12,10 +12,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// RootRefs link subvolumes parent→child for normal subvolumes and +// A RootRef links subvolumes parent→child for normal subvolumes and // base→snapshot for snapshot subvolumes. BACKREF items go the other // direction; child→parent and snapshot→base. // +// Key: +// // ROOT_REF | ROOT_BACKREF // key.objectid = ID of the parent subvolume | ID of the child subvolume // key.offset = ID of the child subvolume | ID of the parent subvolume diff --git a/lib/btrfs/btrfsitem/item_shareddataref.go b/lib/btrfs/btrfsitem/item_shareddataref.go index 6143a5c..5d88522 100644 --- a/lib/btrfs/btrfsitem/item_shareddataref.go +++ b/lib/btrfs/btrfsitem/item_shareddataref.go @@ -8,10 +8,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/binstruct" ) -// key.objectid = laddr of the extent being referenced +// SharedDataRef is part of an Extent. // -// key.offset = laddr of the leaf node containing the FileExtent -// (EXTENT_DATA_KEY) for this reference. +// Key: +// +// key.objectid = laddr of the extent being referenced +// key.offset = laddr of the leaf node containing the FileExtent (EXTENT_DATA_KEY) for this reference. type SharedDataRef struct { // trivial SHARED_DATA_REF=184 Count int32 `bin:"off=0, siz=4"` // reference count binstruct.End `bin:"off=4"` diff --git a/lib/btrfs/btrfsitem/item_uuid.go b/lib/btrfs/btrfsitem/item_uuid.go index fca409d..a5ace33 100644 --- a/lib/btrfs/btrfsitem/item_uuid.go +++ b/lib/btrfs/btrfsitem/item_uuid.go @@ -11,11 +11,16 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// The Key for this item is a UUID, and the item is a subvolume IDs +// A UUIDMap item goes in the UUID_TREE and maps from a UUID to a +// btrfsprim.ObjID. +// +// The Key for this item is a UUID, and the item is a subvolume ID // that UUID maps to. // -// key.objectid = first half of UUID -// key.offset = second half of UUID +// Key: +// +// key.objectid = first half of UUID +// key.offset = second half of UUID type UUIDMap struct { // trivial UUID_SUBVOL=251 UUID_RECEIVED_SUBVOL=252 ObjID btrfsprim.ObjID `bin:"off=0, siz=8"` binstruct.End `bin:"off=8"` diff --git a/lib/btrfs/btrfsitem/items.go b/lib/btrfs/btrfsitem/items.go index 49d421f..a730447 100644 --- a/lib/btrfs/btrfsitem/items.go +++ b/lib/btrfs/btrfsitem/items.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfsitem contains the definitions of all "items" that may +// be stored in a btrfs tree. package btrfsitem import ( @@ -56,7 +58,11 @@ func (o *Error) UnmarshalBinary(dat []byte) (int, error) { return len(dat), nil } -// Rather than returning a separate error value, return an Error item. +// UnmarshalItem consumes the byte slice `dat`, unmarshaling it in to +// the item type specified by `key`. +// +// If there is an error, rather than returning a separate error value, +// return an Error item. func UnmarshalItem(key btrfsprim.Key, csumType btrfssum.CSumType, dat []byte) Item { var gotyp reflect.Type if key.ItemType == UNTYPED_KEY { diff --git a/lib/btrfs/btrfsprim/key.go b/lib/btrfs/btrfsprim/key.go index b07cc8c..5580c52 100644 --- a/lib/btrfs/btrfsprim/key.go +++ b/lib/btrfs/btrfsprim/key.go @@ -21,7 +21,10 @@ type Key struct { const MaxOffset uint64 = math.MaxUint64 -// mimics print-tree.c:btrfs_print_key() +// Format returns a human-friendly string representation of the Key, +// according to which tree it appears in. +// +// The formatting of the key mimics print-tree.c:btrfs_print_key(). func (key Key) Format(tree ObjID) string { switch tree { case UUID_TREE_OBJECTID: @@ -39,12 +42,11 @@ func (key Key) Format(tree ObjID) string { return fmt.Sprintf("(%v %v -1)", key.ObjectID.Format(tree), key.ItemType) - } else { - return fmt.Sprintf("(%v %v %v)", - key.ObjectID.Format(tree), - key.ItemType, - key.Offset) } + return fmt.Sprintf("(%v %v %v)", + key.ObjectID.Format(tree), + key.ItemType, + key.Offset) } } diff --git a/lib/btrfs/btrfsprim/misc.go b/lib/btrfs/btrfsprim/misc.go index 38290d6..43ba306 100644 --- a/lib/btrfs/btrfsprim/misc.go +++ b/lib/btrfs/btrfsprim/misc.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfsprim contains primitive btrfs datatypes, that all +// other btrfs sub-packages may make use of. package btrfsprim import ( diff --git a/lib/btrfs/btrfssum/csum.go b/lib/btrfs/btrfssum/csum.go index 157371e..341eade 100644 --- a/lib/btrfs/btrfssum/csum.go +++ b/lib/btrfs/btrfssum/csum.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfssum contains the checksum types and algorithms that +// btrfs uses. package btrfssum import ( diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go index 4c10ffa..89d4f9d 100644 --- a/lib/btrfs/btrfstree/btree.go +++ b/lib/btrfs/btrfstree/btree.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfstree contains core b+-tree implementation and +// interfaces. package btrfstree import ( diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go index df58c0c..1e3c789 100644 --- a/lib/btrfs/btrfstree/btree_tree.go +++ b/lib/btrfs/btrfstree/btree_tree.go @@ -188,7 +188,8 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, return nil, nil, err } - if node.Data.Head.Level > 0 { + switch { + case node.Data.Head.Level > 0: // interior node // Search for the right-most node.Data.BodyInterior item for which @@ -220,7 +221,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, ToMaxKey: toMaxKey, }) FreeNodeRef(node) - } else { + default: // leaf node // Search for a member of node.Data.BodyLeaf for which diff --git a/lib/btrfs/btrfstree/path.go b/lib/btrfs/btrfstree/path.go index 9b1a5c7..b9ab5bc 100644 --- a/lib/btrfs/btrfstree/path.go +++ b/lib/btrfs/btrfstree/path.go @@ -101,23 +101,22 @@ func (elem TreePathElem) writeNodeTo(w io.Writer) { func (path TreePath) String() string { if len(path) == 0 { return "(empty-path)" + } + var ret strings.Builder + fmt.Fprintf(&ret, "%s->", path[0].FromTree.Format(btrfsprim.ROOT_TREE_OBJECTID)) + if len(path) == 1 && path[0] == (TreePathElem{FromTree: path[0].FromTree, FromItemSlot: -1}) { + ret.WriteString("(empty-path)") } else { - var ret strings.Builder - fmt.Fprintf(&ret, "%s->", path[0].FromTree.Format(btrfsprim.ROOT_TREE_OBJECTID)) - if len(path) == 1 && path[0] == (TreePathElem{FromTree: path[0].FromTree, FromItemSlot: -1}) { - ret.WriteString("(empty-path)") - } else { - path[0].writeNodeTo(&ret) - } - for _, elem := range path[1:] { - fmt.Fprintf(&ret, "[%v]", elem.FromItemSlot) - if elem.ToNodeAddr != 0 { - ret.WriteString("->") - elem.writeNodeTo(&ret) - } + path[0].writeNodeTo(&ret) + } + for _, elem := range path[1:] { + fmt.Fprintf(&ret, "[%v]", elem.FromItemSlot) + if elem.ToNodeAddr != 0 { + ret.WriteString("->") + elem.writeNodeTo(&ret) } - return ret.String() } + return ret.String() } func (path TreePath) DeepCopy() TreePath { @@ -128,9 +127,10 @@ func (path TreePath) Parent() TreePath { return path[:len(path)-1] } -// path.Node(x) is like &path[x], but negative values of x move down -// from the end of path (similar to how lists work in many other -// languages, such as Python). +// Node is returns an element from the path; `path.Node(x)` is like +// `&path[x]`, but negative values of x move down from the end of path +// (similar to how lists work in many other languages, such as +// Python). func (path TreePath) Node(x int) *TreePathElem { if x < 0 { x += len(path) diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 150539d..8295ccb 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -113,20 +113,22 @@ type NodeHeader struct { // .Head.NumItems. func (node Node) MaxItems() uint32 { bodyBytes := node.Size - uint32(nodeHeaderSize) - if node.Head.Level > 0 { + switch { + case node.Head.Level > 0: return bodyBytes / uint32(keyPointerSize) - } else { + default: return bodyBytes / uint32(itemHeaderSize) } } func (node Node) MinItem() (btrfsprim.Key, bool) { - if node.Head.Level > 0 { + switch { + case node.Head.Level > 0: if len(node.BodyInterior) == 0 { return btrfsprim.Key{}, false } return node.BodyInterior[0].Key, true - } else { + default: if len(node.BodyLeaf) == 0 { return btrfsprim.Key{}, false } @@ -135,12 +137,13 @@ func (node Node) MinItem() (btrfsprim.Key, bool) { } func (node Node) MaxItem() (btrfsprim.Key, bool) { - if node.Head.Level > 0 { + switch { + case node.Head.Level > 0: if len(node.BodyInterior) == 0 { return btrfsprim.Key{}, false } return node.BodyInterior[len(node.BodyInterior)-1].Key, true - } else { + default: if len(node.BodyLeaf) == 0 { return btrfsprim.Key{}, false } @@ -221,15 +224,15 @@ func (node Node) MarshalBinary() ([]byte, error) { buf := make([]byte, node.Size) - if bs, err := binstruct.Marshal(node.Head); err != nil { + bs, err := binstruct.Marshal(node.Head) + if err != nil { return buf, err - } else { - if len(bs) != nodeHeaderSize { - return nil, fmt.Errorf("header is %v bytes but expected %v", - len(bs), nodeHeaderSize) - } - copy(buf, bs) } + if len(bs) != nodeHeaderSize { + return nil, fmt.Errorf("header is %v bytes but expected %v", + len(bs), nodeHeaderSize) + } + copy(buf, bs) if node.Head.Level > 0 { if err := node.marshalInteriorTo(buf[nodeHeaderSize:]); err != nil { @@ -456,6 +459,8 @@ func newNodeRef[Addr ~int64]() *diskio.Ref[Addr, Node] { return (*diskio.Ref[Addr, Node])(unsafe.Pointer(ret)) //nolint:gosec // I know it's unsafe. } +// ReadNode reads a node from the given file. +// // It is possible that both a non-nil diskio.Ref and an error are // returned. The error returned (if non-nil) is always of type // *NodeError[Addr]. Notable errors that may be inside of the diff --git a/lib/btrfs/btrfsvol/lvm.go b/lib/btrfs/btrfsvol/lvm.go index 51e2263..3834345 100644 --- a/lib/btrfs/btrfsvol/lvm.go +++ b/lib/btrfs/btrfsvol/lvm.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfsvol contains core logical-volume-management layer of +// btrfs. package btrfsvol import ( diff --git a/lib/btrfs/io1_pv.go b/lib/btrfs/io1_pv.go index 72d33f5..3b13f73 100644 --- a/lib/btrfs/io1_pv.go +++ b/lib/btrfs/io1_pv.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfs (and its sub-packages) are the core implementation of +// the btrfs filesystem. package btrfs import ( diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index e146739..b1a1232 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -122,7 +122,7 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { }) if err != nil { val.Errs = append(val.Errs, err) - return + return val } switch itemBody := item.Body.(type) { @@ -135,7 +135,7 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { panic(fmt.Errorf("should not happen: INODE_ITEM has unexpected item type: %T", itemBody)) } - return + return val }) if val.InodeItem == nil { return nil, val.Errs @@ -156,7 +156,7 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { if err != nil { val.Errs = append(val.Errs, err) if len(items) == 0 { - return + return val } } for _, item := range items { @@ -190,7 +190,7 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { val.OtherItems = append(val.OtherItems, item) } } - return + return val }) if val.InodeItem == nil && val.OtherItems == nil { return nil, val.Errs @@ -205,12 +205,12 @@ func (sv *Subvolume) LoadDir(inode btrfsprim.ObjID) (*Dir, error) { fullInode, err := sv.LoadFullInode(inode) if err != nil { val.Errs = append(val.Errs, err) - return + return val } val.FullInode = *fullInode val.SV = sv val.populate() - return + return val }) if val.Inode == 0 { return nil, val.Errs @@ -342,12 +342,12 @@ func (sv *Subvolume) LoadFile(inode btrfsprim.ObjID) (*File, error) { fullInode, err := sv.LoadFullInode(inode) if err != nil { val.Errs = append(val.Errs, err) - return + return val } val.FullInode = *fullInode val.SV = sv val.populate() - return + return val }) if val.Inode == 0 { return nil, val.Errs diff --git a/lib/btrfscheck/graph.go b/lib/btrfscheck/graph.go index ea51818..806f609 100644 --- a/lib/btrfscheck/graph.go +++ b/lib/btrfscheck/graph.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfscheck implements userspace utilities for checking +// btrfs filesystems. package btrfscheck import ( @@ -45,7 +47,7 @@ func HandleItemWouldBeNoOp(typ btrfsprim.ItemType) bool { } } -func HandleItem(o GraphCallbacks, ctx context.Context, treeID btrfsprim.ObjID, item btrfstree.Item) { +func HandleItem(ctx context.Context, o GraphCallbacks, treeID btrfsprim.ObjID, item btrfstree.Item) { // Notionally, just express the relationships shown in // https://btrfs.wiki.kernel.org/index.php/File:References.png (from the page // https://btrfs.wiki.kernel.org/index.php/Data_Structures ) diff --git a/lib/btrfsutil/doc.go b/lib/btrfsutil/doc.go new file mode 100644 index 0000000..4d00cb3 --- /dev/null +++ b/lib/btrfsutil/doc.go @@ -0,0 +1,7 @@ +// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +// Package btrfsutil implements userspace utilities for working with +// btrfs filesystems. +package btrfsutil diff --git a/lib/btrfsutil/listnodes.go b/lib/btrfsutil/listnodes.go index 16300da..5505d23 100644 --- a/lib/btrfsutil/listnodes.go +++ b/lib/btrfsutil/listnodes.go @@ -30,7 +30,7 @@ func (s nodeStats) String() string { var _ DeviceScanner[nodeStats, containers.Set[btrfsvol.LogicalAddr]] = (*nodeScanner)(nil) -func newNodeScanner(ctx context.Context, sb btrfstree.Superblock, numBytes btrfsvol.PhysicalAddr, numSectors int) DeviceScanner[nodeStats, containers.Set[btrfsvol.LogicalAddr]] { +func newNodeScanner(context.Context, btrfstree.Superblock, btrfsvol.PhysicalAddr, int) DeviceScanner[nodeStats, containers.Set[btrfsvol.LogicalAddr]] { s := new(nodeScanner) s.nodes = make(containers.Set[btrfsvol.LogicalAddr]) return s @@ -40,16 +40,16 @@ func (s *nodeScanner) ScanStats() nodeStats { return nodeStats{numNodes: len(s.nodes)} } -func (*nodeScanner) ScanSector(ctx context.Context, dev *btrfs.Device, paddr btrfsvol.PhysicalAddr) error { +func (*nodeScanner) ScanSector(context.Context, *btrfs.Device, btrfsvol.PhysicalAddr) error { return nil } -func (s *nodeScanner) ScanNode(ctx context.Context, nodeRef *diskio.Ref[btrfsvol.PhysicalAddr, btrfstree.Node]) error { +func (s *nodeScanner) ScanNode(_ context.Context, nodeRef *diskio.Ref[btrfsvol.PhysicalAddr, btrfstree.Node]) error { s.nodes.Insert(nodeRef.Data.Head.Addr) return nil } -func (s *nodeScanner) ScanDone(ctx context.Context) (containers.Set[btrfsvol.LogicalAddr], error) { +func (s *nodeScanner) ScanDone(_ context.Context) (containers.Set[btrfsvol.LogicalAddr], error) { return s.nodes, nil } diff --git a/lib/btrfsutil/print_addrspace.go b/lib/btrfsutil/print_addrspace.go index c9c51f0..ae2c492 100644 --- a/lib/btrfsutil/print_addrspace.go +++ b/lib/btrfsutil/print_addrspace.go @@ -49,7 +49,7 @@ func PrintPhysicalSpace(out io.Writer, fs *btrfs.FS) { return mappings[i].PAddr.Compare(mappings[j].PAddr) < 0 }) - var prevDev btrfsvol.DeviceID = 0 + var prevDev btrfsvol.DeviceID var prevEnd btrfsvol.PhysicalAddr var sumHole, sumExt btrfsvol.AddrDelta for _, mapping := range mappings { diff --git a/lib/containers/doc.go b/lib/containers/doc.go new file mode 100644 index 0000000..1725e31 --- /dev/null +++ b/lib/containers/doc.go @@ -0,0 +1,7 @@ +// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +// Package containers implements generic (type-parameterized) datatype +// containers. +package containers diff --git a/lib/containers/intervaltree.go b/lib/containers/intervaltree.go index 7b96526..d2e2732 100644 --- a/lib/containers/intervaltree.go +++ b/lib/containers/intervaltree.go @@ -39,7 +39,7 @@ type IntervalTree[K Ordered[K], V any] struct { inner RBTree[intervalValue[K, V]] } -func (t *IntervalTree[K, V]) attrFn(node *RBNode[intervalValue[K, V]]) { +func (*IntervalTree[K, V]) attrFn(node *RBNode[intervalValue[K, V]]) { max := node.Value.ValSpan.Max if node.Left != nil && node.Left.Value.ChildSpan.Max.Compare(max) > 0 { max = node.Left.Value.ChildSpan.Max diff --git a/lib/containers/linkedlist.go b/lib/containers/linkedlist.go index 7d40479..07b4760 100644 --- a/lib/containers/linkedlist.go +++ b/lib/containers/linkedlist.go @@ -8,7 +8,7 @@ import ( "git.lukeshu.com/go/typedsync" ) -// LinkedListEntry[T] is an entry in a LinkedList[T]. +// LinkedListEntry [T] is an entry in a LinkedList [T]. type LinkedListEntry[T any] struct { older, newer *LinkedListEntry[T] Value T diff --git a/lib/containers/optional.go b/lib/containers/optional.go index c0e7b32..5bb7bb6 100644 --- a/lib/containers/optional.go +++ b/lib/containers/optional.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later @@ -19,11 +19,10 @@ var ( ) func (o Optional[T]) MarshalJSON() ([]byte, error) { - if o.OK { - return json.Marshal(o.Val) - } else { + if !o.OK { return []byte("null"), nil } + return json.Marshal(o.Val) } func (o *Optional[T]) UnmarshalJSON(dat []byte) error { diff --git a/lib/containers/ordered.go b/lib/containers/ordered.go index 1ebc17e..1289b45 100644 --- a/lib/containers/ordered.go +++ b/lib/containers/ordered.go @@ -12,7 +12,7 @@ type _Ordered[T any] interface { Compare(T) int } -// An Ordered[T] is a type that has a +// An Ordered is a type that has a // // func (a T) Compare(b T) int // @@ -36,10 +36,10 @@ type NativeOrdered[T constraints.Ordered] struct { Val T } -// NativeCompare[T] implements the Ordered[T] Compare operation for +// NativeCompare implements the Ordered[T] Compare operation for // natively-ordered (integer types, float types, and string types). -// While this operation be conceptualized as subtration, -// NativeCompare[T] is careful to avoid integer overflow. +// While this operation be conceptualized as subtration, NativeCompare +// is careful to avoid integer overflow. func NativeCompare[T constraints.Ordered](a, b T) int { switch { case a < b: diff --git a/lib/containers/rbtree.go b/lib/containers/rbtree.go index 6182150..59f63aa 100644 --- a/lib/containers/rbtree.go +++ b/lib/containers/rbtree.go @@ -167,9 +167,8 @@ func (t *RBTree[T]) Subrange(rangeFn func(T) int, handleFn func(*RBNode[T]) bool _, node := t.root.search(func(v T) int { if rangeFn(v) <= 0 { return -1 - } else { - return 1 } + return 1 }) for node != nil && rangeFn(node.Value) > 0 { node = node.Next() diff --git a/lib/containers/rbtree_test.go b/lib/containers/rbtree_test.go index d2fe931..c6e7a3b 100644 --- a/lib/containers/rbtree_test.go +++ b/lib/containers/rbtree_test.go @@ -108,25 +108,25 @@ func checkRBTree[T constraints.Ordered](t *testing.T, expectedSet Set[T], tree * } func FuzzRBTree(f *testing.F) { - Ins := uint8(0b0100_0000) - Del := uint8(0) + ins := uint8(0b0100_0000) + del := uint8(0) f.Add([]uint8{}) - f.Add([]uint8{Ins | 5, Del | 5}) - f.Add([]uint8{Ins | 5, Del | 6}) - f.Add([]uint8{Del | 6}) + f.Add([]uint8{ins | 5, del | 5}) + f.Add([]uint8{ins | 5, del | 6}) + f.Add([]uint8{del | 6}) f.Add([]uint8{ // CLRS Figure 14.4 - Ins | 1, - Ins | 2, - Ins | 5, - Ins | 7, - Ins | 8, - Ins | 11, - Ins | 14, - Ins | 15, - - Ins | 4, + ins | 1, + ins | 2, + ins | 5, + ins | 7, + ins | 8, + ins | 11, + ins | 14, + ins | 15, + + ins | 4, }) f.Fuzz(func(t *testing.T, dat []uint8) { diff --git a/lib/containers/set.go b/lib/containers/set.go index 0d9202c..074d126 100644 --- a/lib/containers/set.go +++ b/lib/containers/set.go @@ -14,7 +14,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/maps" ) -// Set[T] is an unordered set of T. +// Set is an unordered set of T. type Set[T comparable] map[T]struct{} var ( diff --git a/lib/diskio/file_blockbuf.go b/lib/diskio/file_blockbuf.go index b7db849..0bb3156 100644 --- a/lib/diskio/file_blockbuf.go +++ b/lib/diskio/file_blockbuf.go @@ -99,5 +99,5 @@ func (bf *bufferedFile[A]) WriteAt(dat []byte, off A) (n int, err error) { bf.blockCache.Delete(blockOffset) } - return + return n, err } diff --git a/lib/diskio/file_iface.go b/lib/diskio/file_iface.go index 206db0c..d26ffcc 100644 --- a/lib/diskio/file_iface.go +++ b/lib/diskio/file_iface.go @@ -1,7 +1,8 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later +// Package diskio implements utilities for working with disk I/O. package diskio import ( diff --git a/lib/diskio/file_state_test.go b/lib/diskio/file_state_test.go index 3f0c119..32ca705 100644 --- a/lib/diskio/file_state_test.go +++ b/lib/diskio/file_state_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later @@ -21,11 +21,11 @@ func (r byteReaderWithName) Name() string { return r.name } -func (r byteReaderWithName) Close() error { +func (byteReaderWithName) Close() error { return nil } -func (r byteReaderWithName) WriteAt([]byte, int64) (int, error) { +func (byteReaderWithName) WriteAt([]byte, int64) (int, error) { panic("not implemented") } diff --git a/lib/fmtutil/fmt.go b/lib/fmtutil/fmt.go index b310eb6..bad4a30 100644 --- a/lib/fmtutil/fmt.go +++ b/lib/fmtutil/fmt.go @@ -1,7 +1,9 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later +// Package fmtutil provides utilities for implementing the interfaces +// consumed by the "fmt" package. package fmtutil import ( diff --git a/lib/fmtutil/fmt_test.go b/lib/fmtutil/fmt_test.go index 2c63c2e..6d21b3e 100644 --- a/lib/fmtutil/fmt_test.go +++ b/lib/fmtutil/fmt_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later @@ -53,11 +53,11 @@ func (st FmtState) Flag(b int) bool { return false } -func (st FmtState) Write([]byte) (int, error) { +func (FmtState) Write([]byte) (int, error) { panic("not implemented") } -func (dst *FmtState) Format(src fmt.State, verb rune) { +func (dst *FmtState) Format(src fmt.State, _ rune) { if width, ok := src.Width(); ok { dst.MWidth = width } diff --git a/lib/maps/maputil.go b/lib/maps/maputil.go index aeebe12..d409e70 100644 --- a/lib/maps/maputil.go +++ b/lib/maps/maputil.go @@ -1,7 +1,9 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later +// Package maps implements generic (type-parameterized) utilities for +// working with simple Go maps. package maps import ( diff --git a/lib/profile/cobra.go b/lib/profile/cobra.go index 3094015..9bc55dd 100644 --- a/lib/profile/cobra.go +++ b/lib/profile/cobra.go @@ -67,7 +67,7 @@ func (fv *flagValue) Set(filename string) error { } // Type implements pflag.Value. -func (fv *flagValue) Type() string { return "filename" } +func (*flagValue) Type() string { return "filename" } func pStart(name string) startFunc { return func(w io.Writer) (StopFunc, error) { diff --git a/lib/profile/profile.go b/lib/profile/profile.go index 27c7e61..0910e5c 100644 --- a/lib/profile/profile.go +++ b/lib/profile/profile.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package profile implements a uniform interface for getting +// profiling information from the Go runtime. package profile import ( diff --git a/lib/slices/sliceutil.go b/lib/slices/sliceutil.go index 567f9ec..b8823d3 100644 --- a/lib/slices/sliceutil.go +++ b/lib/slices/sliceutil.go @@ -1,7 +1,9 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> // // SPDX-License-Identifier: GPL-2.0-or-later +// Package slices implements generic (type-parameterized) utilities +// for working with simple Go slices. package slices import ( @@ -93,7 +95,7 @@ func max(a, b int) int { return b } -// Search the slice for a value for which `fn(slice[i]) = 0`. +// Search searches the slice for a value for which `fn(slice[i]) = 0`. // // : + + + 0 0 0 - - - // : ^ ^ ^ @@ -121,7 +123,8 @@ func Search[T any](slice []T, fn func(T) int) (int, bool) { return 0, false } -// Search the slice for the left-most value for which `fn(slice[i]) = 0`. +// SearchLowest searches the slice for the left-most value for which +// `fn(slice[i]) = 0`. // // : + + + 0 0 0 - - - // : ^ @@ -151,7 +154,8 @@ func SearchLowest[T any](slice []T, fn func(T) int) (int, bool) { return firstGood, true } -// Search the slice for the right-most value for which `fn(slice[i]) = 0`. +// SearchHighest searches the slice for the right-most value for which +// `fn(slice[i]) = 0`. // // : + + + 0 0 0 - - - // : ^ diff --git a/lib/streamio/runescanner.go b/lib/streamio/runescanner.go index 451f32f..203439f 100644 --- a/lib/streamio/runescanner.go +++ b/lib/streamio/runescanner.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package streamio implements utilities for working with streaming +// I/O. package streamio import ( @@ -87,7 +89,7 @@ func (rs *runeScanner) ReadRune() (r rune, size int, err error) { rs.progressWriter.Set(rs.progress) } } - return + return r, size, err } // ReadRune implements io.RuneScanner. diff --git a/lib/textui/log.go b/lib/textui/log.go index 0a10ef6..9aff364 100644 --- a/lib/textui/log.go +++ b/lib/textui/log.go @@ -35,9 +35,9 @@ type LogLevelFlag struct { var _ pflag.Value = (*LogLevelFlag)(nil) // Type implements pflag.Value. -func (lvl *LogLevelFlag) Type() string { return "loglevel" } +func (*LogLevelFlag) Type() string { return "loglevel" } -// Type implements pflag.Value. +// Set implements pflag.Value. func (lvl *LogLevelFlag) Set(str string) error { switch strings.ToLower(str) { case "error": @@ -56,7 +56,7 @@ func (lvl *LogLevelFlag) Set(str string) error { return nil } -// Type implements pflag.Value. +// String implements fmt.Stringer (and pflag.Value). func (lvl *LogLevelFlag) String() string { switch lvl.Level { case dlog.LogLevelError: @@ -94,7 +94,7 @@ func NewLogger(out io.Writer, lvl dlog.LogLevel) dlog.Logger { } // Helper implements dlog.Logger. -func (l *logger) Helper() {} +func (*logger) Helper() {} // WithField implements dlog.Logger. func (l *logger) WithField(key string, value any) dlog.Logger { @@ -127,7 +127,7 @@ func (l *logger) StdLogger(lvl dlog.LogLevel) *log.Logger { } // Log implements dlog.Logger. -func (l *logger) Log(lvl dlog.LogLevel, msg string) { +func (*logger) Log(dlog.LogLevel, string) { panic("should not happen: optimized log methods should be used instead") } diff --git a/lib/textui/text.go b/lib/textui/text.go index c0a3c5e..538bac2 100644 --- a/lib/textui/text.go +++ b/lib/textui/text.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package textui implements utilities for emitting human-friendly +// text on stdout and stderr. package textui import ( |