1 /* |
1 /* |
2 * Copyright (C) 2014-2017 Mikael Berthe <mikael@lilotux.net> |
2 * Copyright (C) 2014-2018 Mikael Berthe <mikael@lilotux.net> |
3 * |
3 * |
4 * This program is free software; you can redistribute it and/or modify |
4 * This program is free software; you can redistribute it and/or modify |
5 * it under the terms of the GNU General Public License as published by |
5 * it under the terms of the GNU General Public License as published by |
6 * the Free Software Foundation; either version 2 of the License, or (at |
6 * the Free Software Foundation; either version 2 of the License, or (at |
7 * your option) any later version. |
7 * your option) any later version. |
71 ignoreCount int |
70 ignoreCount int |
72 } |
71 } |
73 |
72 |
74 var data dataT |
73 var data dataT |
75 |
74 |
76 type myLogT struct { |
|
77 verbosity int |
|
78 } |
|
79 |
|
80 // Implement my own logger |
75 // Implement my own logger |
81 var myLog myLogT |
76 var myLog myLogT |
82 |
|
83 func (l *myLogT) Printf(level int, format string, args ...interface{}) { |
|
84 if level > l.verbosity { |
|
85 return |
|
86 } |
|
87 if level >= 0 { |
|
88 log.Printf(format, args...) |
|
89 return |
|
90 } |
|
91 // Error message without timestamp |
|
92 fmt.Fprintf(os.Stderr, format, args...) |
|
93 } |
|
94 |
|
95 func (l *myLogT) Println(level int, args ...interface{}) { |
|
96 if level > l.verbosity { |
|
97 return |
|
98 } |
|
99 if level >= 0 { |
|
100 log.Println(args...) |
|
101 return |
|
102 } |
|
103 // Error message without timestamp |
|
104 fmt.Fprintln(os.Stderr, args...) |
|
105 } |
|
106 |
77 |
107 // visit is called for every file and directory. |
78 // visit is called for every file and directory. |
108 // We check the file object is correct (regular, readable...) and add |
79 // We check the file object is correct (regular, readable...) and add |
109 // it to the data.sizeGroups hash. |
80 // it to the data.sizeGroups hash. |
110 func visit(path string, f os.FileInfo, err error) error { |
81 func visit(path string, f os.FileInfo, err error) error { |
485 var skipPartial bool |
456 var skipPartial bool |
486 var ignoreEmpty bool |
457 var ignoreEmpty bool |
487 |
458 |
488 // Assertion on constant values |
459 // Assertion on constant values |
489 if minSizePartialChecksum <= 2*medsumBytes { |
460 if minSizePartialChecksum <= 2*medsumBytes { |
490 log.Fatal("Internal error: assert minSizePartialChecksum > 2*medsumBytes") |
461 myLog.Fatal("Internal error: assert minSizePartialChecksum > 2*medsumBytes") |
491 } |
462 } |
492 |
463 |
493 // Command line parameters parsingg |
464 // Command line parameters parsingg |
494 flag.BoolVar(&verbose, "verbose", false, "Be verbose (verbosity=1)") |
465 flag.BoolVar(&verbose, "verbose", false, "Be verbose (verbosity=1)") |
495 flag.BoolVar(&verbose, "v", false, "See --verbose") |
466 flag.BoolVar(&verbose, "v", false, "See --verbose") |
619 myLog.Println(summaryLevel, "Final count:", data.cmpt, |
590 myLog.Println(summaryLevel, "Final count:", data.cmpt, |
620 "duplicate files in", len(result), "sets") |
591 "duplicate files in", len(result), "sets") |
621 myLog.Println(summaryLevel, "Redundant data size:", |
592 myLog.Println(summaryLevel, "Redundant data size:", |
622 formatSize(dupeSize, false)) |
593 formatSize(dupeSize, false)) |
623 } |
594 } |
624 |
|
625 // Implement a sort interface for the list of duplicate groups |
|
626 type byGroupFileSize foListList |
|
627 |
|
628 func (a byGroupFileSize) Len() int { return len(a) } |
|
629 func (a byGroupFileSize) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
|
630 func (a byGroupFileSize) Less(i, j int) bool { |
|
631 // Since this is supposed to be used for duplicate lists, |
|
632 // we use the size of the first file of the group. |
|
633 if a[i][0].Size() == a[j][0].Size() { |
|
634 return a[i][0].FilePath < a[j][0].FilePath |
|
635 } |
|
636 return a[i][0].Size() < a[j][0].Size() |
|
637 } |
|
638 |
|
639 // Implement a sort interface for a slice of files |
|
640 type byFilePathName FileObjList |
|
641 |
|
642 func (a byFilePathName) Len() int { return len(a) } |
|
643 func (a byFilePathName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
|
644 func (a byFilePathName) Less(i, j int) bool { |
|
645 return a[i].FilePath < a[j].FilePath |
|
646 } |
|