Browse Source

golangci-lint: added more linters

Also fixed pre-existing lint errors.
Jarek Kowalski 6 years ago
parent
commit
72520029b0
83 changed files with 386 additions and 340 deletions
  1. 1 1
      .gitignore
  2. 57 0
      .golangci.yml
  3. 1 1
      Makefile
  4. 2 2
      cli/analytics.go
  5. 5 7
      cli/cli_progress.go
  6. 1 1
      cli/command_benchmark_crypto.go
  7. 2 2
      cli/command_content_list.go
  8. 8 12
      cli/command_content_rewrite.go
  9. 4 3
      cli/command_ls.go
  10. 6 5
      cli/command_mount_browse.go
  11. 3 3
      cli/command_object_verify.go
  12. 1 1
      cli/command_policy_edit.go
  13. 4 8
      cli/command_policy_set.go
  14. 3 0
      cli/command_policy_show.go
  15. 3 3
      cli/command_repository_repair.go
  16. 2 2
      cli/command_server_upload.go
  17. 9 6
      cli/command_snapshot_list.go
  18. 5 5
      cli/command_snapshot_migrate.go
  19. 5 5
      cli/password.go
  20. 7 2
      cli/storage_filesystem.go
  21. 1 2
      cli/storage_providers.go
  22. 3 2
      fs/ignorefs/ignorefs_test.go
  23. 1 0
      fs/localfs/local_fs_test.go
  24. 1 2
      internal/diff/diff.go
  25. 4 4
      internal/editor/editor.go
  26. 1 1
      internal/ignore/ignore.go
  27. 8 6
      internal/jsonstream/stream_test.go
  28. 0 1
      internal/jsonstream/writer.go
  29. 1 1
      internal/mockfs/mockfs.go
  30. 1 0
      internal/parallelwork/parallel_work_queue.go
  31. 1 1
      internal/retry/retry_test.go
  32. 1 2
      internal/scrubber/scrub_sensitive.go
  33. 1 1
      internal/server/api_sources_list.go
  34. 1 1
      internal/server/server.go
  35. 2 2
      internal/server/source_manager.go
  36. 1 1
      internal/serverapi/serverapi.go
  37. 1 1
      internal/throttle/round_tripper.go
  38. 1 0
      internal/throttle/round_tripper_test.go
  39. 2 2
      internal/units/units.go
  40. 10 6
      repo/blob/filesystem/filesystem_storage.go
  41. 3 3
      repo/blob/gcs/gcs_storage.go
  42. 2 2
      repo/blob/s3/s3_storage_test.go
  43. 9 5
      repo/blob/webdav/webdav_storage.go
  44. 1 0
      repo/blob/webdav/webdav_storage_test.go
  45. 1 1
      repo/content/block_manager_compaction.go
  46. 1 0
      repo/content/builder.go
  47. 2 2
      repo/content/cache_hmac.go
  48. 2 2
      repo/content/committed_content_index.go
  49. 4 4
      repo/content/content_cache.go
  50. 2 2
      repo/content/content_cache_test.go
  51. 20 20
      repo/content/content_formatter.go
  52. 3 3
      repo/content/content_formatter_test.go
  53. 1 2
      repo/content/content_formatting_options.go
  54. 2 0
      repo/content/content_index_recovery.go
  55. 3 3
      repo/content/content_index_recovery_test.go
  56. 20 22
      repo/content/content_manager.go
  57. 15 17
      repo/content/content_manager_test.go
  58. 1 1
      repo/content/info.go
  59. 5 5
      repo/content/list_cache.go
  60. 4 2
      repo/content/packindex_test.go
  61. 1 1
      repo/crypto_key_derivation.go
  62. 1 0
      repo/format_block_test.go
  63. 4 4
      repo/manifest/manifest_manager.go
  64. 3 2
      repo/manifest/manifest_manager_test.go
  65. 0 3
      repo/object/object_manager.go
  66. 8 8
      repo/object/object_manager_test.go
  67. 4 1
      repo/object/object_reader.go
  68. 1 1
      repo/object/object_splitter.go
  69. 13 11
      repo/object/object_splitter_test.go
  70. 1 2
      repo/object/splitter_buzhash32.go
  71. 1 0
      repo/object/splitter_rabinkarp64.go
  72. 2 2
      repo/open.go
  73. 8 33
      repo/repository_test.go
  74. 1 7
      site/cli2md/cli2md.go
  75. 6 6
      snapshot/manager.go
  76. 1 1
      snapshot/policy/policy_manager.go
  77. 2 2
      snapshot/policy/retention_policy.go
  78. 15 16
      snapshot/snapshotfs/upload.go
  79. 22 18
      snapshot/snapshotfs/upload_test.go
  80. 1 1
      snapshot/source.go
  81. 3 2
      tests/end_to_end_test/end_to_end_test.go
  82. 4 4
      tests/repository_stress_test/repository_stress_test.go
  83. 12 14
      tests/stress_test/stress_test.go

+ 1 - 1
.gitignore

@@ -11,4 +11,4 @@ dist/
 kopia
 kopia.exe
 Makefile.local.mk
-
+.linterr.txt

+ 57 - 0
.golangci.yml

@@ -0,0 +1,57 @@
+linters-settings:
+  govet:
+    check-shadowing: true
+    settings:
+      printf:
+        funcs:
+          - (github.com/op/go-logging/Logger).Infof
+          - (github.com/op/go-logging/Logger).Warningf
+          - (github.com/op/go-logging/Logger).Errorf
+          - (github.com/op/go-logging/Logger).Fatalf
+  golint:
+    min-confidence: 0
+  gocyclo:
+    min-complexity: 15
+  maligned:
+    suggest-new: true
+  dupl:
+    threshold: 100
+  goconst:
+    min-len: 5
+    min-occurrences: 3
+  misspell:
+    locale: US
+  lll:
+    line-length: 256
+  goimports:
+    local-prefixes: github.com/kopia/kopia
+  gocritic:
+    enabled-tags:
+      - performance
+      - style
+      - experimental
+    disabled-checks:
+      - wrapperFunc
+
+linters:
+  enable-all: true
+  disable:
+    - maligned
+    - prealloc
+    - gochecknoglobals
+    - gochecknoinits
+
+run:
+  skip-dirs:
+    - test/testdata_etc
+
+issues:
+  exclude-rules:
+    - text: "weak cryptographic primitive"
+      linters:
+        - gosec
+
+# golangci.com configuration
+# https://github.com/golangci/golangci/wiki/Configuration
+service:
+  golangci-lint-version: 1.16.x # use the fixed version to not introduce new linters unexpectedly

+ 1 - 1
Makefile

@@ -16,7 +16,7 @@ play:
 	go run cmd/playground/main.go
 
 lint: $(LINTER_TOOL)
-	$(LINTER_TOOL) run
+	$(LINTER_TOOL) --deadline 180s run | tee .linterr.txt
 
 vet:
 	go vet -all .

+ 2 - 2
cli/analytics.go

