goduf.go
changeset 34 b70346ff153d
parent 25 129fd2cee200
child 35 730377b4449f
equal deleted inserted replaced
33:649ba4266d21 34:b70346ff153d
     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.
    31 	"encoding/hex"
    31 	"encoding/hex"
    32 	"errors"
    32 	"errors"
    33 	"flag"
    33 	"flag"
    34 	"fmt"
    34 	"fmt"
    35 	"io"
    35 	"io"
    36 	"log"
       
    37 	"os"
    36 	"os"
    38 	"path/filepath"
    37 	"path/filepath"
    39 	"sort"
    38 	"sort"
    40 )
    39 )
    41 
    40 
    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")
   518 		os.Exit(0)
   489 		os.Exit(0)
   519 	}
   490 	}
   520 
   491 
   521 	// Change log format for benchmarking
   492 	// Change log format for benchmarking
   522 	if *timings {
   493 	if *timings {
   523 		log.SetFlags(log.LstdFlags | log.Lmicroseconds)
   494 		myLog.SetBenchFlags()
   524 	}
   495 	}
   525 
   496 
   526 	data.sizeGroups = make(map[int64]*FileObjList)
   497 	data.sizeGroups = make(map[int64]*FileObjList)
   527 	myLog.Println(1, "* Reading file metadata")
   498 	myLog.Println(1, "* Reading file metadata")
   528 
   499 
   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 }