@@ -1,7 +1,7 @@
 package cli
 
 import (
-	"crypto/rand"
+	cryptorand "crypto/rand"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -75,7 +75,7 @@ func displayAnalyticsConsentPrompt(clientID string) bool {
 func promptForAnalyticsConsent() {
 	// generate 64-bit ID as 16 hex digits.
 	x := make([]byte, 8)
-	rand.Read(x) //nolint:errcheck
+	cryptorand.Read(x) //nolint:errcheck
 	clientID := fmt.Sprintf("%x", x)
 
 	switch *analyticsConsent {

+ 5 - 7
cli/cli_progress.go

@@ -17,7 +17,7 @@ type singleProgress struct {
 	total     int64
 }
 
-func (p *singleProgress) update(progress int64, total int64) {
+func (p *singleProgress) update(progress, total int64) {
 	p.total = total
 	p.progress = progress
 }
@@ -54,7 +54,7 @@ type multiProgress struct {
 	items []*singleProgress
 }
 
-func (mp *multiProgress) findLocked(desc string) (*singleProgress, int) {
+func (mp *multiProgress) findLocked(desc string) (progress *singleProgress, ordinal int) {
 	for i, p := range mp.items {
 		if p.desc == desc {
 			return p, i
@@ -64,7 +64,7 @@ func (mp *multiProgress) findLocked(desc string) (*singleProgress, int) {
 	return nil, 0
 }
 
-func (mp *multiProgress) Report(desc string, progress int64, total int64) {
+func (mp *multiProgress) Report(desc string, progress, total int64) {
 	mp.mu.Lock()
 	defer mp.mu.Unlock()
 
@@ -95,10 +95,8 @@ func (mp *multiProgress) Report(desc string, progress int64, total int64) {
 		if len(segments) > 0 {
 			log.Notice(segments[len(segments)-1])
 		}
-	} else {
-		if len(segments) > 0 {
-			log.Info(segments[len(segments)-1])
-		}
+	} else if len(segments) > 0 {
+		log.Info(segments[len(segments)-1])
 	}
 }
 

+ 1 - 1
cli/command_benchmark_crypto.go

@@ -34,7 +34,7 @@ func runBenchmarkCryptoAction(ctx *kingpin.ParseContext) error {
 				continue
 			}
 
-			h, e, err := content.CreateHashAndEncryptor(content.FormattingOptions{
+			h, e, err := content.CreateHashAndEncryptor(&content.FormattingOptions{
 				Encryption: ea,
 				Hash:       ha,
 				MasterKey:  make([]byte, 32),

+ 2 - 2
cli/command_content_list.go

@@ -84,11 +84,11 @@ func sortContents(contents []content.Info) {
 	case "time":
 		sort.Slice(contents, func(i, j int) bool { return maybeReverse(contents[i].TimestampSeconds < contents[j].TimestampSeconds) })
 	case "pack":
-		sort.Slice(contents, func(i, j int) bool { return maybeReverse(comparePacks(contents[i], contents[j])) })
+		sort.Slice(contents, func(i, j int) bool { return maybeReverse(comparePacks(&contents[i], &contents[j])) })
 	}
 }
 
-func comparePacks(a, b content.Info) bool {
+func comparePacks(a, b *content.Info) bool {
 	if a, b := a.PackBlobID, b.PackBlobID; a != b {
 		return a < b
 	}

+ 8 - 12
cli/command_content_rewrite.go

@@ -98,12 +98,12 @@ func getContentToRewrite(ctx context.Context, rep *repo.Repository) <-chan conte
 		// add all content IDs from short packs
 		if *contentRewriteShortPacks {
 			threshold := uint32(rep.Content.Format.MaxPackSize * 6 / 10)
-			findContentInShortPacks(ctx, rep, ch, threshold)
+			findContentInShortPacks(rep, ch, threshold)
 		}
 
 		// add all blocks with given format version
 		if *contentRewriteFormatVersion != -1 {
-			findContentWithFormatVersion(ctx, rep, ch, *contentRewriteFormatVersion)
+			findContentWithFormatVersion(rep, ch, *contentRewriteFormatVersion)
 		}
 	}()
 
@@ -129,7 +129,7 @@ func findContentInfos(ctx context.Context, rep *repo.Repository, ch chan content
 	}
 }
 
-func findContentWithFormatVersion(ctx context.Context, rep *repo.Repository, ch chan contentInfoOrError, version int) {
+func findContentWithFormatVersion(rep *repo.Repository, ch chan contentInfoOrError, version int) {
 	infos, err := rep.Content.ListContentInfos("", true)
 	if err != nil {
 		ch <- contentInfoOrError{err: errors.Wrap(err, "unable to list index blobs")}
@@ -137,13 +137,13 @@ func findContentWithFormatVersion(ctx context.Context, rep *repo.Repository, ch
 	}
 
 	for _, b := range infos {
-		if int(b.FormatVersion) == *contentRewriteFormatVersion && strings.HasPrefix(string(b.PackBlobID), *contentRewritePackPrefix) {
+		if int(b.FormatVersion) == version && strings.HasPrefix(string(b.PackBlobID), *contentRewritePackPrefix) {
 			ch <- contentInfoOrError{Info: b}
 		}
 	}
 }
 
-func findContentInShortPacks(ctx context.Context, rep *repo.Repository, ch chan contentInfoOrError, threshold uint32) {
+func findContentInShortPacks(rep *repo.Repository, ch chan contentInfoOrError, threshold uint32) {
 	log.Debugf("listing contents...")
 	infos, err := rep.Content.ListContentInfos("", true)
 	if err != nil {
@@ -152,11 +152,7 @@ func findContentInShortPacks(ctx context.Context, rep *repo.Repository, ch chan
 	}
 
 	log.Debugf("finding content in short pack blobs...")
-	shortPackBlocks, err := findShortPackBlobs(infos, threshold)
-	if err != nil {
-		ch <- contentInfoOrError{err: errors.Wrap(err, "unable to find short pack blobs")}
-		return
-	}
+	shortPackBlocks := findShortPackBlobs(infos, threshold)
 	log.Debugf("found %v short pack blobs", len(shortPackBlocks))
 
 	if len(shortPackBlocks) <= 1 {
@@ -170,7 +166,7 @@ func findContentInShortPacks(ctx context.Context, rep *repo.Repository, ch chan
 	}
 }
 
-func findShortPackBlobs(infos []content.Info, threshold uint32) (map[blob.ID]bool, error) {
+func findShortPackBlobs(infos []content.Info, threshold uint32) map[blob.ID]bool {
 	packUsage := map[blob.ID]uint32{}
 
 	for _, bi := range infos {
@@ -185,7 +181,7 @@ func findShortPackBlobs(infos []content.Info, threshold uint32) (map[blob.ID]boo
 		}
 	}
 
-	return shortPackBlocks, nil
+	return shortPackBlocks
 }
 
 func init() {

+ 4 - 3
cli/command_ls.go

@@ -53,7 +53,8 @@ func listDirectory(ctx context.Context, rep *repo.Repository, prefix string, oid
 		var info string
 		objectID := e.(object.HasObjectID).ObjectID()
 		oid := objectID.String()
-		if *lsCommandLong {
+		switch {
+		case *lsCommandLong:
 			info = fmt.Sprintf(
 				"%v %12d %v %-34v %v",
 				e.Mode(),
@@ -62,12 +63,12 @@ func listDirectory(ctx context.Context, rep *repo.Repository, prefix string, oid
 				oid,
 				nameToDisplay(prefix, e),
 			)
-		} else if *lsCommandShowOID {
+		case *lsCommandShowOID:
 			info = fmt.Sprintf(
 				"%-34v %v",
 				oid,
 				nameToDisplay(prefix, e))
-		} else {
+		default:
 			info = nameToDisplay(prefix, e)
 		}
 		fmt.Println(info)

+ 6 - 5
cli/command_mount_browse.go

@@ -12,13 +12,13 @@ var (
 	mountBrowser = mountCommand.Flag("browse", "Browse mounted filesystem using the provided method").Default("OS").Enum("NONE", "WEB", "OS")
 )
 
-var mountBrowsers = map[string]func(mountPoint string, addr string) error{
+var mountBrowsers = map[string]func(mountPoint, addr string) error{
 	"NONE": nil,
 	"WEB":  openInWebBrowser,
 	"OS":   openInOSBrowser,
 }
 
-func browseMount(mountPoint string, addr string) error {
+func browseMount(mountPoint, addr string) error {
 	b := mountBrowsers[*mountBrowser]
 	if b == nil {
 		waitForCtrlC()
@@ -28,13 +28,14 @@ func browseMount(mountPoint string, addr string) error {
 	return b(mountPoint, addr)
 }
 
-func openInWebBrowser(mountPoint string, addr string) error {
+// nolint:unparam
+func openInWebBrowser(mountPoint, addr string) error {
 	startWebBrowser(addr)
 	waitForCtrlC()
 	return nil
 }
 
-func openInOSBrowser(mountPoint string, addr string) error {
+func openInOSBrowser(mountPoint, addr string) error {
 	if isWindows() {
 		return netUSE(mountPoint, addr)
 	}
@@ -44,7 +45,7 @@ func openInOSBrowser(mountPoint string, addr string) error {
 	return nil
 }
 
-func netUSE(mountPoint string, addr string) error {
+func netUSE(mountPoint, addr string) error {
 	c := exec.Command("net", "use", mountPoint, addr)
 	c.Stdout = os.Stdout
 	c.Stderr = os.Stderr

+ 3 - 3
cli/command_object_verify.go

@@ -201,7 +201,7 @@ func runVerifyCommand(ctx context.Context, rep *repo.Repository) error {
 }
 
 func enqueueRootsToVerify(ctx context.Context, v *verifier, rep *repo.Repository) error {
-	manifests, err := loadSourceManifests(ctx, rep, *verifyCommandAllSources, *verifyCommandSources)
+	manifests, err := loadSourceManifests(ctx, rep, *verifyCommandSources)
 	if err != nil {
 		return err
 	}
@@ -240,7 +240,7 @@ func enqueueRootsToVerify(ctx context.Context, v *verifier, rep *repo.Repository
 	return nil
 }
 
-func loadSourceManifests(ctx context.Context, rep *repo.Repository, all bool, sources []string) ([]*snapshot.Manifest, error) {
+func loadSourceManifests(ctx context.Context, rep *repo.Repository, sources []string) ([]*snapshot.Manifest, error) {
 	var manifestIDs []manifest.ID
 	if *verifyCommandAllSources {
 		man, err := snapshot.ListSnapshotManifests(ctx, rep, nil)
@@ -249,7 +249,7 @@ func loadSourceManifests(ctx context.Context, rep *repo.Repository, all bool, so
 		}
 		manifestIDs = append(manifestIDs, man...)
 	} else {
-		for _, srcStr := range *verifyCommandSources {
+		for _, srcStr := range sources {
 			src, err := snapshot.ParseSourceInfo(srcStr, getHostName(), getUserName())
 			if err != nil {
 				return nil, errors.Wrapf(err, "error parsing %q", srcStr)

+ 1 - 1
cli/command_policy_edit.go

@@ -121,7 +121,7 @@ func jsonEqual(v1, v2 interface{}) bool {
 	return prettyJSON(v1) == prettyJSON(v2)
 }
 
-func insertHelpText(s string, lookFor string, help string) string {
+func insertHelpText(s, lookFor, help string) string {
 	p := strings.Index(s, lookFor)
 	if p < 0 {
 		return s

+ 4 - 8
cli/command_policy_set.go

@@ -10,7 +10,6 @@ import (
 
 	"github.com/kopia/kopia/fs/ignorefs"
 	"github.com/kopia/kopia/repo"
-	"github.com/kopia/kopia/snapshot"
 	"github.com/kopia/kopia/snapshot/policy"
 )
 
@@ -69,7 +68,7 @@ func setPolicy(ctx context.Context, rep *repo.Repository) error {
 		printStderr("Setting policy for %v\n", target)
 		changeCount := 0
 
-		if err := setPolicyFromFlags(target, p, &changeCount); err != nil {
+		if err := setPolicyFromFlags(p, &changeCount); err != nil {
 			return err
 		}
 
@@ -85,14 +84,12 @@ func setPolicy(ctx context.Context, rep *repo.Repository) error {
 	return nil
 }
 
-func setPolicyFromFlags(target snapshot.SourceInfo, p *policy.Policy, changeCount *int) error {
+func setPolicyFromFlags(p *policy.Policy, changeCount *int) error {
 	if err := setRetentionPolicyFromFlags(&p.RetentionPolicy, changeCount); err != nil {
 		return errors.Wrap(err, "retention policy")
 	}
 
-	if err := setFilesPolicyFromFlags(&p.FilesPolicy, changeCount); err != nil {
-		return errors.Wrap(err, "files policy")
-	}
+	setFilesPolicyFromFlags(&p.FilesPolicy, changeCount)
 
 	if err := setSchedulingPolicyFromFlags(&p.SchedulingPolicy, changeCount); err != nil {
 		return errors.Wrap(err, "scheduling policy")
@@ -111,7 +108,7 @@ func setPolicyFromFlags(target snapshot.SourceInfo, p *policy.Policy, changeCoun
 	return nil
 }
 
-func setFilesPolicyFromFlags(fp *ignorefs.FilesPolicy, changeCount *int) error {
+func setFilesPolicyFromFlags(fp *ignorefs.FilesPolicy, changeCount *int) {
 	if *policySetClearDotIgnore {
 		*changeCount++
 		printStderr(" - removing all rules for dot-ignore files\n")
@@ -126,7 +123,6 @@ func setFilesPolicyFromFlags(fp *ignorefs.FilesPolicy, changeCount *int) error {
 	} else {
 		fp.IgnoreRules = addRemoveDedupeAndSort("ignored files", fp.IgnoreRules, *policySetAddIgnore, *policySetRemoveIgnore, changeCount)
 	}
-	return nil
 }
 
 func setRetentionPolicyFromFlags(rp *policy.RetentionPolicy, changeCount *int) error {

+ 3 - 0
cli/command_policy_show.go

@@ -124,6 +124,7 @@ func printFilesPolicy(p *policy.Policy, parents []*policy.Policy) {
 		printStdout("  No ignore rules.\n")
 	}
 	for _, rule := range p.FilesPolicy.IgnoreRules {
+		rule := rule
 		printStdout("    %-30v %v\n", rule, getDefinitionPoint(parents, func(pol *policy.Policy) bool {
 			return containsString(pol.FilesPolicy.IgnoreRules, rule)
 		}))
@@ -132,6 +133,7 @@ func printFilesPolicy(p *policy.Policy, parents []*policy.Policy) {
 		printStdout("  Read ignore rules from files:\n")
 	}
 	for _, dotFile := range p.FilesPolicy.DotIgnoreFiles {
+		dotFile := dotFile
 		printStdout("    %-30v %v\n", dotFile, getDefinitionPoint(parents, func(pol *policy.Policy) bool {
 			return containsString(pol.FilesPolicy.DotIgnoreFiles, dotFile)
 		}))
@@ -155,6 +157,7 @@ func printSchedulingPolicy(p *policy.Policy, parents []*policy.Policy) {
 	if len(p.SchedulingPolicy.TimesOfDay) > 0 {
 		printStdout("Snapshot times:\n")
 		for _, tod := range p.SchedulingPolicy.TimesOfDay {
+			tod := tod
 			printStdout("  %9v                        %v\n", tod, getDefinitionPoint(parents, func(pol *policy.Policy) bool {
 				for _, t := range pol.SchedulingPolicy.TimesOfDay {
 					if t == tod {

+ 3 - 3
cli/command_repository_repair.go

@@ -18,13 +18,13 @@ var (
 )
 
 func runRepairCommandWithStorage(ctx context.Context, st blob.Storage) error {
-	if err := maybeRecoverFormatBlob(ctx, st, *repairCommandRecoverFormatBlobPrefix); err != nil {
+	if err := maybeRecoverFormatBlob(ctx, st); err != nil {
 		return err
 	}
 	return nil
 }
 
-func maybeRecoverFormatBlob(ctx context.Context, st blob.Storage, prefix string) error {
+func maybeRecoverFormatBlob(ctx context.Context, st blob.Storage) error {
 	switch *repairCommandRecoverFormatBlob {
 	case "auto":
 		log.Infof("looking for format blob...")
@@ -43,7 +43,7 @@ func maybeRecoverFormatBlob(ctx context.Context, st blob.Storage, prefix string)
 func recoverFormatBlob(ctx context.Context, st blob.Storage, prefix string) error {
 	errSuccess := errors.New("success")
 
-	err := st.ListBlobs(ctx, blob.ID(*repairCommandRecoverFormatBlobPrefix), func(bi blob.Metadata) error {
+	err := st.ListBlobs(ctx, blob.ID(prefix), func(bi blob.Metadata) error {
 		log.Infof("looking for replica of format blob in %v...", bi.BlobID)
 		if b, err := repo.RecoverFormatBlob(ctx, st, bi.BlobID, bi.Length); err == nil {
 			if !*repairDryDrun {

+ 2 - 2
cli/command_server_upload.go

@@ -16,10 +16,10 @@ func init() {
 }
 
 func runServerStartUpload(ctx context.Context, cli *serverapi.Client) error {
-	return triggerActionOnMatchingSources(ctx, cli, "sources/upload")
+	return triggerActionOnMatchingSources(cli, "sources/upload")
 }
 
-func triggerActionOnMatchingSources(ctx context.Context, cli *serverapi.Client, path string) error {
+func triggerActionOnMatchingSources(cli *serverapi.Client, path string) error {
 	var resp serverapi.MultipleSourceActionResponse
 
 	if err := cli.Post(path, &serverapi.Empty{}, &resp); err != nil {

+ 9 - 6
cli/command_snapshot_list.go

@@ -190,11 +190,13 @@ func outputManifestFromSingleSource(ctx context.Context, rep *repo.Repository, m
 			bits = append(bits, "incomplete:"+m.IncompleteReason)
 		}
 
-		bits = append(bits, maybeHumanReadableBytes(*snapshotListShowHumanReadable, ent.Size()))
-		bits = append(bits, fmt.Sprintf("%v", ent.Mode()))
+		bits = append(bits,
+			maybeHumanReadableBytes(*snapshotListShowHumanReadable, ent.Size()),
+			fmt.Sprintf("%v", ent.Mode()))
 		if *shapshotListShowOwner {
-			bits = append(bits, fmt.Sprintf("uid:%v", ent.Owner().UserID))
-			bits = append(bits, fmt.Sprintf("gid:%v", ent.Owner().GroupID))
+			bits = append(bits,
+				fmt.Sprintf("uid:%v", ent.Owner().UserID),
+				fmt.Sprintf("gid:%v", ent.Owner().GroupID))
 		}
 		if *snapshotListShowModTime {
 			bits = append(bits, fmt.Sprintf("modified:%v", formatTimestamp(ent.ModTime())))
@@ -214,8 +216,9 @@ func outputManifestFromSingleSource(ctx context.Context, rep *repo.Repository, m
 		if d, ok := ent.(fs.Directory); ok {
 			s := d.Summary()
 			if s != nil {
-				bits = append(bits, fmt.Sprintf("files:%v", s.TotalFileCount))
-				bits = append(bits, fmt.Sprintf("dirs:%v", s.TotalDirCount))
+				bits = append(bits,
+					fmt.Sprintf("files:%v", s.TotalFileCount),
+					fmt.Sprintf("dirs:%v", s.TotalDirCount))
 			}
 		}
 

+ 5 - 5
cli/command_snapshot_migrate.go

@@ -39,7 +39,7 @@ func runMigrateCommand(ctx context.Context, destRepo *repo.Repository) error {
 
 	var (
 		mu              sync.Mutex
-		cancelled       bool
+		canceled        bool
 		activeUploaders = map[snapshot.SourceInfo]*snapshotfs.Uploader{}
 	)
 
@@ -47,8 +47,8 @@ func runMigrateCommand(ctx context.Context, destRepo *repo.Repository) error {
 		mu.Lock()
 		defer mu.Unlock()
 
-		if !cancelled {
-			cancelled = true
+		if !canceled {
+			canceled = true
 			for s, u := range activeUploaders {
 				log.Warningf("cancelling active uploader for %v", s)
 				u.Cancel()
@@ -57,9 +57,9 @@ func runMigrateCommand(ctx context.Context, destRepo *repo.Repository) error {
 	})
 
 	for _, s := range sources {
-		// start a new uploader unless already cancelled
+		// start a new uploader unless already canceled
 		mu.Lock()
-		if cancelled {
+		if canceled {
 			mu.Unlock()
 			break
 		}

+ 5 - 5
cli/password.go

@@ -40,7 +40,7 @@ func mustAskForExistingRepositoryPassword() string {
 	return p1
 }
 
-func mustGetPasswordFromFlags(isNew bool, allowPersistent bool) string {
+func mustGetPasswordFromFlags(isNew, allowPersistent bool) string {
 	if !isNew && allowPersistent {
 		pass, ok := getPersistedPassword(repositoryConfigFileName(), getUserName())
 		if ok {
@@ -66,7 +66,7 @@ func askPass(prompt string) (string, error) {
 			return "", err
 		}
 
-		if len(p) == 0 {
+		if p == "" {
 			continue
 		}
 
@@ -76,7 +76,7 @@ func askPass(prompt string) (string, error) {
 	return "", errors.New("can't get password")
 }
 
-func getPersistedPassword(configFile string, username string) (string, bool) {
+func getPersistedPassword(configFile, username string) (string, bool) {
 	if *keyringEnabled {
 		kr, err := keyring.Get(getKeyringItemID(configFile), username)
 		if err == nil {
@@ -98,7 +98,7 @@ func getPersistedPassword(configFile string, username string) (string, bool) {
 	return "", false
 }
 
-func persistPassword(configFile string, username string, password string) error {
+func persistPassword(configFile, username, password string) error {
 	if *keyringEnabled {
 		log.Debugf("saving password to OS keyring...")
 		err := keyring.Set(getKeyringItemID(configFile), username, password)
@@ -116,7 +116,7 @@ func persistPassword(configFile string, username string, password string) error
 	return ioutil.WriteFile(fn, []byte(base64.StdEncoding.EncodeToString([]byte(password))), 0600)
 }
 
-func deletePassword(configFile string, username string) {
+func deletePassword(configFile, username string) {
 	// delete from both keyring and a file
 	if *keyringEnabled {
 		err := keyring.Delete(getKeyringItemID(configFile), username)

+ 7 - 2
cli/storage_filesystem.go

@@ -13,6 +13,11 @@ import (
 
 var options filesystem.Options
 
+const (
+	defaultFileMode = 0600
+	defaultDirMode  = 0700
+)
+
 var (
 	connectOwnerUID string
 	connectOwnerGID string
@@ -30,8 +35,8 @@ func connect(ctx context.Context, isNew bool) (blob.Storage, error) {
 		fso.FileGID = getIntPtrValue(v, 10)
 	}
 
-	fso.FileMode = getFileModeValue(connectFileMode, 0600)
-	fso.DirectoryMode = getFileModeValue(connectDirMode, 0700)
+	fso.FileMode = getFileModeValue(connectFileMode, defaultFileMode)
+	fso.DirectoryMode = getFileModeValue(connectDirMode, defaultDirMode)
 
 	if connectFlat {
 		fso.DirectoryShards = []int{}

+ 1 - 2
cli/storage_providers.go

@@ -12,8 +12,7 @@ import (
 // RegisterStorageConnectFlags registers repository subcommand to connect to a storage
 // or create new repository in a given storage.
 func RegisterStorageConnectFlags(
-	name string,
-	description string,
+	name, description string,
 	flags func(*kingpin.CmdClause),
 	connect func(ctx context.Context, isNew bool) (blob.Storage, error)) {
 

+ 3 - 2
fs/ignorefs/ignorefs_test.go

@@ -210,6 +210,7 @@ func TestIgnoreFS(t *testing.T) {
 	}
 
 	for _, tc := range cases {
+		tc := tc
 		t.Run(tc.desc, func(t *testing.T) {
 			root := setupFilesystem()
 			originalFiles := walkTree(t, root)
@@ -260,8 +261,8 @@ func walkTree(t *testing.T, dir fs.Directory) []string {
 		for _, e := range entries {
 			relPath := path + "/" + e.Name()
 
-			if dir, ok := e.(fs.Directory); ok {
-				if err := walk(relPath, dir); err != nil {
+			if subdir, ok := e.(fs.Directory); ok {
+				if err := walk(relPath, subdir); err != nil {
 					return err
 				}
 			} else {

+ 1 - 0
fs/localfs/local_fs_test.go

@@ -13,6 +13,7 @@ import (
 	"testing"
 )
 
+//nolint:gocyclo
 func TestFiles(t *testing.T) {
 	ctx := context.Background()
 	var err error

+ 1 - 2
internal/diff/diff.go

@@ -191,8 +191,7 @@ func (c *Comparer) compareFiles(ctx context.Context, f1, f2 fs.File, fname strin
 
 	var args []string
 	args = append(args, c.DiffArguments...)
-	args = append(args, oldName)
-	args = append(args, newName)
+	args = append(args, oldName, newName)
 
 	cmd := exec.CommandContext(ctx, c.DiffCommand, args...)
 	cmd.Dir = c.tmpDir

+ 4 - 4
internal/editor/editor.go

@@ -19,8 +19,8 @@ var log = kopialogging.Logger("editor")
 
 // EditLoop launches OS-specific editor (VI, notepad.exe or anoter editor configured through environment variables)
 // It creates a temporary file with 'initial' contents and repeatedly invokes the editor until the provided 'parse' function
-// returns nil result indicating success. The 'parse' function is passed the contents of edited files without # line commments.
-func EditLoop(fname string, initial string, parse func(updated string) error) error {
+// returns nil result indicating success. The 'parse' function is passed the contents of edited files without # line comments.
+func EditLoop(fname, initial string, parse func(updated string) error) error {
 	tmpDir, err := ioutil.TempDir("", "kopia")
 	if err != nil {
 		return err
@@ -99,7 +99,7 @@ func editFile(file string) error {
 	return nil
 }
 
-func getEditorCommand() (string, []string) {
+func getEditorCommand() (cmd string, args []string) {
 	editor := os.Getenv("VISUAL")
 	if editor == "" {
 		editor = os.Getenv("EDITOR")
@@ -116,7 +116,7 @@ func getEditorCommand() (string, []string) {
 	return "vi", nil
 }
 
-func parseEditor(s string) (string, []string) {
+func parseEditor(s string) (cmd string, args []string) {
 	// quoted editor path
 	if s[0] == '"' {
 		p := strings.Index(s[1:], "\"")

+ 1 - 1
internal/ignore/ignore.go

@@ -14,7 +14,7 @@ type Matcher func(path string, isDir bool) bool
 type nameMatcher func(path string) bool
 
 // ParseGitIgnore returns a Matcher for a given gitignore-formatted pattern.
-func ParseGitIgnore(baseDir string, pattern string) (Matcher, error) {
+func ParseGitIgnore(baseDir, pattern string) (Matcher, error) {
 	if !strings.HasSuffix(baseDir, "/") {
 		baseDir += "/"
 	}

+ 8 - 6
internal/jsonstream/stream_test.go

@@ -23,13 +23,14 @@ func TestStream(t *testing.T) {
 	var buf bytes.Buffer
 
 	data := []TestObj{
-		TestObj{Name: "foo"},
-		TestObj{Name: "bar"},
-		TestObj{Name: "baz"},
+		{Name: "foo"},
+		{Name: "bar"},
+		{Name: "baz"},
 	}
 
 	w := NewWriter(&buf, testHeader1)
 	for _, d := range data {
+		d := d
 		if err := w.Write(&d); err != nil {
 			t.Errorf("write error: %v", err)
 		}
@@ -61,13 +62,14 @@ func TestStreamWithSummary(t *testing.T) {
 	var buf bytes.Buffer
 
 	data := []TestObj{
-		TestObj{Name: "foo"},
-		TestObj{Name: "bar"},
-		TestObj{Name: "baz"},
+		{Name: "foo"},
+		{Name: "bar"},
+		{Name: "baz"},
 	}
 
 	w := NewWriter(&buf, testHeader1)
 	for _, d := range data {
+		d := d
 		if err := w.Write(&d); err != nil {
 			t.Errorf("write error: %v", err)
 		}

+ 0 - 1
internal/jsonstream/writer.go

@@ -24,7 +24,6 @@ func (w *Writer) Write(v interface{}) error {
 	if err != nil {
 		return err
 	}
-	// log.Printf("*** %v: %v", w.header, string(j))
 	if _, err := w.output.Write(j); err != nil {
 		return err
 	}

+ 1 - 1
internal/mockfs/mockfs.go

@@ -125,7 +125,7 @@ func (imd *Directory) addChild(e fs.Entry) {
 	imd.children.Sort()
 }
 
-func (imd *Directory) resolveSubdir(name string) (*Directory, string) {
+func (imd *Directory) resolveSubdir(name string) (parent *Directory, leaf string) {
 	parts := strings.Split(name, "/")
 	for _, n := range parts[0 : len(parts)-1] {
 		imd = imd.Subdir(n)

+ 1 - 0
internal/parallelwork/parallel_work_queue.go

@@ -56,6 +56,7 @@ func (v *Queue) Process(workers int) {
 
 		go func(workerID int) {
 			defer wg.Done()
+			_ = workerID
 
 			for {
 				callback := v.dequeue()

+ 1 - 1
internal/retry/retry_test.go

@@ -41,8 +41,8 @@ func TestRetry(t *testing.T) {
 	}
 
 	for _, tc := range cases {
+		tc := tc
 		t.Run(tc.desc, func(t *testing.T) {
-			tc := tc
 			t.Parallel()
 
 			got, err := WithExponentialBackoff(tc.desc, tc.f, isRetriable)

+ 1 - 2
internal/scrubber/scrub_sensitive.go

@@ -20,8 +20,7 @@ func ScrubSensitiveData(v reflect.Value) reflect.Value {
 			sf := v.Type().Field(i)
 
 			if sf.Tag.Get("kopia") == "sensitive" {
-				switch sf.Type.Kind() {
-				case reflect.String:
+				if sf.Type.Kind() == reflect.String {
 					res.Field(i).SetString(strings.Repeat("*", fv.Len()))
 				}
 			} else {

+ 1 - 1
internal/server/api_sources_list.go

@@ -10,7 +10,7 @@ import (
 
 func (s *Server) handleSourcesList(ctx context.Context, r *http.Request) (interface{}, *apiError) {
 	resp := &serverapi.SourcesResponse{
-		Sources: []serverapi.SourceStatus{},
+		Sources: []*serverapi.SourceStatus{},
 	}
 
 	for _, v := range s.sourceManagers {

+ 1 - 1
internal/server/server.go

@@ -120,7 +120,7 @@ func (s *Server) endUpload(src snapshot.SourceInfo) {
 
 // New creates a Server on top of a given Repository.
 // The server will manage sources for a given username@hostname.
-func New(ctx context.Context, rep *repo.Repository, hostname string, username string) (*Server, error) {
+func New(ctx context.Context, rep *repo.Repository, hostname, username string) (*Server, error) {
 	s := &Server{
 		hostname:        hostname,
 		username:        username,

+ 2 - 2
internal/server/source_manager.go

@@ -38,11 +38,11 @@ type sourceManager struct {
 	uploadPathTotal     int64
 }
 
-func (s *sourceManager) Status() serverapi.SourceStatus {
+func (s *sourceManager) Status() *serverapi.SourceStatus {
 	s.mu.RLock()
 	defer s.mu.RUnlock()
 
-	st := serverapi.SourceStatus{
+	st := &serverapi.SourceStatus{
 		Source:           s.src,
 		Status:           s.state,
 		LastSnapshotSize: s.lastSnapshot.Stats.TotalFileSize,

+ 1 - 1
internal/serverapi/serverapi.go

@@ -18,7 +18,7 @@ type StatusResponse struct {
 
 // SourcesResponse is the response of 'sources' HTTP API command.
 type SourcesResponse struct {
-	Sources []SourceStatus `json:"sources"`
+	Sources []*SourceStatus `json:"sources"`
 }
 
 // SourceStatus describes the status of a single source.

+ 1 - 1
internal/throttle/round_tripper.go

@@ -31,7 +31,7 @@ func (rt *throttlingRoundTripper) RoundTrip(req *http.Request) (*http.Response,
 }
 
 // NewRoundTripper returns http.RoundTripper that throttles upload and downloads.
-func NewRoundTripper(base http.RoundTripper, downloadPool throttlerPool, uploadPool throttlerPool) http.RoundTripper {
+func NewRoundTripper(base http.RoundTripper, downloadPool, uploadPool throttlerPool) http.RoundTripper {
 	if base == nil {
 		base = http.DefaultTransport
 	}

+ 1 - 0
internal/throttle/round_tripper_test.go

@@ -41,6 +41,7 @@ func (fp *fakePool) AddReader(r io.ReadCloser) (io.ReadCloser, error) {
 	return r, nil
 }
 
+//nolint:gocyclo
 func TestRoundTripper(t *testing.T) {
 	downloadBody := ioutil.NopCloser(bytes.NewReader([]byte("data1")))
 	uploadBody := ioutil.NopCloser(bytes.NewReader([]byte("data1")))

+ 2 - 2
internal/units/units.go

@@ -12,12 +12,12 @@ func niceNumber(f float64) string {
 	return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", f), "0"), ".")
 }
 
-func toDecimalUnitString(f float64, thousand float64, prefixes []string, suffix string) string {
+func toDecimalUnitString(f, thousand float64, prefixes []string, suffix string) string {
 	for i := range prefixes {
 		if f < 0.9*thousand {
 			return fmt.Sprintf("%v %v%v", niceNumber(f), prefixes[i], suffix)
 		}
-		f = f / thousand
+		f /= thousand
 	}
 
 	return fmt.Sprintf("%v %v%v", niceNumber(f), prefixes[len(prefixes)-1], suffix)

+ 10 - 6
repo/blob/filesystem/filesystem_storage.go

@@ -3,10 +3,10 @@ package filesystem
 
 import (
 	"context"
+	"crypto/rand"
 	"fmt"
 	"io"
 	"io/ioutil"
-	"math/rand"
 	"os"
 	"path/filepath"
 	"strings"
@@ -142,7 +142,11 @@ func (fs *fsStorage) TouchBlob(ctx context.Context, blobID blob.ID, threshold ti
 func (fs *fsStorage) PutBlob(ctx context.Context, blobID blob.ID, data []byte) error {
 	_, path := fs.getShardedPathAndFilePath(blobID)
 
-	tempFile := fmt.Sprintf("%s.tmp.%d", path, rand.Int())
+	randSuffix := make([]byte, 8)
+	if _, err := rand.Read(randSuffix); err != nil {
+		return errors.Wrap(err, "can't get random bytes")
+	}
+	tempFile := fmt.Sprintf("%s.tmp.%x", path, randSuffix)
 	f, err := fs.createTempFileAndDir(tempFile)
 	if err != nil {
 		return errors.Wrap(err, "cannot create temporary file")
@@ -208,10 +212,10 @@ func (fs *fsStorage) getShardDirectory(blobID blob.ID) (string, blob.ID) {
 	return shardPath, blobID
 }
 
-func (fs *fsStorage) getShardedPathAndFilePath(blobID blob.ID) (string, string) {
-	shardPath, blobID := fs.getShardDirectory(blobID)
-	result := filepath.Join(shardPath, makeFileName(blobID))
-	return shardPath, result
+func (fs *fsStorage) getShardedPathAndFilePath(blobID blob.ID) (shardPath, filePath string) {
+	shardPath, blobID = fs.getShardDirectory(blobID)
+	filePath = filepath.Join(shardPath, makeFileName(blobID))
+	return
 }
 
 func (fs *fsStorage) ConnectionInfo() blob.ConnectionInfo {

+ 3 - 3
repo/blob/gcs/gcs_storage.go

@@ -158,12 +158,12 @@ func (gcs *gcsStorage) ListBlobs(ctx context.Context, prefix blob.ID, callback f
 
 	oa, err := lst.Next()
 	for err == nil {
-		if err = callback(blob.Metadata{
+		if cberr := callback(blob.Metadata{
 			BlobID:    blob.ID(oa.Name[len(gcs.Prefix):]),
 			Length:    oa.Size,
 			Timestamp: oa.Created,
-		}); err != nil {
-			return err
+		}); cberr != nil {
+			return cberr
 		}
 		oa, err = lst.Next()
 	}

+ 2 - 2
repo/blob/s3/s3_storage_test.go

@@ -20,8 +20,8 @@ import (
 // https://github.com/minio/minio-go
 const (
 	endpoint        = "play.minio.io:9000"
-	accessKeyID     = "Q3AM3UQ867SPQQA43P2F"
-	secretAccessKey = "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
+	accessKeyID     = "Q3AM3UQ867SPQQA43P2F"                     //nolint:gosec
+	secretAccessKey = "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" //nolint:gosec
 	useSSL          = true
 
 	// the test takes a few seconds, delete stuff older than 1h to avoid accumulating cruft

+ 9 - 5
repo/blob/webdav/webdav_storage.go

@@ -19,6 +19,9 @@ import (
 const (
 	davStorageType       = "webdav"
 	fsStorageChunkSuffix = ".f"
+
+	defaultFilePerm = 0600
+	defaultDirPerm  = 0700
 )
 
 var (
@@ -64,8 +67,9 @@ func (d *davStorage) translateError(err error) error {
 		switch err.Err.Error() {
 		case "404":
 			return blob.ErrBlobNotFound
+		default:
+			return err
 		}
-		return err
 	default:
 		return err
 	}
@@ -135,13 +139,13 @@ func (d *davStorage) ListBlobs(ctx context.Context, prefix blob.ID, callback fun
 func (d *davStorage) PutBlob(ctx context.Context, blobID blob.ID, data []byte) error {
 	dirPath, filePath := d.getDirPathAndFilePath(blobID)
 	tmpPath := fmt.Sprintf("%v-%v", filePath, rand.Int63())
-	if err := d.translateError(d.cli.Write(tmpPath, data, 0600)); err != nil {
+	if err := d.translateError(d.cli.Write(tmpPath, data, defaultFilePerm)); err != nil {
 		if err != blob.ErrBlobNotFound {
 			return err
 		}
 
-		d.cli.MkdirAll(dirPath, 0700) //nolint:errcheck
-		if err = d.translateError(d.cli.Write(tmpPath, data, 0600)); err != nil {
+		d.cli.MkdirAll(dirPath, defaultDirPerm) //nolint:errcheck
+		if err := d.translateError(d.cli.Write(tmpPath, data, defaultFilePerm)); err != nil {
 			return err
 		}
 	}
@@ -167,7 +171,7 @@ func (d *davStorage) getShardDirectory(blobID blob.ID) (string, blob.ID) {
 	return shardPath, blobID
 }
 
-func (d *davStorage) getDirPathAndFilePath(blobID blob.ID) (string, string) {
+func (d *davStorage) getDirPathAndFilePath(blobID blob.ID) (dirPath, filePath string) {
 	shardPath, blobID := d.getShardDirectory(blobID)
 	result := filepath.Join(shardPath, makeFileName(blobID))
 	return shardPath, result

+ 1 - 0
repo/blob/webdav/webdav_storage_test.go

@@ -40,6 +40,7 @@ func TestWebDAVStorage(t *testing.T) {
 		{1, 2},
 		{2, 2, 2},
 	} {
+		shardSpec := shardSpec
 		t.Run(fmt.Sprintf("shards-%v", shardSpec), func(t *testing.T) {
 			if err := os.RemoveAll(tmpDir); err != nil {
 				t.Errorf("can't remove all: %q", tmpDir)

+ 1 - 1
repo/content/block_manager_compaction.go

@@ -114,7 +114,7 @@ func (bm *Manager) compactAndDeleteIndexBlobs(ctx context.Context, indexBlobs []
 			continue
 		}
 
-		bm.listCache.deleteListCache(ctx)
+		bm.listCache.deleteListCache()
 		if err := bm.st.DeleteBlob(ctx, indexBlob.BlobID); err != nil {
 			log.Warningf("unable to delete compacted blob %q: %v", indexBlob.BlobID, err)
 		}

+ 1 - 0
repo/content/builder.go

@@ -15,6 +15,7 @@ import (
 type packIndexBuilder map[ID]*Info
 
 // Add adds a new entry to the builder or conditionally replaces it if the timestamp is greater.
+// nolint:gocritic
 func (b packIndexBuilder) Add(i Info) {
 	old, ok := b[i.ID]
 	if !ok || i.TimestampSeconds >= old.TimestampSeconds {

+ 2 - 2
repo/content/cache_hmac.go

@@ -4,13 +4,13 @@ import "crypto/hmac"
 import "crypto/sha256"
 import "errors"
 
-func appendHMAC(data []byte, secret []byte) []byte {
+func appendHMAC(data, secret []byte) []byte {
 	h := hmac.New(sha256.New, secret)
 	h.Write(data) // nolint:errcheck
 	return h.Sum(data)
 }
 
-func verifyAndStripHMAC(b []byte, secret []byte) ([]byte, error) {
+func verifyAndStripHMAC(b, secret []byte) ([]byte, error) {
 	if len(b) < sha256.Size {
 		return nil, errors.New("invalid data - too short")
 	}

+ 2 - 2
repo/content/committed_content_index.go

@@ -120,7 +120,7 @@ func (b *committedContentIndex) use(packFiles []blob.ID) (bool, error) {
 	return true, nil
 }
 
-func newCommittedContentIndex(caching CachingOptions) (*committedContentIndex, error) {
+func newCommittedContentIndex(caching CachingOptions) *committedContentIndex {
 	var cache committedContentIndexCache
 
 	if caching.CacheDirectory != "" {
@@ -135,5 +135,5 @@ func newCommittedContentIndex(caching CachingOptions) (*committedContentIndex, e
 	return &committedContentIndex{
 		cache: cache,
 		inUse: map[blob.ID]packIndex{},
-	}, nil
+	}
 }

+ 4 - 4
repo/content/content_cache.go

@@ -47,7 +47,7 @@ func adjustCacheKey(cacheKey blob.ID) blob.ID {
 	return cacheKey
 }
 
-func (c *contentCache) getContentContent(ctx context.Context, cacheKey blob.ID, blobID blob.ID, offset, length int64) ([]byte, error) {
+func (c *contentCache) getContentContent(ctx context.Context, cacheKey, blobID blob.ID, offset, length int64) ([]byte, error) {
 	cacheKey = adjustCacheKey(cacheKey)
 
 	useCache := shouldUseContentCache(ctx) && c.cacheStorage != nil
@@ -184,8 +184,8 @@ func newContentCache(ctx context.Context, st blob.Storage, caching CachingOption
 		contentCacheDir := filepath.Join(caching.CacheDirectory, "contents")
 
 		if _, err = os.Stat(contentCacheDir); os.IsNotExist(err) {
-			if err = os.MkdirAll(contentCacheDir, 0700); err != nil {
-				return nil, err
+			if mkdirerr := os.MkdirAll(contentCacheDir, 0700); mkdirerr != nil {
+				return nil, mkdirerr
 			}
 		}
 
@@ -201,7 +201,7 @@ func newContentCache(ctx context.Context, st blob.Storage, caching CachingOption
 	return newContentCacheWithCacheStorage(ctx, st, cacheStorage, caching, defaultTouchThreshold, defaultSweepFrequency)
 }
 
-func newContentCacheWithCacheStorage(ctx context.Context, st, cacheStorage blob.Storage, caching CachingOptions, touchThreshold time.Duration, sweepFrequency time.Duration) (*contentCache, error) {
+func newContentCacheWithCacheStorage(ctx context.Context, st, cacheStorage blob.Storage, caching CachingOptions, touchThreshold, sweepFrequency time.Duration) (*contentCache, error) {
 	c := &contentCache{
 		st:             st,
 		cacheStorage:   cacheStorage,

+ 2 - 2
repo/content/content_cache_test.go

@@ -148,8 +148,8 @@ func verifyContentCache(t *testing.T, cache *contentCache) {
 		// corrupt the data and write back
 		d[0] ^= 1
 
-		if err := cache.cacheStorage.PutBlob(ctx, cacheKey, d); err != nil {
-			t.Fatalf("unable to write corrupted content: %v", err)
+		if puterr := cache.cacheStorage.PutBlob(ctx, cacheKey, d); puterr != nil {
+			t.Fatalf("unable to write corrupted content: %v", puterr)
 		}
 
 		v, err := cache.getContentContent(ctx, "xf0f0f1", "content-1", 1, 5)

+ 20 - 20
repo/content/content_formatter.go

@@ -26,18 +26,18 @@ const (
 type HashFunc func(data []byte) []byte
 
 // HashFuncFactory returns a hash function for given formatting options.
-type HashFuncFactory func(o FormattingOptions) (HashFunc, error)
+type HashFuncFactory func(o *FormattingOptions) (HashFunc, error)
 
 // Encryptor performs encryption and decryption of contents of data.
 type Encryptor interface {
 	// Encrypt returns encrypted bytes corresponding to the given plaintext.
 	// Must not clobber the input slice and return ciphertext with additional padding and checksum.
-	Encrypt(plainText []byte, contentID []byte) ([]byte, error)
+	Encrypt(plainText, contentID []byte) ([]byte, error)
 
 	// Decrypt returns unencrypted bytes corresponding to the given ciphertext.
 	// Must not clobber the input slice. If IsAuthenticated() == true, Decrypt will perform
 	// authenticity check before decrypting.
-	Decrypt(cipherText []byte, contentID []byte) ([]byte, error)
+	Decrypt(cipherText, contentID []byte) ([]byte, error)
 
 	// IsAuthenticated returns true if encryption is authenticated.
 	// In this case Decrypt() is expected to perform authenticity check.
@@ -45,7 +45,7 @@ type Encryptor interface {
 }
 
 // EncryptorFactory creates new Encryptor for given FormattingOptions
-type EncryptorFactory func(o FormattingOptions) (Encryptor, error)
+type EncryptorFactory func(o *FormattingOptions) (Encryptor, error)
 
 var hashFunctions = map[string]HashFuncFactory{}
 var encryptors = map[string]EncryptorFactory{}
@@ -54,11 +54,11 @@ var encryptors = map[string]EncryptorFactory{}
 type nullEncryptor struct {
 }
 
-func (fi nullEncryptor) Encrypt(plainText []byte, contentID []byte) ([]byte, error) {
+func (fi nullEncryptor) Encrypt(plainText, contentID []byte) ([]byte, error) {
 	return cloneBytes(plainText), nil
 }
 
-func (fi nullEncryptor) Decrypt(cipherText []byte, contentID []byte) ([]byte, error) {
+func (fi nullEncryptor) Decrypt(cipherText, contentID []byte) ([]byte, error) {
 	return cloneBytes(cipherText), nil
 }
 
@@ -71,11 +71,11 @@ type ctrEncryptor struct {
 	createCipher func() (cipher.Block, error)
 }
 
-func (fi ctrEncryptor) Encrypt(plainText []byte, contentID []byte) ([]byte, error) {
+func (fi ctrEncryptor) Encrypt(plainText, contentID []byte) ([]byte, error) {
 	return symmetricEncrypt(fi.createCipher, contentID, plainText)
 }
 
-func (fi ctrEncryptor) Decrypt(cipherText []byte, contentID []byte) ([]byte, error) {
+func (fi ctrEncryptor) Decrypt(cipherText, contentID []byte) ([]byte, error) {
 	return symmetricEncrypt(fi.createCipher, contentID, cipherText)
 }
 
@@ -83,7 +83,7 @@ func (fi ctrEncryptor) IsAuthenticated() bool {
 	return false
 }
 
-func symmetricEncrypt(createCipher func() (cipher.Block, error), iv []byte, b []byte) ([]byte, error) {
+func symmetricEncrypt(createCipher func() (cipher.Block, error), iv, b []byte) ([]byte, error) {
 	blockCipher, err := createCipher()
 	if err != nil {
 		return nil, err
@@ -101,7 +101,7 @@ type salsaEncryptor struct {
 	hmacSecret []byte
 }
 
-func (s salsaEncryptor) Decrypt(input []byte, contentID []byte) ([]byte, error) {
+func (s salsaEncryptor) Decrypt(input, contentID []byte) ([]byte, error) {
 	if s.hmacSecret != nil {
 		var err error
 		input, err = verifyAndStripHMAC(input, s.hmacSecret)
@@ -113,7 +113,7 @@ func (s salsaEncryptor) Decrypt(input []byte, contentID []byte) ([]byte, error)
 	return s.encryptDecrypt(input, contentID)
 }
 
-func (s salsaEncryptor) Encrypt(input []byte, contentID []byte) ([]byte, error) {
+func (s salsaEncryptor) Encrypt(input, contentID []byte) ([]byte, error) {
 	v, err := s.encryptDecrypt(input, contentID)
 	if err != nil {
 		return nil, errors.Wrap(err, "decrypt")
@@ -130,7 +130,7 @@ func (s salsaEncryptor) IsAuthenticated() bool {
 	return s.hmacSecret != nil
 }
 
-func (s salsaEncryptor) encryptDecrypt(input []byte, contentID []byte) ([]byte, error) {
+func (s salsaEncryptor) encryptDecrypt(input, contentID []byte) ([]byte, error) {
 	if len(contentID) < s.nonceSize {
 		return nil, errors.Errorf("hash too short, expected >=%v bytes, got %v", s.nonceSize, len(contentID))
 	}
@@ -143,7 +143,7 @@ func (s salsaEncryptor) encryptDecrypt(input []byte, contentID []byte) ([]byte,
 // truncatedHMACHashFuncFactory returns a HashFuncFactory that computes HMAC(hash, secret) of a given content of bytes
 // and truncates results to the given size.
 func truncatedHMACHashFuncFactory(hf func() hash.Hash, truncate int) HashFuncFactory {
-	return func(o FormattingOptions) (HashFunc, error) {
+	return func(o *FormattingOptions) (HashFunc, error) {
 		return func(b []byte) []byte {
 			h := hmac.New(hf, o.HMACSecret)
 			h.Write(b) // nolint:errcheck
@@ -155,7 +155,7 @@ func truncatedHMACHashFuncFactory(hf func() hash.Hash, truncate int) HashFuncFac
 // truncatedKeyedHashFuncFactory returns a HashFuncFactory that computes keyed hash of a given content of bytes
 // and truncates results to the given size.
 func truncatedKeyedHashFuncFactory(hf func(key []byte) (hash.Hash, error), truncate int) HashFuncFactory {
-	return func(o FormattingOptions) (HashFunc, error) {
+	return func(o *FormattingOptions) (HashFunc, error) {
 		if _, err := hf(o.HMACSecret); err != nil {
 			return nil, err
 		}
@@ -170,7 +170,7 @@ func truncatedKeyedHashFuncFactory(hf func(key []byte) (hash.Hash, error), trunc
 
 // newCTREncryptorFactory returns new EncryptorFactory that uses CTR with symmetric encryption (such as AES) and a given key size.
 func newCTREncryptorFactory(keySize int, createCipherWithKey func(key []byte) (cipher.Block, error)) EncryptorFactory {
-	return func(o FormattingOptions) (Encryptor, error) {
+	return func(o *FormattingOptions) (Encryptor, error) {
 		key, err := adjustKey(o.MasterKey, keySize)
 		if err != nil {
 			return nil, errors.Wrap(err, "unable to get encryption key")
@@ -230,23 +230,23 @@ func init() {
 	RegisterHash("BLAKE2B-256-128", truncatedKeyedHashFuncFactory(blake2b.New256, 16))
 	RegisterHash("BLAKE2B-256", truncatedKeyedHashFuncFactory(blake2b.New256, 32))
 
-	RegisterEncryption("NONE", func(f FormattingOptions) (Encryptor, error) {
+	RegisterEncryption("NONE", func(f *FormattingOptions) (Encryptor, error) {
 		return nullEncryptor{}, nil
 	})
 	RegisterEncryption("AES-128-CTR", newCTREncryptorFactory(16, aes.NewCipher))
 	RegisterEncryption("AES-192-CTR", newCTREncryptorFactory(24, aes.NewCipher))
 	RegisterEncryption("AES-256-CTR", newCTREncryptorFactory(32, aes.NewCipher))
-	RegisterEncryption("SALSA20", func(f FormattingOptions) (Encryptor, error) {
+	RegisterEncryption("SALSA20", func(f *FormattingOptions) (Encryptor, error) {
 		var k [32]byte
 		copy(k[:], f.MasterKey[0:32])
 		return salsaEncryptor{8, &k, nil}, nil
 	})
-	RegisterEncryption("XSALSA20", func(f FormattingOptions) (Encryptor, error) {
+	RegisterEncryption("XSALSA20", func(f *FormattingOptions) (Encryptor, error) {
 		var k [32]byte
 		copy(k[:], f.MasterKey[0:32])
 		return salsaEncryptor{24, &k, nil}, nil
 	})
-	RegisterEncryption("SALSA20-HMAC", func(f FormattingOptions) (Encryptor, error) {
+	RegisterEncryption("SALSA20-HMAC", func(f *FormattingOptions) (Encryptor, error) {
 		encryptionKey := f.DeriveKey([]byte(purposeEncryptionKey), salsaKeyLength)
 		hmacSecret := f.DeriveKey([]byte(purposeHMACSecret), hmacLength)
 
@@ -254,7 +254,7 @@ func init() {
 		copy(k[:], encryptionKey)
 		return salsaEncryptor{8, &k, hmacSecret}, nil
 	})
-	RegisterEncryption("XSALSA20-HMAC", func(f FormattingOptions) (Encryptor, error) {
+	RegisterEncryption("XSALSA20-HMAC", func(f *FormattingOptions) (Encryptor, error) {
 		encryptionKey := f.DeriveKey([]byte(purposeEncryptionKey), salsaKeyLength)
 		hmacSecret := f.DeriveKey([]byte(purposeHMACSecret), hmacLength)
 		var k [salsaKeyLength]byte

+ 3 - 3
repo/content/content_formatter_test.go

@@ -2,8 +2,8 @@ package content
 
 import (
 	"bytes"
+	cryptorand "crypto/rand"
 	"crypto/sha1"
-	"math/rand"
 	"testing"
 )
 
@@ -23,12 +23,12 @@ func TestFormatters(t *testing.T) {
 	secret := []byte("secret")
 
 	data := make([]byte, 100)
-	rand.Read(data)
+	cryptorand.Read(data) //nolint:errcheck
 	h0 := sha1.Sum(data)
 
 	for _, hashAlgo := range SupportedHashAlgorithms() {
 		for _, encryptionAlgo := range SupportedEncryptionAlgorithms() {
-			h, e, err := CreateHashAndEncryptor(FormattingOptions{
+			h, e, err := CreateHashAndEncryptor(&FormattingOptions{
 				HMACSecret: secret,
 				MasterKey:  make([]byte, 32),
 				Hash:       hashAlgo,

+ 1 - 2
repo/content/content_formatting_options.go

@@ -18,10 +18,9 @@ type FormattingOptions struct {
 }
 
 // DeriveKey uses HKDF to derive a key of a given length and a given purpose.
-func (o FormattingOptions) DeriveKey(purpose []byte, length int) []byte {
+func (o *FormattingOptions) DeriveKey(purpose []byte, length int) []byte {
 	key := make([]byte, length)
 	k := hkdf.New(sha256.New, o.MasterKey, purpose, nil)
 	io.ReadFull(k, key) //nolint:errcheck
 	return key
-
 }

+ 2 - 0
repo/content/content_index_recovery.go

@@ -200,6 +200,8 @@ func (bm *Manager) appendPackFileIndexRecoveryData(contentData []byte, pending p
 }
 
 func (bm *Manager) readPackFileLocalIndex(ctx context.Context, packFile blob.ID, packFileLength int64) ([]byte, error) {
+	// TODO(jkowalski): optimize read when packFileLength is provided
+	_ = packFileLength
 	payload, err := bm.st.GetBlob(ctx, packFile, 0, -1)
 	if err != nil {
 		return nil, err

+ 3 - 3
repo/content/content_index_recovery_test.go

@@ -63,9 +63,9 @@ func TestContentIndexRecovery(t *testing.T) {
 	totalRecovered = 0
 
 	err = bm.st.ListBlobs(ctx, PackBlobIDPrefix, func(bi blob.Metadata) error {
-		infos, err := bm.RecoverIndexFromPackBlob(ctx, bi.BlobID, bi.Length, true)
-		if err != nil {
-			return err
+		infos, rerr := bm.RecoverIndexFromPackBlob(ctx, bi.BlobID, bi.Length, true)
+		if rerr != nil {
+			return rerr
 		}
 		totalRecovered += len(infos)
 		log.Debugf("recovered %v contents", len(infos))

+ 20 - 22
repo/content/content_manager.go

@@ -147,6 +147,8 @@ func (bm *Manager) DeleteContent(contentID ID) error {
 	return nil
 }
 
+//nolint:gocritic
+// We're intentionally passing "i" by value
 func (bm *Manager) setPendingContent(i Info) {
 	bm.packIndexBuilder.Add(i)
 	bm.currentPackItems[i.ID] = i
@@ -435,7 +437,7 @@ func (bm *Manager) loadPackIndexesUnlocked(ctx context.Context) ([]IndexBlobInfo
 		}
 
 		if i > 0 {
-			bm.listCache.deleteListCache(ctx)
+			bm.listCache.deleteListCache()
 			log.Debugf("encountered NOT_FOUND when loading, sleeping %v before retrying #%v", nextSleepTime, i)
 			time.Sleep(nextSleepTime)
 			nextSleepTime *= 2
@@ -514,8 +516,7 @@ func (bm *Manager) tryLoadPackIndexBlobsUnlocked(ctx context.Context, contents [
 }
 
 // unprocessedIndexBlobsUnlocked returns a closed channel filled with content IDs that are not in committedContents cache.
-func (bm *Manager) unprocessedIndexBlobsUnlocked(contents []IndexBlobInfo) (<-chan blob.ID, int64, error) {
-	var totalSize int64
+func (bm *Manager) unprocessedIndexBlobsUnlocked(contents []IndexBlobInfo) (resultCh <-chan blob.ID, totalSize int64, err error) {
 	ch := make(chan blob.ID, len(contents))
 	for _, c := range contents {
 		has, err := bm.committedContents.cache.hasIndexBlobID(c.BlobID)
@@ -615,7 +616,7 @@ func (bm *Manager) RewriteContent(ctx context.Context, contentID ID) error {
 		return err
 	}
 
-	data, err := bm.getContentContentsUnlocked(ctx, bi)
+	data, err := bm.getContentDataUnlocked(ctx, &bi)
 	if err != nil {
 		return err
 	}
@@ -663,7 +664,7 @@ func validatePrefix(prefix ID) error {
 func (bm *Manager) writePackFileNotLocked(ctx context.Context, packFile blob.ID, data []byte) error {
 	atomic.AddInt32(&bm.stats.WrittenContents, 1)
 	atomic.AddInt64(&bm.stats.WrittenBytes, int64(len(data)))
-	bm.listCache.deleteListCache(ctx)
+	bm.listCache.deleteListCache()
 	return bm.st.PutBlob(ctx, packFile, data)
 }
 
@@ -680,7 +681,7 @@ func (bm *Manager) encryptAndWriteContentNotLocked(ctx context.Context, data []b
 
 	atomic.AddInt32(&bm.stats.WrittenContents, 1)
 	atomic.AddInt64(&bm.stats.WrittenBytes, int64(len(data2)))
-	bm.listCache.deleteListCache(ctx)
+	bm.listCache.deleteListCache()
 	if err := bm.st.PutBlob(ctx, blobID, data2); err != nil {
 		return "", err
 	}
@@ -711,7 +712,7 @@ func (bm *Manager) GetContent(ctx context.Context, contentID ID) ([]byte, error)
 		return nil, ErrContentNotFound
 	}
 
-	return bm.getContentContentsUnlocked(ctx, bi)
+	return bm.getContentDataUnlocked(ctx, &bi)
 }
 
 func (bm *Manager) getContentInfo(contentID ID) (Info, error) {
@@ -786,7 +787,7 @@ func findPackContentsInUse(infos []Info) map[blob.ID]int {
 	return packUsage
 }
 
-func (bm *Manager) getContentContentsUnlocked(ctx context.Context, bi Info) ([]byte, error) {
+func (bm *Manager) getContentDataUnlocked(ctx context.Context, bi *Info) ([]byte, error) {
 	if bi.Payload != nil {
 		return cloneBytes(bi.Payload), nil
 	}
@@ -812,7 +813,7 @@ func (bm *Manager) getContentContentsUnlocked(ctx context.Context, bi Info) ([]b
 	return decrypted, nil
 }
 
-func (bm *Manager) decryptAndVerify(encrypted []byte, iv []byte) ([]byte, error) {
+func (bm *Manager) decryptAndVerify(encrypted, iv []byte) ([]byte, error) {
 	decrypted, err := bm.encryptor.Decrypt(encrypted, iv)
 	if err != nil {
 		return nil, errors.Wrap(err, "decrypt")
@@ -864,13 +865,13 @@ func getPackedContentIV(contentID ID) ([]byte, error) {
 }
 
 func getIndexBlobIV(s blob.ID) ([]byte, error) {
-	if p := strings.Index(string(s), "-"); p >= 0 {
+	if p := strings.Index(string(s), "-"); p >= 0 { // nolint:gocritic
 		s = s[0:p]
 	}
 	return hex.DecodeString(string(s[len(s)-(aes.BlockSize*2):]))
 }
 
-func (bm *Manager) verifyChecksum(data []byte, contentID []byte) error {
+func (bm *Manager) verifyChecksum(data, contentID []byte) error {
 	expected := bm.hasher(data)
 	expected = expected[len(expected)-aes.BlockSize:]
 	if !bytes.HasSuffix(contentID, expected) {
@@ -941,11 +942,11 @@ func listIndexBlobsFromStorage(ctx context.Context, st blob.Storage) ([]IndexBlo
 }
 
 // NewManager creates new content manager with given packing options and a formatter.
-func NewManager(ctx context.Context, st blob.Storage, f FormattingOptions, caching CachingOptions, repositoryFormatBytes []byte) (*Manager, error) {
+func NewManager(ctx context.Context, st blob.Storage, f *FormattingOptions, caching CachingOptions, repositoryFormatBytes []byte) (*Manager, error) {
 	return newManagerWithOptions(ctx, st, f, caching, time.Now, repositoryFormatBytes)
 }
 
-func newManagerWithOptions(ctx context.Context, st blob.Storage, f FormattingOptions, caching CachingOptions, timeNow func() time.Time, repositoryFormatBytes []byte) (*Manager, error) {
+func newManagerWithOptions(ctx context.Context, st blob.Storage, f *FormattingOptions, caching CachingOptions, timeNow func() time.Time, repositoryFormatBytes []byte) (*Manager, error) {
 	if f.Version < minSupportedReadVersion || f.Version > currentWriteVersion {
 		return nil, errors.Errorf("can't handle repositories created using version %v (min supported %v, max supported %v)", f.Version, minSupportedReadVersion, maxSupportedReadVersion)
 	}
@@ -964,18 +965,15 @@ func newManagerWithOptions(ctx context.Context, st blob.Storage, f FormattingOpt
 		return nil, errors.Wrap(err, "unable to initialize content cache")
 	}
 
-	listCache, err := newListCache(ctx, st, caching)
+	listCache, err := newListCache(st, caching)
 	if err != nil {
 		return nil, errors.Wrap(err, "unable to initialize list cache")
 	}
 
-	contentIndex, err := newCommittedContentIndex(caching)
-	if err != nil {
-		return nil, errors.Wrap(err, "unable to initialize committed content index")
-	}
+	contentIndex := newCommittedContentIndex(caching)
 
 	m := &Manager{
-		Format:                f,
+		Format:                *f,
 		timeNow:               timeNow,
 		flushPackIndexesAfter: timeNow().Add(flushPackIndexTimeout),
 		maxPackSize:           f.MaxPackSize,
@@ -1006,7 +1004,7 @@ func newManagerWithOptions(ctx context.Context, st blob.Storage, f FormattingOpt
 	return m, nil
 }
 
-func CreateHashAndEncryptor(f FormattingOptions) (HashFunc, Encryptor, error) {
+func CreateHashAndEncryptor(f *FormattingOptions) (HashFunc, Encryptor, error) {
 	h, err := createHashFunc(f)
 	if err != nil {
 		return nil, nil, errors.Wrap(err, "unable to create hash")
@@ -1026,7 +1024,7 @@ func CreateHashAndEncryptor(f FormattingOptions) (HashFunc, Encryptor, error) {
 	return h, e, nil
 }
 
-func createHashFunc(f FormattingOptions) (HashFunc, error) {
+func createHashFunc(f *FormattingOptions) (HashFunc, error) {
 	h := hashFunctions[f.Hash]
 	if h == nil {
 		return nil, errors.Errorf("unknown hash function %v", f.Hash)
@@ -1044,7 +1042,7 @@ func createHashFunc(f FormattingOptions) (HashFunc, error) {
 	return hashFunc, nil
 }
 
-func createEncryptor(f FormattingOptions) (Encryptor, error) {
+func createEncryptor(f *FormattingOptions) (Encryptor, error) {
 	e := encryptors[f.Encryption]
 	if e == nil {
 		return nil, errors.Errorf("unknown encryption algorithm: %v", f.Encryption)

+ 15 - 17
repo/content/content_manager_test.go

@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"context"
 	"crypto/hmac"
+	cryptorand "crypto/rand"
 	"crypto/sha256"
 	"encoding/hex"
 	"errors"
@@ -182,7 +183,7 @@ func TestContentManagerInternalFlush(t *testing.T) {
 
 	for i := 0; i < 100; i++ {
 		b := make([]byte, 25)
-		rand.Read(b)
+		cryptorand.Read(b) //nolint:errcheck
 		writeContentAndVerify(ctx, t, bm, b)
 	}
 
@@ -194,7 +195,7 @@ func TestContentManagerInternalFlush(t *testing.T) {
 	// do it again - should be 2 contents + 1000 bytes pending.
 	for i := 0; i < 100; i++ {
 		b := make([]byte, 25)
-		rand.Read(b)
+		cryptorand.Read(b) //nolint:errcheck
 		writeContentAndVerify(ctx, t, bm, b)
 	}
 
@@ -222,7 +223,6 @@ func TestContentManagerWriteMultiple(t *testing.T) {
 	var contentIDs []ID
 
 	for i := 0; i < 5000; i++ {
-		//t.Logf("i=%v", i)
 		b := seededRandomData(i, i%113)
 		blkID, err := bm.WriteContent(ctx, b, "")
 		if err != nil {
@@ -232,20 +232,15 @@ func TestContentManagerWriteMultiple(t *testing.T) {
 		contentIDs = append(contentIDs, blkID)
 
 		if i%17 == 0 {
-			//t.Logf("flushing %v", i)
 			if err := bm.Flush(ctx); err != nil {
 				t.Fatalf("error flushing: %v", err)
 			}
-			//dumpContentManagerData(t, data)
 		}
 
 		if i%41 == 0 {
-			//t.Logf("opening new manager: %v", i)
 			if err := bm.Flush(ctx); err != nil {
 				t.Fatalf("error flushing: %v", err)
 			}
-			//t.Logf("data content count: %v", len(data))
-			//dumpContentManagerData(t, data)
 			bm = newTestContentManager(data, keyTime, timeFunc)
 		}
 
@@ -270,7 +265,7 @@ func TestContentManagerFailedToWritePack(t *testing.T) {
 	}
 	st = faulty
 
-	bm, err := newManagerWithOptions(context.Background(), st, FormattingOptions{
+	bm, err := newManagerWithOptions(context.Background(), st, &FormattingOptions{
 		Version:     1,
 		Hash:        "HMAC-SHA256-128",
 		Encryption:  "AES-256-CTR",
@@ -404,7 +399,6 @@ func TestDeleteContent(t *testing.T) {
 	bm.Flush(ctx)
 	log.Debugf("-----------")
 	bm = newTestContentManager(data, keyTime, nil)
-	//dumpContentManagerData(t, data)
 	verifyContentNotFound(ctx, t, bm, content1)
 	verifyContentNotFound(ctx, t, bm, content2)
 }
@@ -416,6 +410,9 @@ func TestRewriteNonDeleted(t *testing.T) {
 	// where actionX can be (0=flush and reopen, 1=flush, 2=nothing)
 	for action1 := 0; action1 < stepBehaviors; action1++ {
 		for action2 := 0; action2 < stepBehaviors; action2++ {
+			action1 := action1
+			action2 := action2
+
 			t.Run(fmt.Sprintf("case-%v-%v", action1, action2), func(t *testing.T) {
 				ctx := context.Background()
 				data := blobtesting.DataMap{}
@@ -478,6 +475,9 @@ func TestRewriteDeleted(t *testing.T) {
 	for action1 := 0; action1 < stepBehaviors; action1++ {
 		for action2 := 0; action2 < stepBehaviors; action2++ {
 			for action3 := 0; action3 < stepBehaviors; action3++ {
+				action1 := action1
+				action2 := action2
+				action3 := action3
 				t.Run(fmt.Sprintf("case-%v-%v-%v", action1, action2, action3), func(t *testing.T) {
 					ctx := context.Background()
 					data := blobtesting.DataMap{}
@@ -526,10 +526,10 @@ func TestDeleteAndRecreate(t *testing.T) {
 		isVisible    bool
 	}{
 		{"deleted before delete and-recreate", fakeTime.Add(5 * time.Second), true},
-		//{"deleted after delete and recreate", fakeTime.Add(25 * time.Second), false},
 	}
 
 	for _, tc := range cases {
+		tc := tc
 		t.Run(tc.desc, func(t *testing.T) {
 			// write a content
 			data := blobtesting.DataMap{}
@@ -556,8 +556,6 @@ func TestDeleteAndRecreate(t *testing.T) {
 			// commit deletion from bm0 (t0+5)
 			bm0.Flush(ctx)
 
-			//dumpContentManagerData(t, data)
-
 			if content1 != content2 {
 				t.Errorf("got invalid content %v, expected %v", content2, content1)
 			}
@@ -702,6 +700,7 @@ func TestContentReadAliasing(t *testing.T) {
 
 func TestVersionCompatibility(t *testing.T) {
 	for writeVer := minSupportedReadVersion; writeVer <= currentWriteVersion; writeVer++ {
+		writeVer := writeVer
 		t.Run(fmt.Sprintf("version-%v", writeVer), func(t *testing.T) {
 			verifyVersionCompat(t, writeVer)
 		})
@@ -721,7 +720,7 @@ func verifyVersionCompat(t *testing.T, writeVersion int) {
 
 	for i := 0; i < 3000000; i = (i + 1) * 2 {
 		data := make([]byte, i)
-		rand.Read(data)
+		cryptorand.Read(data) //nolint:errcheck
 
 		cid, err := mgr.WriteContent(ctx, data, "")
 		if err != nil {
@@ -783,12 +782,11 @@ func verifyContentManagerDataSet(ctx context.Context, t *testing.T, mgr *Manager
 }
 
 func newTestContentManager(data blobtesting.DataMap, keyTime map[blob.ID]time.Time, timeFunc func() time.Time) *Manager {
-	//st = logging.NewWrapper(st)
 	if timeFunc == nil {
 		timeFunc = fakeTimeNowWithAutoAdvance(fakeTime, 1*time.Second)
 	}
 	st := blobtesting.NewMapStorage(data, keyTime, timeFunc)
-	bm, err := newManagerWithOptions(context.Background(), st, FormattingOptions{
+	bm, err := newManagerWithOptions(context.Background(), st, &FormattingOptions{
 		Hash:        "HMAC-SHA256",
 		Encryption:  "NONE",
 		HMACSecret:  hmacSecret,
@@ -878,7 +876,7 @@ func writeContentAndVerify(ctx context.Context, t *testing.T, bm *Manager, b []b
 	return contentID
 }
 
-func seededRandomData(seed int, length int) []byte {
+func seededRandomData(seed, length int) []byte {
 	b := make([]byte, length)
 	rnd := rand.New(rand.NewSource(int64(seed)))
 	rnd.Read(b)

+ 1 - 1
repo/content/info.go

@@ -22,6 +22,6 @@ type Info struct {
 }
 
 // Timestamp returns the time when a content was created or deleted.
-func (i Info) Timestamp() time.Time {
+func (i *Info) Timestamp() time.Time {
 	return time.Unix(i.TimestampSeconds, 0)
 }

+ 5 - 5
repo/content/list_cache.go

@@ -37,7 +37,7 @@ func (c *listCache) listIndexBlobs(ctx context.Context) ([]IndexBlobInfo, error)
 
 	contents, err := listIndexBlobsFromStorage(ctx, c.st)
 	if err == nil {
-		c.saveListToCache(ctx, &cachedList{
+		c.saveListToCache(&cachedList{
 			Contents:  contents,
 			Timestamp: time.Now(),
 		})
@@ -47,7 +47,7 @@ func (c *listCache) listIndexBlobs(ctx context.Context) ([]IndexBlobInfo, error)
 	return contents, err
 }
 
-func (c *listCache) saveListToCache(ctx context.Context, ci *cachedList) {
+func (c *listCache) saveListToCache(ci *cachedList) {
 	if c.cacheFile == "" {
 		return
 	}
@@ -62,7 +62,7 @@ func (c *listCache) saveListToCache(ctx context.Context, ci *cachedList) {
 	}
 }
 
-func (c *listCache) deleteListCache(ctx context.Context) {
+func (c *listCache) deleteListCache() {
 	if c.cacheFile != "" {
 		os.Remove(c.cacheFile) //nolint:errcheck
 	}
@@ -97,7 +97,7 @@ func (c *listCache) readContentsFromCache(ctx context.Context) (*cachedList, err
 
 }
 
-func newListCache(ctx context.Context, st blob.Storage, caching CachingOptions) (*listCache, error) {
+func newListCache(st blob.Storage, caching CachingOptions) (*listCache, error) {
 	var listCacheFile string
 
 	if caching.CacheDirectory != "" {
@@ -118,7 +118,7 @@ func newListCache(ctx context.Context, st blob.Storage, caching CachingOptions)
 	}
 
 	if caching.IgnoreListCache {
-		c.deleteListCache(ctx)
+		c.deleteListCache()
 	}
 
 	return c, nil

+ 4 - 2
repo/content/packindex_test.go

@@ -13,6 +13,7 @@ import (
 	"github.com/kopia/kopia/repo/blob"
 )
 
+//nolint:gocyclo
 func TestPackIndex(t *testing.T) {
 	contentNumber := 0
 
@@ -120,7 +121,7 @@ func TestPackIndex(t *testing.T) {
 	}
 
 	t.Run("FuzzTest", func(t *testing.T) {
-		fuzzTestIndexOpen(t, data1)
+		fuzzTestIndexOpen(data1)
 	})
 
 	ndx, err := openPackIndex(bytes.NewReader(data1))
@@ -168,6 +169,7 @@ func TestPackIndex(t *testing.T) {
 
 	for _, prefix := range prefixes {
 		cnt2 := 0
+		prefix := prefix
 		assertNoError(t, ndx.Iterate(prefix, func(info2 Info) error {
 			cnt2++
 			if !strings.HasPrefix(string(info2.ID), string(prefix)) {
@@ -179,7 +181,7 @@ func TestPackIndex(t *testing.T) {
 	}
 }
 
-func fuzzTestIndexOpen(t *testing.T, originalData []byte) {
+func fuzzTestIndexOpen(originalData []byte) {
 	// use consistent random
 	rnd := rand.New(rand.NewSource(12345))
 

+ 1 - 1
repo/crypto_key_derivation.go

@@ -12,7 +12,7 @@ import (
 // defaultKeyDerivationAlgorithm is the key derivation algorithm for new configurations.
 const defaultKeyDerivationAlgorithm = "scrypt-65536-8-1"
 
-func (f formatBlob) deriveMasterKeyFromPassword(password string) ([]byte, error) {
+func (f *formatBlob) deriveMasterKeyFromPassword(password string) ([]byte, error) {
 	const masterKeySize = 32
 
 	switch f.KeyDerivationAlgorithm {

+ 1 - 0
repo/format_block_test.go

@@ -56,6 +56,7 @@ func TestFormatBlobRecovery(t *testing.T) {
 	}
 
 	for _, tc := range cases {
+		tc := tc
 		t.Run(string(tc.blobID), func(t *testing.T) {
 			v, err := RecoverFormatBlob(ctx, st, tc.blobID, -1)
 			if tc.err == nil {

+ 4 - 4
repo/manifest/manifest_manager.go

@@ -337,7 +337,7 @@ func (m *Manager) loadManifestContents(ctx context.Context, contentIDs []content
 }
 
 func (m *Manager) loadContentsInParallel(ctx context.Context, contentIDs []content.ID) ([]manifest, error) {
-	errors := make(chan error, len(contentIDs))
+	errch := make(chan error, len(contentIDs))
 	manifests := make(chan manifest, len(contentIDs))
 	ch := make(chan content.ID, len(contentIDs))
 	var wg sync.WaitGroup
@@ -352,7 +352,7 @@ func (m *Manager) loadContentsInParallel(ctx context.Context, contentIDs []conte
 				man, err := m.loadManifestContent(ctx, blk)
 
 				if err != nil {
-					errors <- err
+					errch <- err
 					log.Debugf("manifest content %v failed to be loaded by worker %v in %v: %v.", blk, workerID, time.Since(t1), err)
 				} else {
 					log.Debugf("manifest content %v loaded by worker %v in %v.", blk, workerID, time.Since(t1))
@@ -370,11 +370,11 @@ func (m *Manager) loadContentsInParallel(ctx context.Context, contentIDs []conte
 
 	// wait for workers to complete
 	wg.Wait()
-	close(errors)
+	close(errch)
 	close(manifests)
 
 	// if there was any error, forward it
-	if err := <-errors; err != nil {
+	if err := <-errch; err != nil {
 		return nil, err
 	}
 

+ 3 - 2
repo/manifest/manifest_manager_test.go

@@ -118,7 +118,7 @@ func TestManifestInitCorruptedBlock(t *testing.T) {
 	data := blobtesting.DataMap{}
 	st := blobtesting.NewMapStorage(data, nil, nil)
 
-	f := content.FormattingOptions{
+	f := &content.FormattingOptions{
 		Hash:        "HMAC-SHA256-128",
 		Encryption:  "NONE",
 		MaxPackSize: 100000,
@@ -180,6 +180,7 @@ func TestManifestInitCorruptedBlock(t *testing.T) {
 	}
 
 	for _, tc := range cases {
+		tc := tc
 		t.Run(tc.desc, func(t *testing.T) {
 			err := tc.f()
 			if err == nil || !strings.Contains(err.Error(), "invalid checksum") {
@@ -263,7 +264,7 @@ func sortIDs(s []ID) {
 func newManagerForTesting(ctx context.Context, t *testing.T, data blobtesting.DataMap) *Manager {
 	st := blobtesting.NewMapStorage(data, nil, nil)
 
-	bm, err := content.NewManager(ctx, st, content.FormattingOptions{
+	bm, err := content.NewManager(ctx, st, &content.FormattingOptions{
 		Hash:        "HMAC-SHA256-128",
 		Encryption:  "NONE",
 		MaxPackSize: 100000,

+ 0 - 3
repo/object/object_manager.go

@@ -57,9 +57,6 @@ func (om *Manager) NewWriter(ctx context.Context, opt WriterOptions) Writer {
 
 // Open creates new ObjectReader for reading given object from a repository.
 func (om *Manager) Open(ctx context.Context, objectID ID) (Reader, error) {
-	// log.Printf("Repository::Open %v", objectID.String())
-	// defer log.Printf("finished Repository::Open() %v", objectID.String())
-
 	if indexObjectID, ok := objectID.IndexObjectID(); ok {
 		rd, err := om.Open(ctx, indexObjectID)
 		if err != nil {

+ 8 - 8
repo/object/object_manager_test.go

@@ -10,7 +10,6 @@ import (
 	"fmt"
 	"io/ioutil"
 	"math/rand"
-	"reflect"
 	"runtime/debug"
 	"sync"
 	"testing"
@@ -122,18 +121,18 @@ func TestWriters(t *testing.T) {
 	}
 }
 
-func objectIDsEqual(o1 ID, o2 ID) bool {
-	return reflect.DeepEqual(o1, o2)
+func objectIDsEqual(o1, o2 ID) bool {
+	return o1 == o2
 }
 
 func TestWriterCompleteChunkInTwoWrites(t *testing.T) {
 	ctx := context.Background()
 	_, om := setupTest(t)
 
-	bytes := make([]byte, 100)
+	b := make([]byte, 100)
 	writer := om.NewWriter(ctx, WriterOptions{})
-	writer.Write(bytes[0:50]) //nolint:errcheck
-	writer.Write(bytes[0:50]) //nolint:errcheck
+	writer.Write(b[0:50]) //nolint:errcheck
+	writer.Write(b[0:50]) //nolint:errcheck
 	result, err := writer.Result()
 	if !objectIDsEqual(result, "cd00e292c5970d3c5e2f0ffa5171e555bc46bfc4faddfb4a418b6840b86e79a3") {
 		t.Errorf("unexpected result: %v err: %v", result, err)
@@ -229,12 +228,12 @@ func indirectionLevel(oid ID) int {
 
 func TestHMAC(t *testing.T) {
 	ctx := context.Background()
-	content := bytes.Repeat([]byte{0xcd}, 50)
+	c := bytes.Repeat([]byte{0xcd}, 50)
 
 	_, om := setupTest(t)
 
 	w := om.NewWriter(ctx, WriterOptions{})
-	w.Write(content) //nolint:errcheck
+	w.Write(c) //nolint:errcheck
 	result, err := w.Result()
 	if result.String() != "cad29ff89951a3c085c86cb7ed22b82b51f7bdfda24f932c7f9601f51d5975ba" {
 		t.Errorf("unexpected result: %v err: %v", result.String(), err)
@@ -326,6 +325,7 @@ func verify(ctx context.Context, t *testing.T, om *Manager, objectID ID, expecte
 		return
 	}
 
+	// nolint:dupl
 	for i := 0; i < 20; i++ {
 		sampleSize := int(rand.Int31n(300))
 		seekOffset := int(rand.Int31n(int32(len(expectedData))))

+ 4 - 1
repo/object/object_reader.go

@@ -49,7 +49,10 @@ func (r *objectReader) Read(buffer []byte) (int, error) {
 			r.currentPosition += int64(toCopy)
 			readBytes += toCopy
 			remaining -= toCopy
-		} else if r.currentChunkIndex < len(r.seekTable) {
+			continue
+		}
+
+		if r.currentChunkIndex < len(r.seekTable) {
 			err := r.openCurrentChunk()
 			if err != nil {
 				return 0, err

+ 1 - 1
repo/object/object_splitter.go

@@ -40,7 +40,7 @@ var splitterFactories = map[string]SplitterFactory{
 	// handle deprecated legacy names to splitters of arbitrary size
 	"FIXED": newFixedSplitterFactory(4 << 20),
 
-	// we don't want to use old DYNAMIC splitter because of its licence, so
+	// we don't want to use old DYNAMIC splitter because of its license, so
 	// map this one to arbitrary buzhash32 (different)
 	"DYNAMIC": newBuzHash32SplitterFactory(megabytes(4)),
 }

+ 13 - 11
repo/object/object_splitter_test.go

@@ -1,6 +1,7 @@
 package object
 
 import (
+	cryptorand "crypto/rand"
 	"math"
 	"math/rand"
 	"testing"
@@ -20,7 +21,7 @@ func TestSplitters(t *testing.T) {
 		s2 := tc.newSplitter()
 
 		rnd := make([]byte, 50000000)
-		rand.Read(rnd)
+		cryptorand.Read(rnd) //nolint:errcheck
 
 		for i, p := range rnd {
 			if got, want := s1.ShouldSplit(p), s2.ShouldSplit(p); got != want {
@@ -67,17 +68,18 @@ func TestSplitterStability(t *testing.T) {
 		minSplit := int(math.MaxInt32)
 		count := 0
 		for i, p := range rnd {
-			if s.ShouldSplit(p) {
-				l := i - lastSplit
-				if l >= maxSplit {
-					maxSplit = l
-				}
-				if l < minSplit {
-					minSplit = l
-				}
-				count++
-				lastSplit = i
+			if !s.ShouldSplit(p) {
+				continue
 			}
+			l := i - lastSplit
+			if l >= maxSplit {
+				maxSplit = l
+			}
+			if l < minSplit {
+				minSplit = l
+			}
+			count++
+			lastSplit = i
 		}
 
 		var avg int

+ 1 - 2
repo/object/splitter_buzhash32.go

@@ -1,3 +1,4 @@
+//nolint:dupl
 package object
 
 import (
@@ -37,8 +38,6 @@ func newBuzHash32SplitterFactory(avgSize int) SplitterFactory {
 	maxSize := avgSize * 2
 	minSize := avgSize / 2
 
-	// log.Printf("Setting up buzhash with avg size: %v mask: %v %032b", avgSize, avgSize-1, mask)
-
 	return func() Splitter {
 		s := buzhash32.New()
 		s.Write(make([]byte, splitterSlidingWindowSize)) //nolint:errcheck

+ 1 - 0
repo/object/splitter_rabinkarp64.go

@@ -1,3 +1,4 @@
+//nolint:dupl
 package object
 
 import "github.com/chmduquesne/rollinghash/rabinkarp64"

+ 2 - 2
repo/open.go

@@ -27,7 +27,7 @@ type Options struct {
 }
 
 // Open opens a Repository specified in the configuration file.
-func Open(ctx context.Context, configFile string, password string, options *Options) (rep *Repository, err error) {
+func Open(ctx context.Context, configFile, password string, options *Options) (rep *Repository, err error) {
 	log.Debugf("opening repository from %v", configFile)
 	defer func() {
 		if err == nil {
@@ -105,7 +105,7 @@ func OpenWithConfig(ctx context.Context, st blob.Storage, lc *LocalConfig, passw
 
 	caching.HMACSecret = deriveKeyFromMasterKey(masterKey, f.UniqueID, []byte("local-cache-integrity"), 16)
 
-	fo := repoConfig.FormattingOptions
+	fo := &repoConfig.FormattingOptions
 	if fo.MaxPackSize == 0 {
 		fo.MaxPackSize = 20 << 20 // 20 MB
 	}

+ 8 - 33
repo/repository_test.go

@@ -3,11 +3,8 @@ package repo_test
 import (
 	"bytes"
 	"context"
-	cryptorand "crypto/rand"
-	"fmt"
 	"io/ioutil"
 	"math/rand"
-	"reflect"
 	"runtime/debug"
 	"testing"
 
@@ -54,8 +51,8 @@ func TestWriters(t *testing.T) {
 	}
 }
 
-func objectIDsEqual(o1 object.ID, o2 object.ID) bool {
-	return reflect.DeepEqual(o1, o2)
+func objectIDsEqual(o1, o2 object.ID) bool {
+	return o1 == o2
 }
 
 func TestWriterCompleteChunkInTwoWrites(t *testing.T) {
@@ -63,10 +60,10 @@ func TestWriterCompleteChunkInTwoWrites(t *testing.T) {
 	defer env.Setup(t).Close(t)
 	ctx := context.Background()
 
-	bytes := make([]byte, 100)
+	b := make([]byte, 100)
 	writer := env.Repository.Objects.NewWriter(ctx, object.WriterOptions{})
-	writer.Write(bytes[0:50]) //nolint:errcheck
-	writer.Write(bytes[0:50]) //nolint:errcheck
+	writer.Write(b[0:50]) //nolint:errcheck
+	writer.Write(b[0:50]) //nolint:errcheck
 	result, err := writer.Result()
 	if result != "1d804f1f69df08f3f59070bf962de69433e3d61ac18522a805a84d8c92741340" {
 		t.Errorf("unexpected result: %v err: %v", result, err)
@@ -147,10 +144,10 @@ func TestHMAC(t *testing.T) {
 	defer env.Setup(t).Close(t)
 	ctx := context.Background()
 
-	content := bytes.Repeat([]byte{0xcd}, 50)
+	c := bytes.Repeat([]byte{0xcd}, 50)
 
 	w := env.Repository.Objects.NewWriter(ctx, object.WriterOptions{})
-	w.Write(content) //nolint:errcheck
+	w.Write(c) //nolint:errcheck
 	result, err := w.Result()
 	if result.String() != "367352007ee6ca9fa755ce8352347d092c17a24077fd33c62f655574a8cf906d" {
 		t.Errorf("unexpected result: %v err: %v", result.String(), err)
@@ -186,29 +183,6 @@ func TestReaderStoredBlockNotFound(t *testing.T) {
 	}
 }
 
-func TestEndToEndReadAndSeek(t *testing.T) {
-	var env repotesting.Environment
-	defer env.Setup(t).Close(t)
-	ctx := context.Background()
-
-	for _, size := range []int{1, 199, 200, 201, 9999, 512434} {
-		// Create some random data sample of the specified size.
-		randomData := make([]byte, size)
-		cryptorand.Read(randomData) //nolint:errcheck
-
-		writer := env.Repository.Objects.NewWriter(ctx, object.WriterOptions{})
-		writer.Write(randomData) //nolint:errcheck
-		objectID, err := writer.Result()
-		writer.Close()
-		if err != nil {
-			t.Errorf("cannot get writer result for %v: %v", size, err)
-			continue
-		}
-
-		verify(ctx, t, env.Repository, objectID, randomData, fmt.Sprintf("%v %v", objectID, size))
-	}
-}
-
 func writeObject(ctx context.Context, t *testing.T, rep *repo.Repository, data []byte, testCaseID string) object.ID {
 	w := rep.Objects.NewWriter(ctx, object.WriterOptions{})
 	if _, err := w.Write(data); err != nil {
@@ -231,6 +205,7 @@ func verify(ctx context.Context, t *testing.T, rep *repo.Repository, objectID ob
 		return
 	}
 
+	// nolint:dupl
 	for i := 0; i < 20; i++ {
 		sampleSize := int(rand.Int31n(300))
 		seekOffset := int(rand.Int31n(int32(len(expectedData))))

+ 1 - 7
site/cli2md/cli2md.go

@@ -181,12 +181,6 @@ func flattenCommands(cmds []*kingpin.CmdModel) []*kingpin.CmdModel {
 		root.Commands = flattenChildren(c, nil, c.Hidden)
 	}
 
-	// for _, root := range result {
-	// 	sort.Slice(root.Commands, func(i, j int) bool {
-	// 		return root.Commands[i].FullCommand < root.Commands[j].FullCommand
-	// 	})
-	// }
-
 	return result
 }
 
@@ -212,7 +206,7 @@ func flattenChildren(cmd *kingpin.CmdModel, parentFlags []*kingpin.FlagModel, fo
 	return result
 }
 
-func generateSubcommands(w io.Writer, dir string, sectionTitle string, cmds []*kingpin.CmdModel, advanced bool) {
+func generateSubcommands(w io.Writer, dir, sectionTitle string, cmds []*kingpin.CmdModel, advanced bool) {
 	cmds = append([]*kingpin.CmdModel(nil), cmds...)
 	first := true
 	for _, c := range cmds {

+ 6 - 6
snapshot/manager.go

@@ -69,22 +69,22 @@ func loadSnapshot(ctx context.Context, rep *repo.Repository, manifestID manifest
 }
 
 // SaveSnapshot persists given snapshot manifest and returns manifest ID.
-func SaveSnapshot(ctx context.Context, rep *repo.Repository, manifest *Manifest) (manifest.ID, error) {
-	if manifest.Source.Host == "" {
+func SaveSnapshot(ctx context.Context, rep *repo.Repository, man *Manifest) (manifest.ID, error) {
+	if man.Source.Host == "" {
 		return "", errors.New("missing host")
 	}
-	if manifest.Source.UserName == "" {
+	if man.Source.UserName == "" {
 		return "", errors.New("missing username")
 	}
-	if manifest.Source.Path == "" {
+	if man.Source.Path == "" {
 		return "", errors.New("missing path")
 	}
 
-	id, err := rep.Manifests.Put(ctx, sourceInfoToLabels(manifest.Source), manifest)
+	id, err := rep.Manifests.Put(ctx, sourceInfoToLabels(man.Source), man)
 	if err != nil {
 		return "", err
 	}
-	manifest.ID = id
+	man.ID = id
 	return id, nil
 }
 

+ 1 - 1
snapshot/policy/policy_manager.go

@@ -23,7 +23,7 @@ var log = kopialogging.Logger("kopia/snapshot/policy")
 // GetEffectivePolicy calculates effective snapshot policy for a given source by combining the source-specifc policy (if any)
 // with parent policies. The source must contain a path.
 // Returns the effective policies and all source policies that contributed to that (most specific first).
-func GetEffectivePolicy(ctx context.Context, rep *repo.Repository, si snapshot.SourceInfo) (*Policy, []*Policy, error) {
+func GetEffectivePolicy(ctx context.Context, rep *repo.Repository, si snapshot.SourceInfo) (effective *Policy, sources []*Policy, e error) {
 	var md []*manifest.EntryMetadata
 
 	// Find policies applying to paths all the way up to the root.

+ 2 - 2
snapshot/policy/retention_policy.go

@@ -31,7 +31,7 @@ func (r *RetentionPolicy) ComputeRetentionReasons(manifests []*snapshot.Manifest
 		return maxTime
 	}
 
-	cutoff := cutoffTimes{
+	cutoff := &cutoffTimes{
 		annual:  cutoffTime(r.KeepAnnual, yearsAgo),
 		monthly: cutoffTime(r.KeepMonthly, monthsAgo),
 		daily:   cutoffTime(r.KeepDaily, daysAgo),
@@ -51,7 +51,7 @@ func (r *RetentionPolicy) ComputeRetentionReasons(manifests []*snapshot.Manifest
 	}
 }
 
-func (r *RetentionPolicy) getRetentionReasons(i int, s *snapshot.Manifest, cutoff cutoffTimes, ids map[string]bool, idCounters map[string]int) []string {
+func (r *RetentionPolicy) getRetentionReasons(i int, s *snapshot.Manifest, cutoff *cutoffTimes, ids map[string]bool, idCounters map[string]int) []string {
 	if s.IncompleteReason != "" {
 		return nil
 	}

+ 15 - 16
snapshot/snapshotfs/upload.go

@@ -41,7 +41,7 @@ func metadataHash(e fs.Entry, fileSize int64) uint64 {
 	return h.Sum64()
 }
 
-var errCancelled = errors.New("cancelled")
+var errCancelled = errors.New("canceled")
 
 // Uploader supports efficient uploading files and directories to repository.
 type Uploader struct {
@@ -73,7 +73,7 @@ type Uploader struct {
 
 	hashCacheCutoff time.Time
 	stats           snapshot.Stats
-	cancelled       int32
+	canceled        int32
 
 	progressMutex          sync.Mutex
 	nextProgressReportTime time.Time
@@ -83,14 +83,14 @@ type Uploader struct {
 	currentDirTotalSize    int64  // total # of bytes in current directory
 }
 
-// IsCancelled returns true if the upload is cancelled.
+// IsCancelled returns true if the upload is canceled.
 func (u *Uploader) IsCancelled() bool {
 	return u.cancelReason() != ""
 }
 
 func (u *Uploader) cancelReason() string {
-	if c := atomic.LoadInt32(&u.cancelled) != 0; c {
-		return "cancelled"
+	if c := atomic.LoadInt32(&u.canceled) != 0; c {
+		return "canceled"
 	}
 
 	if mub := u.MaxUploadBytes; mub > 0 && u.repo.Content.Stats().WrittenBytes > mub {
@@ -100,7 +100,7 @@ func (u *Uploader) cancelReason() string {
 	return ""
 }
 
-func (u *Uploader) uploadFileInternal(ctx context.Context, f fs.File, relativePath string) entryResult {
+func (u *Uploader) uploadFileInternal(ctx context.Context, f fs.File) entryResult {
 	file, err := f.Open(ctx)
 	if err != nil {
 		return entryResult{err: errors.Wrap(err, "unable to open file")}
@@ -112,7 +112,7 @@ func (u *Uploader) uploadFileInternal(ctx context.Context, f fs.File, relativePa
 	})
 	defer writer.Close() //nolint:errcheck
 
-	written, err := u.copyWithProgress(relativePath, writer, file, 0, f.Size())
+	written, err := u.copyWithProgress(writer, file, 0, f.Size())
 	if err != nil {
 		return entryResult{err: err}
 	}
@@ -133,7 +133,7 @@ func (u *Uploader) uploadFileInternal(ctx context.Context, f fs.File, relativePa
 	return entryResult{de: de, hash: metadataHash(fi2, written)}
 }
 
-func (u *Uploader) uploadSymlinkInternal(ctx context.Context, f fs.Symlink, relativePath string) entryResult {
+func (u *Uploader) uploadSymlinkInternal(ctx context.Context, f fs.Symlink) entryResult {
 	target, err := f.Readlink(ctx)
 	if err != nil {
 		return entryResult{err: errors.Wrap(err, "unable to read symlink")}
@@ -144,7 +144,7 @@ func (u *Uploader) uploadSymlinkInternal(ctx context.Context, f fs.Symlink, rela
 	})
 	defer writer.Close() //nolint:errcheck
 
-	written, err := u.copyWithProgress(relativePath, writer, bytes.NewBufferString(target), 0, f.Size())
+	written, err := u.copyWithProgress(writer, bytes.NewBufferString(target), 0, f.Size())
 	if err != nil {
 		return entryResult{err: err}
 	}
@@ -178,7 +178,7 @@ func (u *Uploader) addDirProgress(length int64) {
 	}
 }
 
-func (u *Uploader) copyWithProgress(path string, dst io.Writer, src io.Reader, completed int64, length int64) (int64, error) {
+func (u *Uploader) copyWithProgress(dst io.Writer, src io.Reader, completed, length int64) (int64, error) {
 	uploadBuf := make([]byte, 128*1024) // 128 KB buffer
 
 	var written int64
@@ -247,7 +247,7 @@ func newDirEntry(md fs.Entry, oid object.ID) *snapshot.DirEntry {
 
 // uploadFile uploads the specified File to the repository.
 func (u *Uploader) uploadFile(ctx context.Context, file fs.File) (*snapshot.DirEntry, error) {
-	res := u.uploadFileInternal(ctx, file, file.Name())
+	res := u.uploadFileInternal(ctx, file)
 	if res.err != nil {
 		return nil, res.err
 	}
@@ -393,8 +393,7 @@ func (u *Uploader) prepareWorkItems(ctx context.Context, dirRelativePath string,
 		// ... and whether file metadata is identical to the previous one.
 		computedHash := metadataHash(entry, entry.Size())
 
-		switch entry.(type) {
-		case fs.File:
+		if entry, ok := entry.(fs.File); ok {
 			u.stats.TotalFileCount++
 			u.stats.TotalFileSize += entry.Size()
 			summ.TotalFileCount++
@@ -431,7 +430,7 @@ func (u *Uploader) prepareWorkItems(ctx context.Context, dirRelativePath string,
 					entry:             entry,
 					entryRelativePath: entryRelativePath,
 					uploadFunc: func() entryResult {
-						return u.uploadSymlinkInternal(ctx, entry, entryRelativePath)
+						return u.uploadSymlinkInternal(ctx, entry)
 					},
 				})
 
@@ -441,7 +440,7 @@ func (u *Uploader) prepareWorkItems(ctx context.Context, dirRelativePath string,
 					entry:             entry,
 					entryRelativePath: entryRelativePath,
 					uploadFunc: func() entryResult {
-						return u.uploadFileInternal(ctx, entry, entryRelativePath)
+						return u.uploadFileInternal(ctx, entry)
 					},
 				})
 
@@ -606,7 +605,7 @@ func NewUploader(r *repo.Repository) *Uploader {
 
 // Cancel requests cancellation of an upload that's in progress. Will typically result in an incomplete snapshot.
 func (u *Uploader) Cancel() {
-	atomic.StoreInt32(&u.cancelled, 1)
+	atomic.StoreInt32(&u.canceled, 1)
 }
 
 // Upload uploads contents of the specified filesystem entry (file or directory) to the repository and returns snapshot.Manifest with statistics.

+ 22 - 18
snapshot/snapshotfs/upload_test.go

@@ -17,7 +17,10 @@ import (
 	"github.com/kopia/kopia/snapshot"
 )
 
-const masterPassword = "foofoofoofoofoofoofoofoo"
+const (
+	masterPassword     = "foofoofoofoofoofoofoofoo"
+	defaultPermissions = 0777
+)
 
 type uploadTestHarness struct {
 	sourceDir *mockfs.Directory
@@ -63,24 +66,24 @@ func newUploadTestHarness() *uploadTestHarness {
 	}
 
 	sourceDir := mockfs.NewDirectory()
-	sourceDir.AddFile("f1", []byte{1, 2, 3}, 0777)
-	sourceDir.AddFile("f2", []byte{1, 2, 3, 4}, 0777)
-	sourceDir.AddFile("f3", []byte{1, 2, 3, 4, 5}, 0777)
+	sourceDir.AddFile("f1", []byte{1, 2, 3}, defaultPermissions)
+	sourceDir.AddFile("f2", []byte{1, 2, 3, 4}, defaultPermissions)
+	sourceDir.AddFile("f3", []byte{1, 2, 3, 4, 5}, defaultPermissions)
 
-	sourceDir.AddDir("d1", 0777)
-	sourceDir.AddDir("d1/d1", 0777)
-	sourceDir.AddDir("d1/d2", 0777)
-	sourceDir.AddDir("d2", 0777)
-	sourceDir.AddDir("d2/d1", 0777)
+	sourceDir.AddDir("d1", defaultPermissions)
+	sourceDir.AddDir("d1/d1", defaultPermissions)
+	sourceDir.AddDir("d1/d2", defaultPermissions)
+	sourceDir.AddDir("d2", defaultPermissions)
+	sourceDir.AddDir("d2/d1", defaultPermissions)
 
 	// Prepare directory contents.
-	sourceDir.AddFile("d1/d1/f1", []byte{1, 2, 3}, 0777)
-	sourceDir.AddFile("d1/d1/f2", []byte{1, 2, 3, 4}, 0777)
-	sourceDir.AddFile("d1/f2", []byte{1, 2, 3, 4}, 0777)
-	sourceDir.AddFile("d1/d2/f1", []byte{1, 2, 3}, 0777)
-	sourceDir.AddFile("d1/d2/f2", []byte{1, 2, 3, 4}, 0777)
-	sourceDir.AddFile("d2/d1/f1", []byte{1, 2, 3}, 0777)
-	sourceDir.AddFile("d2/d1/f2", []byte{1, 2, 3, 4}, 0777)
+	sourceDir.AddFile("d1/d1/f1", []byte{1, 2, 3}, defaultPermissions)
+	sourceDir.AddFile("d1/d1/f2", []byte{1, 2, 3, 4}, defaultPermissions)
+	sourceDir.AddFile("d1/f2", []byte{1, 2, 3, 4}, defaultPermissions)
+	sourceDir.AddFile("d1/d2/f1", []byte{1, 2, 3}, defaultPermissions)
+	sourceDir.AddFile("d1/d2/f2", []byte{1, 2, 3, 4}, defaultPermissions)
+	sourceDir.AddFile("d2/d1/f1", []byte{1, 2, 3}, defaultPermissions)
+	sourceDir.AddFile("d2/d1/f2", []byte{1, 2, 3, 4}, defaultPermissions)
 
 	th := &uploadTestHarness{
 		sourceDir: sourceDir,
@@ -91,6 +94,7 @@ func newUploadTestHarness() *uploadTestHarness {
 	return th
 }
 
+// nolint:gocyclo
 func TestUpload(t *testing.T) {
 	ctx := context.Background()
 	th := newUploadTestHarness()
@@ -125,7 +129,7 @@ func TestUpload(t *testing.T) {
 	}
 
 	// Add one more file, the s1.RootObjectID should change.
-	th.sourceDir.AddFile("d2/d1/f3", []byte{1, 2, 3, 4, 5}, 0777)
+	th.sourceDir.AddFile("d2/d1/f3", []byte{1, 2, 3, 4, 5}, defaultPermissions)
 	s3, err := u.Upload(ctx, th.sourceDir, snapshot.SourceInfo{}, s1)
 	if err != nil {
 		t.Errorf("upload failed: %v", err)
@@ -218,7 +222,7 @@ func TestUpload_SubDirectoryReadFailure(t *testing.T) {
 	}
 }
 
-func objectIDsEqual(o1 object.ID, o2 object.ID) bool {
+func objectIDsEqual(o1, o2 object.ID) bool {
 	return reflect.DeepEqual(o1, o2)
 }
 

+ 1 - 1
snapshot/source.go

@@ -30,7 +30,7 @@ func (ssi SourceInfo) String() string {
 // ParseSourceInfo parses a given path in the context of given hostname and username and returns
 // SourceInfo. The path may be bare (in which case it's interpreted as local path and canonicalized)
 // or may be 'username@host:path' where path, username and host are not processed.
-func ParseSourceInfo(path string, hostname string, username string) (SourceInfo, error) {
+func ParseSourceInfo(path, hostname, username string) (SourceInfo, error) {
 	if path == "(global)" {
 		return SourceInfo{}, nil
 	}

+ 3 - 2
tests/end_to_end_test/end_to_end_test.go

@@ -1,6 +1,7 @@
 package endtoend_test
 
 import (
+	cryptorand "crypto/rand"
 	"encoding/hex"
 	"fmt"
 	"io"
@@ -17,7 +18,7 @@ import (
 	"github.com/kylelemons/godebug/pretty"
 )
 
-const repoPassword = "qWQPJ2hiiLgWRRCr"
+const repoPassword = "qWQPJ2hiiLgWRRCr" // nolint:gosec
 
 type testenv struct {
 	repoDir   string
@@ -392,7 +393,7 @@ func mustParseSnapshots(t *testing.T, lines []string) []sourceInfo {
 
 func randomName() string {
 	b := make([]byte, rand.Intn(10)+3)
-	rand.Read(b)
+	cryptorand.Read(b) // nolint:errcheck
 	return hex.EncodeToString(b)
 }
 

+ 4 - 4
tests/repository_stress_test/repository_stress_test.go

@@ -2,6 +2,7 @@ package repositorystress_test
 
 import (
 	"context"
+	cryptorand "crypto/rand"
 	"fmt"
 	"io/ioutil"
 	"log"
@@ -21,7 +22,7 @@ import (
 	"github.com/kopia/kopia/repo/content"
 )
 
-const masterPassword = "foo-bar-baz-1234"
+const masterPassword = "foo-bar-baz-1234" // nolint:gosec
 
 var (
 	knownBlocks      []content.ID
@@ -151,7 +152,7 @@ func repositoryTest(ctx context.Context, t *testing.T, cancel chan struct{}, rep
 		weight   int
 		hitCount int
 	}{
-		//{"reopen", reopen, 1, 0},
+		// {"reopen", reopen, 1, 0},
 		{"writeRandomBlock", writeRandomBlock, 100, 0},
 		{"writeRandomManifest", writeRandomManifest, 100, 0},
 		{"readKnownBlock", readKnownBlock, 500, 0},
@@ -190,7 +191,6 @@ func repositoryTest(ctx context.Context, t *testing.T, cancel chan struct{}, rep
 		for _, w := range workTypes {
 			if roulette < w.weight {
 				w.hitCount++
-				//log.Printf("running %v", w.name)
 				if err := w.fun(ctx, t, rep); err != nil {
 					w.hitCount++
 					t.Errorf("error: %v", errors.Wrapf(err, "error running %v", w.name))
@@ -207,7 +207,7 @@ func repositoryTest(ctx context.Context, t *testing.T, cancel chan struct{}, rep
 
 func writeRandomBlock(ctx context.Context, t *testing.T, r *repo.Repository) error {
 	data := make([]byte, 1000)
-	rand.Read(data)
+	cryptorand.Read(data) //nolint:errcheck
 	contentID, err := r.Content.WriteContent(ctx, data, "")
 	if err == nil {
 		knownBlocksMutex.Lock()

+ 12 - 14
tests/stress_test/stress_test.go

@@ -37,7 +37,7 @@ func stressTestWithStorage(t *testing.T, st blob.Storage, duration time.Duration
 	ctx := context.Background()
 
 	openMgr := func() (*content.Manager, error) {
-		return content.NewManager(ctx, st, content.FormattingOptions{
+		return content.NewManager(ctx, st, &content.FormattingOptions{
 			Version:     1,
 			Hash:        "HMAC-SHA256-128",
 			Encryption:  "AES-256-CTR",
@@ -57,15 +57,15 @@ func stressTestWithStorage(t *testing.T, st blob.Storage, duration time.Duration
 			i := i
 			t.Run(fmt.Sprintf("worker-%v", i), func(t *testing.T) {
 				t.Parallel()
-				stressWorker(ctx, t, deadline, i, openMgr, int64(seed0+i))
+				stressWorker(ctx, t, deadline, openMgr, int64(seed0+i))
 			})
 		}
 	})
 }
 
-func stressWorker(ctx context.Context, t *testing.T, deadline time.Time, workerID int, openMgr func() (*content.Manager, error), seed int64) {
+func stressWorker(ctx context.Context, t *testing.T, deadline time.Time, openMgr func() (*content.Manager, error), seed int64) {
 	src := rand.NewSource(seed)
-	rand := rand.New(src)
+	rnd := rand.New(src)
 
 	bm, err := openMgr()
 	if err != nil {
@@ -80,9 +80,9 @@ func stressWorker(ctx context.Context, t *testing.T, deadline time.Time, workerI
 	var workerBlocks []writtenBlock
 
 	for time.Now().Before(deadline) {
-		l := rand.Intn(30000)
+		l := rnd.Intn(30000)
 		data := make([]byte, l)
-		if _, err := rand.Read(data); err != nil {
+		if _, err := rnd.Read(data); err != nil {
 			t.Errorf("err: %v", err)
 			return
 		}
@@ -93,15 +93,15 @@ func stressWorker(ctx context.Context, t *testing.T, deadline time.Time, workerI
 			return
 		}
 
-		switch rand.Intn(20) {
+		switch rnd.Intn(20) {
 		case 0:
-			if err := bm.Flush(ctx); err != nil {
-				t.Errorf("flush error: %v", err)
+			if ferr := bm.Flush(ctx); ferr != nil {
+				t.Errorf("flush error: %v", ferr)
 				return
 			}
 		case 1:
-			if err := bm.Flush(ctx); err != nil {
-				t.Errorf("flush error: %v", err)
+			if ferr := bm.Flush(ctx); ferr != nil {
+				t.Errorf("flush error: %v", ferr)
 				return
 			}
 			bm, err = openMgr()
@@ -111,12 +111,10 @@ func stressWorker(ctx context.Context, t *testing.T, deadline time.Time, workerI
 			}
 		}
 
-		//log.Printf("wrote %v", contentID)
 		workerBlocks = append(workerBlocks, writtenBlock{contentID, dataCopy})
 		if len(workerBlocks) > 5 {
-			pos := rand.Intn(len(workerBlocks))
+			pos := rnd.Intn(len(workerBlocks))
 			previous := workerBlocks[pos]
-			//log.Printf("reading %v", previous.contentID)
 			d2, err := bm.GetContent(ctx, previous.contentID)
 			if err != nil {
 				t.Errorf("error verifying content %q: %v", previous.contentID, err)