diff --git a/cmd/hasher/calculate.go b/cmd/hasher/calculate.go index 29d43a9..825158b 100644 --- a/cmd/hasher/calculate.go +++ b/cmd/hasher/calculate.go @@ -1,271 +1,57 @@ package main import ( - "encoding/hex" - "fmt" - "os" "path/filepath" - "strconv" - "strings" cla "github.com/vault-thirteen/Hasher/pkg/Models/CommandLineArguments" - ht "github.com/vault-thirteen/Hasher/pkg/Models/HashType" + h "github.com/vault-thirteen/Hasher/pkg/Models/Hashing" ot "github.com/vault-thirteen/Hasher/pkg/Models/ObjectType" - "github.com/vault-thirteen/Hasher/pkg/hash" - sc "github.com/vault-thirteen/Hasher/pkg/strconv" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" ) func calculateHash(args *cla.CommandLineArguments) (err error) { switch args.ObjectType().ID() { - case ot.IdFile: + case ot.Id_File: return calculateHashOfFile(args) - case ot.IdFolder: + case ot.Id_Folder: return calculateHashOfFolder(args) default: - return fmt.Errorf(ot.ErrUnknown, args.ObjectType()) + return c.ErrorA1(ot.ErrUnknownObjectType, args.ObjectType()) } } func calculateHashOfFile(args *cla.CommandLineArguments) (err error) { - switch args.HashType().ID() { - case ht.IdCRC32: - return calculateFileHashCRC32(args) - case ht.IdMD5: - return calculateFileHashMD5(args) - case ht.IdSHA256: - return calculateFileHashSHA256(args) - case ht.IdFileSize: - return calculateFileHashFileSize(args) - case ht.IdFileExistence: - return calculateFileHashFileExistence(args) - default: - return fmt.Errorf(ht.ErrUnknown, args.HashType()) - } -} - -func calculateFileHashCRC32(args *cla.CommandLineArguments) (err error) { - var sum uint32 - sum, err = hash.GetFileHashCRC32(args.ObjectPath()) - if err != nil { - return err - } - - printHashLine(strings.ToUpper(strconv.FormatUint(uint64(sum), 16)), filepath.Base(args.ObjectPath())) - return nil -} - -func calculateFileHashMD5(args *cla.CommandLineArguments) (err error) { - var sum []byte - sum, err = hash.GetFileHashMD5(args.ObjectPath()) - if err != nil { - return err - } - - printHashLine(strings.ToUpper(hex.EncodeToString(sum[:])), filepath.Base(args.ObjectPath())) - return nil -} + file := args.ObjectPath() -func calculateFileHashSHA256(args *cla.CommandLineArguments) (err error) { - var sum []byte - sum, err = hash.GetFileHashSHA256(args.ObjectPath()) + var hasher *h.Hashing + hasher, err = h.NewHashing(args.HashType().ID()) if err != nil { return err } - printHashLine(strings.ToUpper(hex.EncodeToString(sum[:])), filepath.Base(args.ObjectPath())) - return nil -} - -func calculateFileHashFileSize(args *cla.CommandLineArguments) (err error) { - var sum int64 - sum, err = hash.GetFileHashFileSize(args.ObjectPath()) + var result *h.HashingResult + result, err = hasher.Calculate(file) if err != nil { return err } - printHashLine(strconv.FormatInt(sum, 10), filepath.Base(args.ObjectPath())) - return nil -} - -func calculateFileHashFileExistence(args *cla.CommandLineArguments) (err error) { - var sum bool - sum, err = hash.GetFileHashFileExistence(args.ObjectPath()) - if err != nil { - return err - } - - printHashLine(sc.FormatBooleanAsNumber(sum), filepath.Base(args.ObjectPath())) + c.PrintHashLine(result.ToString(), filepath.Base(file)) return nil } func calculateHashOfFolder(args *cla.CommandLineArguments) (err error) { - switch args.HashType().ID() { - case ht.IdCRC32: - return calculateFolderHashCRC32(args) - case ht.IdMD5: - return calculateFolderHashMD5(args) - case ht.IdSHA256: - return calculateFolderHashSHA256(args) - case ht.IdFileSize: - return calculateFolderHashFileSize(args) - case ht.IdFileExistence: - return calculateFolderHashFileExistence(args) - default: - return fmt.Errorf(ht.ErrUnknown, args.HashType()) - } -} - -func calculateFolderHashCRC32(args *cla.CommandLineArguments) (err error) { basePath := args.ObjectPath() - err = filepath.Walk(basePath, crc32DirWalker) + var hasher *h.Hashing + hasher, err = h.NewHashing(args.HashType().ID()) if err != nil { return err } - return nil -} - -func crc32DirWalker(path string, fi os.FileInfo, err error) error { + err = filepath.Walk(basePath, hasher.WalkerFn) if err != nil { return err } - if fi.IsDir() { - return nil - } - - var sum uint32 - sum, err = hash.GetFileHashCRC32(path) - if err != nil { - return err - } - - printHashLine(strings.ToUpper(strconv.FormatUint(uint64(sum), 16)), path) - - return nil -} - -func calculateFolderHashMD5(args *cla.CommandLineArguments) (err error) { - basePath := args.ObjectPath() - - err = filepath.Walk(basePath, md5DirWalker) - if err != nil { - return err - } - - return nil -} - -func md5DirWalker(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if fi.IsDir() { - return nil - } - - var sum []byte - sum, err = hash.GetFileHashMD5(path) - if err != nil { - return err - } - - printHashLine(strings.ToUpper(hex.EncodeToString(sum[:])), path) - - return nil -} - -func calculateFolderHashSHA256(args *cla.CommandLineArguments) (err error) { - basePath := args.ObjectPath() - - err = filepath.Walk(basePath, sha256DirWalker) - if err != nil { - return err - } - - return nil -} - -func calculateFolderHashFileSize(args *cla.CommandLineArguments) (err error) { - basePath := args.ObjectPath() - - err = filepath.Walk(basePath, fileSizeDirWalker) - if err != nil { - return err - } - - return nil -} - -func calculateFolderHashFileExistence(args *cla.CommandLineArguments) (err error) { - basePath := args.ObjectPath() - - err = filepath.Walk(basePath, fileExistenceDirWalker) - if err != nil { - return err - } - - return nil -} - -func sha256DirWalker(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if fi.IsDir() { - return nil - } - - var sum []byte - sum, err = hash.GetFileHashSHA256(path) - if err != nil { - return err - } - - printHashLine(strings.ToUpper(hex.EncodeToString(sum[:])), path) - - return nil -} - -func fileSizeDirWalker(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if fi.IsDir() { - return nil - } - - var sum int64 - sum, err = hash.GetFileHashFileSize(path) - if err != nil { - return err - } - - printHashLine(strconv.FormatInt(sum, 10), path) - - return nil -} - -func fileExistenceDirWalker(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if fi.IsDir() { - return nil - } - - var sum bool - sum, err = hash.GetFileHashFileExistence(path) - if err != nil { - return err - } - - printHashLine(sc.FormatBooleanAsNumber(sum), path) - return nil } diff --git a/cmd/hasher/check.go b/cmd/hasher/check.go index 3a23035..c13c506 100644 --- a/cmd/hasher/check.go +++ b/cmd/hasher/check.go @@ -1,253 +1,46 @@ package main import ( - "encoding/hex" - "errors" - "fmt" "io" "os" - "strconv" - "strings" + ch "github.com/vault-thirteen/Hasher/pkg/Models/Check" cla "github.com/vault-thirteen/Hasher/pkg/Models/CommandLineArguments" - ht "github.com/vault-thirteen/Hasher/pkg/Models/HashType" + h "github.com/vault-thirteen/Hasher/pkg/Models/Hashing" ot "github.com/vault-thirteen/Hasher/pkg/Models/ObjectType" - "github.com/vault-thirteen/Hasher/pkg/hash" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" ae "github.com/vault-thirteen/auxie/errors" - "github.com/vault-thirteen/auxie/number" "github.com/vault-thirteen/auxie/reader" ) const ( - ErrFolderCheckIsNotPossible = "folder check is not possible, use file check" - ErrChecksumMismatch = "checksum mismatch: '%s' vs '%s'" - ErrDataIsDamaged = "data is damaged" - ErrDamagedEntriesCountLimitReached = "too many damaged entries" + ErrFolderCheckIsNotPossible = "folder check is not possible, use file check" ) -const ( - TplHr = "--------------------------------------------------------------------------------" - TplError = "[ERROR] " - TplOK = "[ OK ] " - TplSummary = "Total files checked: %d. Good files: %d. Bad files: %d." - MsgErrorsWereFound = "Errors were found !" - MsgAllClear = "All clear." - DamagedEntriesCountLimit = 10 -) - -func checkHash(args *cla.CommandLineArguments) (err error) { +func checkHash(args *cla.CommandLineArguments) (results *ch.Check, err error) { switch args.ObjectType().ID() { - case ot.IdFile: + case ot.Id_File: return checkHashesInFile(args) - case ot.IdFolder: - return errors.New(ErrFolderCheckIsNotPossible) + case ot.Id_Folder: + return nil, c.Error(ErrFolderCheckIsNotPossible) default: - return fmt.Errorf(ot.ErrUnknown, args.ObjectType()) - } -} - -func checkHashesInFile(args *cla.CommandLineArguments) (err error) { - switch args.HashType().ID() { - case ht.IdCRC32: - return checkCRC32HashesInFile(args.ObjectPath()) - case ht.IdMD5: - return checkMD5HashesInFile(args.ObjectPath()) - case ht.IdSHA256: - return checkSHA256HashesInFile(args.ObjectPath()) - case ht.IdFileSize: - return checkFileSizeHashesInFile(args.ObjectPath()) - case ht.IdFileExistence: - return checkFileExistenceHashesInFile(args.ObjectPath()) - default: - return fmt.Errorf(ht.ErrUnknown, args.HashType()) - } -} - -func checkCRC32HashesInFile(filePath string) (err error) { - var f *os.File - f, err = os.Open(filePath) - if err != nil { - return err - } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - var ( - r = reader.New(f) - buf []byte - checkErr error - file string - nGood, nBad, nTotal, nDamaged int - ) - - fmt.Println(TplHr) - - for { - if nDamaged > DamagedEntriesCountLimit { - return errors.New(ErrDamagedEntriesCountLimitReached) - } - - // Yes. Each line in the hash sum file must end with CR+LF. - // If you are a user of Unix, Linux, OS X, Mac OS or any other OS with - // non-standard line ends, please, check this article: - // https://en.wikipedia.org/wiki/Newline - buf, err = r.ReadLineEndingWithCRLF() - if err == nil { - file, checkErr = checkCRC32Line(buf) - if checkErr != nil { - nBad++ - if len(file) == 0 { - nDamaged++ - file = "???" - } - fmt.Println(TplError, file) - } else { - nGood++ - fmt.Println(TplOK, file) - } - nTotal++ - continue - } - - if err == io.EOF { - break - } - - return err - } - - fmt.Println(TplHr) - if (nTotal == nGood) && (nBad == 0) { - fmt.Println(MsgAllClear) - } else { - fmt.Println(MsgErrorsWereFound) - } - fmt.Println(fmt.Sprintf(TplSummary, nTotal, nGood, nBad)) - - return nil -} - -func checkCRC32Line(buf []byte) (file string, err error) { - if len(buf) < 10 { - return file, errors.New(ErrDataIsDamaged) - } - - var sumA string - var sumTmp uint32 - sumA = strings.ToUpper(string(buf[:8])) - file = strings.TrimSpace(string(buf[9:])) - sumTmp, err = hash.GetFileHashCRC32(file) - if err != nil { - return file, err + return nil, c.ErrorA1(ot.ErrUnknownObjectType, args.ObjectType()) } - - if sumA != strings.ToUpper(strconv.FormatUint(uint64(sumTmp), 16)) { - err = fmt.Errorf(ErrChecksumMismatch, sumA, strings.ToUpper(strconv.FormatUint(uint64(sumTmp), 16))) - return file, err - } - - return file, nil } -func checkMD5HashesInFile(filePath string) (err error) { - var f *os.File - f, err = os.Open(filePath) +func checkHashesInFile(args *cla.CommandLineArguments) (results *ch.Check, err error) { + var hasher *h.Hashing + hasher, err = h.NewHashing(args.HashType().ID()) if err != nil { - return err + return nil, err } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - var ( - r = reader.New(f) - buf []byte - checkErr error - file string - nGood, nBad, nTotal, nDamaged int - ) - fmt.Println(TplHr) - - for { - if nDamaged > DamagedEntriesCountLimit { - return errors.New(ErrDamagedEntriesCountLimitReached) - } - - // Yes. Each line in the hash sum file must end with CR+LF. - // If you are a user of Unix, Linux, OS X, Mac OS or any other OS with - // non-standard line ends, please, check this article: - // https://en.wikipedia.org/wiki/Newline - buf, err = r.ReadLineEndingWithCRLF() - if err == nil { - file, checkErr = checkMD5Line(buf) - if checkErr != nil { - nBad++ - if len(file) == 0 { - nDamaged++ - file = "???" - } - fmt.Println(TplError, file) - } else { - nGood++ - fmt.Println(TplOK, file) - } - nTotal++ - continue - } - - if err == io.EOF { - break - } + mainFilePath := args.ObjectPath() - return err - } - - fmt.Println(TplHr) - if (nTotal == nGood) && (nBad == 0) { - fmt.Println(MsgAllClear) - } else { - fmt.Println(MsgErrorsWereFound) - } - fmt.Println(fmt.Sprintf(TplSummary, nTotal, nGood, nBad)) - - return nil -} - -func checkMD5Line(buf []byte) (file string, err error) { - if len(buf) < 34 { - return file, errors.New(ErrDataIsDamaged) - } - - var sumA string - var sumTmp []byte - sumA = strings.ToUpper(string(buf[:32])) - file = strings.TrimSpace(string(buf[33:])) - sumTmp, err = hash.GetFileHashMD5(file) - if err != nil { - return file, err - } - - if sumA != strings.ToUpper(hex.EncodeToString(sumTmp)) { - err = fmt.Errorf(ErrChecksumMismatch, sumA, strings.ToUpper(hex.EncodeToString(sumTmp))) - return file, err - } - - return file, nil -} - -func checkSHA256HashesInFile(filePath string) (err error) { var f *os.File - f, err = os.Open(filePath) + f, err = os.Open(mainFilePath) if err != nil { - return err + return nil, err } defer func() { derr := f.Close() @@ -256,269 +49,48 @@ func checkSHA256HashesInFile(filePath string) (err error) { } }() - var ( - r = reader.New(f) - buf []byte - checkErr error - file string - nGood, nBad, nTotal, nDamaged int - ) - - fmt.Println(TplHr) + var rdr = reader.New(f) + var line []byte + results = ch.NewCheck() + var hashText string + var hash any + var result *ch.CheckedFile for { - if nDamaged > DamagedEntriesCountLimit { - return errors.New(ErrDamagedEntriesCountLimitReached) - } - - // Yes. Each line in the hash sum file must end with CR+LF. - // If you are a user of Unix, Linux, OS X, Mac OS or any other OS with - // non-standard line ends, please, check this article: - // https://en.wikipedia.org/wiki/Newline - buf, err = r.ReadLineEndingWithCRLF() - if err == nil { - file, checkErr = checkSHA256Line(buf) - if checkErr != nil { - nBad++ - if len(file) == 0 { - nDamaged++ - file = "???" - } - fmt.Println(TplError, file) + line, err = rdr.ReadLineEndingWithCRLF() + if err != nil { + if err == io.EOF { + break } else { - nGood++ - fmt.Println(TplOK, file) + return nil, err } - nTotal++ - continue - } - - if err == io.EOF { - break } - return err - } - - fmt.Println(TplHr) - if (nTotal == nGood) && (nBad == 0) { - fmt.Println(MsgAllClear) - } else { - fmt.Println(MsgErrorsWereFound) - } - fmt.Println(fmt.Sprintf(TplSummary, nTotal, nGood, nBad)) - - return nil -} - -func checkFileSizeHashesInFile(filePath string) (err error) { - var f *os.File - f, err = os.Open(filePath) - if err != nil { - return err - } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - var ( - r = reader.New(f) - buf []byte - checkErr error - file string - nGood, nBad, nTotal, nDamaged int - ) - - fmt.Println(TplHr) - - for { - if nDamaged > DamagedEntriesCountLimit { - return errors.New(ErrDamagedEntriesCountLimitReached) - } - - // Yes. Each line in the hash sum file must end with CR+LF. - // If you are a user of Unix, Linux, OS X, Mac OS or any other OS with - // non-standard line ends, please, check this article: - // https://en.wikipedia.org/wiki/Newline - buf, err = r.ReadLineEndingWithCRLF() - if err == nil { - file, checkErr = checkFileSizeLine(buf) - if checkErr != nil { - nBad++ - if len(file) == 0 { - nDamaged++ - file = "???" - } - fmt.Println(TplError, file) - } else { - nGood++ - fmt.Println(TplOK, file) - } - nTotal++ + if len(line) == 0 { + results.AddFile(nil) continue } - if err == io.EOF { - break - } - - return err - } - - fmt.Println(TplHr) - if (nTotal == nGood) && (nBad == 0) { - fmt.Println(MsgAllClear) - } else { - fmt.Println(MsgErrorsWereFound) - } - fmt.Println(fmt.Sprintf(TplSummary, nTotal, nGood, nBad)) - - return nil -} - -func checkSHA256Line(buf []byte) (file string, err error) { - if len(buf) < 66 { - return file, errors.New(ErrDataIsDamaged) - } - - var sumA string - var sumTmp []byte - sumA = strings.ToUpper(string(buf[:64])) - file = strings.TrimSpace(string(buf[65:])) - sumTmp, err = hash.GetFileHashSHA256(file) - if err != nil { - return file, err - } - - if sumA != strings.ToUpper(hex.EncodeToString(sumTmp)) { - err = fmt.Errorf(ErrChecksumMismatch, sumA, strings.ToUpper(hex.EncodeToString(sumTmp))) - return file, err - } - - return file, nil -} - -func checkFileSizeLine(buf []byte) (file string, err error) { - parts := strings.Split(string(buf), " ") - if len(parts) != 2 { - return file, errors.New(ErrDataIsDamaged) - } - - var sumA int64 - sumA, err = number.ParseInt64(parts[0]) - if err != nil { - return file, err - } - - var sumTmp int64 - file = strings.TrimSpace(parts[1]) - sumTmp, err = hash.GetFileHashFileSize(file) - if err != nil { - return file, err - } - - if sumA != sumTmp { - err = fmt.Errorf(ErrChecksumMismatch, sumA, sumTmp) - return file, err - } - - return file, nil -} - -func checkFileExistenceHashesInFile(filePath string) (err error) { - var f *os.File - f, err = os.Open(filePath) - if err != nil { - return err - } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - var ( - r = reader.New(f) - buf []byte - checkErr error - file string - nGood, nBad, nTotal, nDamaged int - ) - - fmt.Println(TplHr) + result = &ch.CheckedFile{} - for { - if nDamaged > DamagedEntriesCountLimit { - return errors.New(ErrDamagedEntriesCountLimitReached) + hashText, result.Path, err = hasher.ParseFileLine(line) + if err != nil { + return nil, err } - // Yes. Each line in the hash sum file must end with CR+LF. - // If you are a user of Unix, Linux, OS X, Mac OS or any other OS with - // non-standard line ends, please, check this article: - // https://en.wikipedia.org/wiki/Newline - buf, err = r.ReadLineEndingWithCRLF() - if err == nil { - file, checkErr = checkFileExistenceLine(buf) - if checkErr != nil { - nBad++ - if len(file) == 0 { - nDamaged++ - file = "???" - } - fmt.Println(TplError, file) - } else { - nGood++ - fmt.Println(TplOK, file) - } - nTotal++ - continue + hash, err = hasher.ParseHash(hashText) + if err != nil { + return nil, err } - if err == io.EOF { - break + result.Ok, err = hasher.Verify(result.Path, hash) + if err != nil { + return nil, err } - return err - } - - fmt.Println(TplHr) - if (nTotal == nGood) && (nBad == 0) { - fmt.Println(MsgAllClear) - } else { - fmt.Println(MsgErrorsWereFound) - } - fmt.Println(fmt.Sprintf(TplSummary, nTotal, nGood, nBad)) - - return nil -} - -func checkFileExistenceLine(buf []byte) (file string, err error) { - parts := strings.Split(string(buf), " ") - if len(parts) != 2 { - return file, errors.New(ErrDataIsDamaged) - } - - var sumA bool - sumA, err = strconv.ParseBool(parts[0]) - if err != nil { - return file, err - } - - var sumTmp bool - file = strings.TrimSpace(parts[1]) - sumTmp, err = hash.GetFileHashFileExistence(file) - if err != nil { - return file, err - } - - if sumA != sumTmp { - err = fmt.Errorf(ErrChecksumMismatch, sumA, sumTmp) - return file, err + results.AddFile(result) + continue } - return file, nil + return results, nil } diff --git a/cmd/hasher/main.go b/cmd/hasher/main.go index b95c619..c7a7711 100644 --- a/cmd/hasher/main.go +++ b/cmd/hasher/main.go @@ -6,7 +6,9 @@ import ( "os" a "github.com/vault-thirteen/Hasher/pkg/Models/Action" + ch "github.com/vault-thirteen/Hasher/pkg/Models/Check" cla "github.com/vault-thirteen/Hasher/pkg/Models/CommandLineArguments" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" ver "github.com/vault-thirteen/auxie/Versioneer" ) @@ -29,10 +31,6 @@ Notes: Checker reads lines with standard line end (CR+LF). Change directory (CD) to a working directory before usage.` -const ( - OutputFormat = "%v %s\r\n" // [1]=Sum, [2]=ObjectName. -) - func main() { args, err := cla.New() if err != nil { @@ -43,15 +41,33 @@ func main() { return } + err = work(args) + mustBeNoError(err) +} + +func work(args *cla.CommandLineArguments) (err error) { switch args.Action().ID() { - case a.IdCalculate: + case a.Id_Calculate: err = calculateHash(args) - case a.IdCheck: - err = checkHash(args) + if err != nil { + return err + } + + case a.Id_Check: + var checkResults *ch.Check + checkResults, err = checkHash(args) + if err != nil { + return err + } + + checkResults.PrintReport() + default: - err = fmt.Errorf(a.ErrUnknown, args.Action()) + err = c.ErrorA1(a.ErrUnknownAction, args.Action()) + return err } - mustBeNoError(err) + + return nil } func mustBeNoError(err error) { @@ -71,7 +87,3 @@ func showIntro() { func showUsage() { fmt.Println(UsageHint) } - -func printHashLine(sum any, fileRelPath string) { - fmt.Printf(OutputFormat, sum, fileRelPath) -} diff --git a/pkg/Models/Action/Action.go b/pkg/Models/Action/Action.go index b23c48c..a373437 100644 --- a/pkg/Models/Action/Action.go +++ b/pkg/Models/Action/Action.go @@ -1,61 +1,39 @@ package a import ( - "fmt" "strings" -) - -const ( - IdCalculate = 1 - IdCheck = 2 - IdDefault = IdCalculate -) -const ( - NameCalculate = "CALCULATE" - NameCheck = "CHECK" - NameEmpty = "" - NameDefault = NameCalculate + c "github.com/vault-thirteen/Hasher/pkg/Models/common" ) const ( - ErrUnknown = "action is unknown: %v" + ErrUnknownAction = "action is unknown" ) type Action struct { - id byte - name string + id ActionId + name ActionName } -func New(actionName string) (action *Action, err error) { - switch strings.ToUpper(actionName) { - case NameCalculate: - return &Action{ - id: IdCalculate, - name: NameCalculate, - }, nil - - case NameCheck: - return &Action{ - id: IdCheck, - name: NameCheck, - }, nil - - case NameEmpty: - return &Action{ - id: IdDefault, - name: NameDefault, - }, nil - +func New(actionName string) (a *Action, err error) { + x := ActionName(strings.ToUpper(actionName)) + switch x { + case Name_Calculate: + a = &Action{id: Id_Calculate, name: Name_Calculate} + case Name_Check: + a = &Action{id: Id_Check, name: Name_Check} + case Name_Empty: + a = &Action{id: Id_Default, name: Name_Default} default: - return nil, fmt.Errorf(ErrUnknown, actionName) + return nil, c.ErrorA1(ErrUnknownAction, actionName) } + return a, nil } -func (a *Action) ID() (id byte) { +func (a *Action) ID() (id ActionId) { return a.id } -func (a *Action) Name() (name string) { +func (a *Action) Name() (name ActionName) { return a.name } diff --git a/pkg/Models/Action/ActionId.go b/pkg/Models/Action/ActionId.go new file mode 100644 index 0000000..a6b04f0 --- /dev/null +++ b/pkg/Models/Action/ActionId.go @@ -0,0 +1,10 @@ +package a + +type ActionId byte + +const ( + Id_Calculate = ActionId(1) + Id_Check = ActionId(2) + + Id_Default = Id_Calculate +) diff --git a/pkg/Models/Action/ActionName.go b/pkg/Models/Action/ActionName.go new file mode 100644 index 0000000..0c1c492 --- /dev/null +++ b/pkg/Models/Action/ActionName.go @@ -0,0 +1,15 @@ +package a + +type ActionName string + +const ( + Name_Calculate = ActionName("CALCULATE") + Name_Check = ActionName("CHECK") + Name_Empty = ActionName("") + + Name_Default = Name_Calculate +) + +func (a ActionName) ToString() string { + return string(a) +} diff --git a/pkg/Models/Check/Check.go b/pkg/Models/Check/Check.go new file mode 100644 index 0000000..fe41645 --- /dev/null +++ b/pkg/Models/Check/Check.go @@ -0,0 +1,73 @@ +package ch + +import "fmt" + +const ( + TplHr = "--------------------------------------------------------------------------------" + TplError = "[ERROR] " + TplOK = "[ OK ] " + TplSummary = "Total files checked: %d. Good files: %d. Bad files: %d." + MsgAllClear = "All clear." +) + +type Check struct { + Files []*CheckedFile + Counter CheckCounter +} + +func NewCheck() (c *Check) { + c = new(Check) + c.Files = make([]*CheckedFile, 0, 256) + return c +} + +func (c *Check) AddFile(file *CheckedFile) { + c.Counter.Total++ + + if file == nil { + c.Counter.Damaged++ + return + } + + c.Files = append(c.Files, file) + + if file.Ok { + c.Counter.Good++ + } else { + c.Counter.Bad++ + } +} + +func (c *Check) PrintReport() { + nBD := c.Counter.Bad + c.Counter.Damaged + + // IF all files are good. + if nBD == 0 { + fmt.Println(fmt.Sprintf(TplSummary, c.Counter.Total, c.Counter.Good, nBD)) + fmt.Println(MsgAllClear) + return + } + + // Otherwise, show the details. + lineFormat := "%s %s" + + // 1. Show good files. + fmt.Println(TplHr) + for _, file := range c.Files { + if file.Ok { + fmt.Println(fmt.Sprintf(lineFormat, TplOK, file.Path)) + } + } + + // 2. Show other files. + fmt.Println(TplHr) + for _, file := range c.Files { + if !file.Ok { + fmt.Println(fmt.Sprintf(lineFormat, TplError, file.Path)) + } + } + + // 3. Summary. + fmt.Println(TplHr) + fmt.Println(fmt.Sprintf(TplSummary, c.Counter.Total, c.Counter.Good, nBD)) +} diff --git a/pkg/Models/Check/CheckCounter.go b/pkg/Models/Check/CheckCounter.go new file mode 100644 index 0000000..72ca805 --- /dev/null +++ b/pkg/Models/Check/CheckCounter.go @@ -0,0 +1,8 @@ +package ch + +type CheckCounter struct { + Good int + Bad int + Damaged int + Total int +} diff --git a/pkg/Models/Check/CheckedFile.go b/pkg/Models/Check/CheckedFile.go new file mode 100644 index 0000000..a175eb9 --- /dev/null +++ b/pkg/Models/Check/CheckedFile.go @@ -0,0 +1,6 @@ +package ch + +type CheckedFile struct { + Path string + Ok bool +} diff --git a/pkg/Models/CommandLineArguments/CommandLineArguments.go b/pkg/Models/CommandLineArguments/CommandLineArguments.go index e36d46d..39b3ae6 100644 --- a/pkg/Models/CommandLineArguments/CommandLineArguments.go +++ b/pkg/Models/CommandLineArguments/CommandLineArguments.go @@ -1,13 +1,12 @@ package cla import ( - "errors" - "fmt" "os" a "github.com/vault-thirteen/Hasher/pkg/Models/Action" ht "github.com/vault-thirteen/Hasher/pkg/Models/HashType" ot "github.com/vault-thirteen/Hasher/pkg/Models/ObjectType" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" "github.com/vault-thirteen/auxie/file" ) @@ -32,26 +31,29 @@ func New() (cla *CommandLineArguments, err error) { computedArgs = append(computedArgs, os.Args[2]) computedArgs = append(computedArgs, os.Args[3]) computedArgs = append(computedArgs, os.Args[4]) + case 4: - computedArgs = append(computedArgs, a.NameDefault) + computedArgs = append(computedArgs, a.Name_Default.ToString()) computedArgs = append(computedArgs, os.Args[1]) computedArgs = append(computedArgs, os.Args[2]) computedArgs = append(computedArgs, os.Args[3]) + default: - return nil, errors.New(ErrSyntax) + return nil, c.Error(ErrSyntax) } // Stop those fools who are blind. cla = &CommandLineArguments{ objectPath: computedArgs[3], } - cla.objectType, err = ot.New(computedArgs[2]) + + cla.objectType, err = ot.New(ot.ObjectTypeName(computedArgs[2])) if err != nil { return nil, err } // Fill the rest data. - cla.hashType, err = ht.New(computedArgs[1]) + cla.hashType, err = ht.New(ht.HashTypeName(computedArgs[1])) if err != nil { return nil, err } @@ -63,8 +65,8 @@ func New() (cla *CommandLineArguments, err error) { // Some of the algorithms work with non-existent objects, // so sometimes absent objects are not an error. - if (cla.action.ID() == a.IdCheck) || - (cla.hashType.ID() != ht.IdFileExistence) { + if (cla.action.ID() == a.Id_Check) || + (cla.hashType.ID() != ht.Id_FileExistence) { err = ensureObjectExists(cla) if err != nil { return nil, err @@ -77,18 +79,18 @@ func New() (cla *CommandLineArguments, err error) { func ensureObjectExists(cla *CommandLineArguments) (err error) { var objectExists bool switch cla.objectType.ID() { - case ot.IdFile: + case ot.Id_File: objectExists, err = file.FileExists(cla.ObjectPath()) - case ot.IdFolder: + case ot.Id_Folder: objectExists, err = file.FolderExists(cla.ObjectPath()) default: - return fmt.Errorf(ot.ErrUnknown, cla.objectType) + return c.ErrorS1(ot.ErrUnknownObjectType, cla.objectType) } if err != nil { return err } if !objectExists { - return errors.New(ErrObjectIsNotFound) + return c.Error(ErrObjectIsNotFound) } return nil diff --git a/pkg/Models/HashSize/HashSize.go b/pkg/Models/HashSize/HashSize.go new file mode 100644 index 0000000..979ee0f --- /dev/null +++ b/pkg/Models/HashSize/HashSize.go @@ -0,0 +1,10 @@ +package hs + +type HashSize int + +const ( + HashSize_None = HashSize(0) + HashSize_CRC32 = HashSize(4) + HashSize_MD5 = HashSize(16) + HashSize_SHA256 = HashSize(32) +) diff --git a/pkg/Models/HashType/HashType.go b/pkg/Models/HashType/HashType.go index 9c3cb30..10fc58c 100644 --- a/pkg/Models/HashType/HashType.go +++ b/pkg/Models/HashType/HashType.go @@ -1,76 +1,77 @@ package ht import ( - "fmt" "strings" -) -const ( - IdCRC32 = 1 - IdMD5 = 2 - IdSHA256 = 3 - IdFileSize = 4 - IdFileExistence = 5 -) - -const ( - NameCRC32 = "CRC32" - NameMD5 = "MD5" - NameSHA256 = "SHA256" - NameFileSize = "SIZE" - NameFileExistence = "EXISTENCE" + hs "github.com/vault-thirteen/Hasher/pkg/Models/HashSize" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" ) const ( - ErrUnknown = "hash type is unknown: %v" + ErrUnknownHashType = "unknown hash type" ) type HashType struct { - id byte - name string -} - -func New(hashTypeName string) (hashType *HashType, err error) { - switch strings.ToUpper(hashTypeName) { - case NameCRC32: - return &HashType{ - id: IdCRC32, - name: NameCRC32, - }, nil + id HashTypeId + name HashTypeName - case NameMD5: - return &HashType{ - id: IdMD5, - name: NameMD5, - }, nil - - case NameSHA256: - return &HashType{ - id: IdSHA256, - name: NameSHA256, - }, nil + isBinary bool + sumSize hs.HashSize +} - case NameFileSize: - return &HashType{ - id: IdFileSize, - name: NameFileSize, - }, nil +func New(hashTypeName HashTypeName) (ht *HashType, err error) { + return NewByName(hashTypeName) +} - case NameFileExistence: - return &HashType{ - id: IdFileExistence, - name: NameFileExistence, - }, nil +func NewByName(hashTypeName HashTypeName) (ht *HashType, err error) { + x := HashTypeName(strings.ToUpper(string(hashTypeName))) + switch x { + case Name_FileExistence: + ht = &HashType{id: Id_FileExistence, name: Name_FileExistence, isBinary: false, sumSize: hs.HashSize_None} + case Name_FileSize: + ht = &HashType{id: Id_FileSize, name: Name_FileSize, isBinary: false, sumSize: hs.HashSize_None} + case Name_CRC32: + ht = &HashType{id: Id_CRC32, name: Name_CRC32, isBinary: true, sumSize: hs.HashSize_CRC32} + case Name_MD5: + ht = &HashType{id: Id_MD5, name: Name_MD5, isBinary: true, sumSize: hs.HashSize_MD5} + case Name_SHA256: + ht = &HashType{id: Id_SHA256, name: Name_SHA256, isBinary: true, sumSize: hs.HashSize_SHA256} + default: + return nil, c.ErrorS1(ErrUnknownHashType, hashTypeName) + } + return ht, nil +} +func NewById(hashTypeId HashTypeId) (ht *HashType, err error) { + switch hashTypeId { + case Id_FileExistence: + ht = &HashType{id: Id_FileExistence, name: Name_FileExistence, isBinary: false, sumSize: hs.HashSize_None} + case Id_FileSize: + ht = &HashType{id: Id_FileSize, name: Name_FileSize, isBinary: false, sumSize: hs.HashSize_None} + case Id_CRC32: + ht = &HashType{id: Id_CRC32, name: Name_CRC32, isBinary: true, sumSize: hs.HashSize_CRC32} + case Id_MD5: + ht = &HashType{id: Id_MD5, name: Name_MD5, isBinary: true, sumSize: hs.HashSize_MD5} + case Id_SHA256: + ht = &HashType{id: Id_SHA256, name: Name_SHA256, isBinary: true, sumSize: hs.HashSize_SHA256} default: - return nil, fmt.Errorf(ErrUnknown, hashTypeName) + return nil, c.ErrorA1(ErrUnknownHashType, hashTypeId) } + return ht, nil } -func (ht *HashType) ID() (id byte) { +func (ht *HashType) ID() (id HashTypeId) { return ht.id } -func (ht *HashType) Name() (name string) { +func (ht *HashType) Name() (name HashTypeName) { return ht.name } + +func (ht *HashType) IsBinary() (isBinary bool) { + return ht.isBinary +} + +func (ht *HashType) SumSize() (sumSize hs.HashSize) { + return ht.sumSize +} diff --git a/pkg/Models/HashType/HashTypeId.go b/pkg/Models/HashType/HashTypeId.go new file mode 100644 index 0000000..9df02f5 --- /dev/null +++ b/pkg/Models/HashType/HashTypeId.go @@ -0,0 +1,11 @@ +package ht + +type HashTypeId byte + +const ( + Id_FileExistence = HashTypeId(1) + Id_FileSize = HashTypeId(2) + Id_CRC32 = HashTypeId(3) + Id_MD5 = HashTypeId(4) + Id_SHA256 = HashTypeId(5) +) diff --git a/pkg/Models/HashType/HashTypeName.go b/pkg/Models/HashType/HashTypeName.go new file mode 100644 index 0000000..e223834 --- /dev/null +++ b/pkg/Models/HashType/HashTypeName.go @@ -0,0 +1,11 @@ +package ht + +type HashTypeName string + +const ( + Name_FileExistence = HashTypeName("EXISTENCE") + Name_FileSize = HashTypeName("SIZE") + Name_CRC32 = HashTypeName("CRC32") + Name_MD5 = HashTypeName("MD5") + Name_SHA256 = HashTypeName("SHA256") +) diff --git a/pkg/Models/Hashing/Hashing.go b/pkg/Models/Hashing/Hashing.go new file mode 100644 index 0000000..1f6245d --- /dev/null +++ b/pkg/Models/Hashing/Hashing.go @@ -0,0 +1,240 @@ +package h + +import ( + "encoding/hex" + "os" + "strconv" + "strings" + + ht "github.com/vault-thirteen/Hasher/pkg/Models/HashType" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" + "github.com/vault-thirteen/auxie/number" +) + +const ( + ErrDataIsDamaged = "data is damaged" +) + +type Hashing struct { + // typ is type. The word 'type' can not be used in Go language. + typ *ht.HashType +} + +func NewHashing(hti ht.HashTypeId) (h *Hashing, err error) { + h = &Hashing{} + + h.typ, err = ht.NewById(hti) + if err != nil { + return nil, err + } + + return h, nil +} + +func (h *Hashing) GetType() (ht ht.HashType) { + if h.typ == nil { + return + } + + return *(h.typ) +} + +func (h *Hashing) Calculate(file string) (result *HashingResult, err error) { + var data any + + switch h.typ.ID() { + case ht.Id_FileExistence: + data, err = checkFileExistence(file) + if err != nil { + return nil, err + } + + result, err = NewHashingResult(data, HashingResultType_Boolean) + if err != nil { + return nil, err + } + + case ht.Id_FileSize: + data, err = getFileSize(file) + if err != nil { + return nil, err + } + + result, err = NewHashingResult(data, HashingResultType_Integer) + if err != nil { + return nil, err + } + + case ht.Id_CRC32: + data, err = calculateBinaryFileHash(file, ht.Id_CRC32) + if err != nil { + return nil, err + } + + result, err = NewHashingResult(data, HashingResultType_Binary) + if err != nil { + return nil, err + } + + case ht.Id_MD5: + data, err = calculateBinaryFileHash(file, ht.Id_MD5) + if err != nil { + return nil, err + } + + result, err = NewHashingResult(data, HashingResultType_Binary) + if err != nil { + return nil, err + } + + case ht.Id_SHA256: + data, err = calculateBinaryFileHash(file, ht.Id_SHA256) + if err != nil { + return nil, err + } + + result, err = NewHashingResult(data, HashingResultType_Binary) + if err != nil { + return nil, err + } + + default: + return nil, c.Error(ht.ErrUnknownHashType) + } + + return result, nil +} + +func (h *Hashing) Verify(file string, value any) (isEqual bool, err error) { + var result *HashingResult + result, err = h.Calculate(file) + if err != nil { + return false, err + } + + return result.Compare(value) +} + +func (h *Hashing) ParseHash(hashText string) (hashValue any, err error) { + switch h.typ.ID() { + case ht.Id_FileExistence: + var x bool + x, err = strconv.ParseBool(hashText) + if err != nil { + return "", err + } + + return x, nil + + case ht.Id_FileSize: + var x int + x, err = number.ParseInt(hashText) + if err != nil { + return "", err + } + + return x, nil + + case ht.Id_CRC32: + case ht.Id_MD5: + case ht.Id_SHA256: + + default: + return nil, c.Error(ht.ErrUnknownHashType) + } + + // Binary hash sum. + var x []byte + x, err = hex.DecodeString(hashText) + if err != nil { + return "", err + } + + return x, nil +} + +// WalkerFn is a method implementing the signature of a 'walk function': +// type WalkFunc func(path string, info fs.FileInfo, err error) error +func (h *Hashing) WalkerFn(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + + if fi.IsDir() { + return nil + } + + var result *HashingResult + result, err = h.Calculate(path) + if err != nil { + return err + } + + c.PrintHashLine(result.ToString(), path) + return nil +} + +func (h *Hashing) ParseFileLine(line []byte) (hashText string, filePath string, err error) { + // Hash line starts with a hash text separated with a single space symbol: + // XXXX + if h.typ.IsBinary() { + hashTextLen := int(h.typ.SumSize()) * 2 + if len(line) < hashTextLen+2 { + return "", "", c.Error(ErrDataIsDamaged) + } + + hashText = strings.ToUpper(string(line[:hashTextLen])) + filePath = strings.TrimSpace(string(line[(hashTextLen + 1):])) + return hashText, filePath, nil + } + + var p1, p2 string + p1, p2, err = splitLine(line) + if err != nil { + return "", "", err + } + + filePath = strings.TrimSpace(p2) + + switch h.typ.ID() { + case ht.Id_FileExistence: + hashText, err = parseAndFormatBoolean(p1) + case ht.Id_FileSize: + hashText, err = parseAndFormatInteger(p1) + default: + err = c.Error(ht.ErrUnknownHashType) + } + if err != nil { + return "", "", err + } + + return hashText, filePath, nil +} + +func splitLine(line []byte) (p1, p2 string, err error) { + parts := strings.Split(string(line), " ") + if len(parts) != 2 { + return "", "", c.Error(ErrDataIsDamaged) + } + + return parts[0], parts[1], nil +} + +func parseAndFormatBoolean(in string) (out string, err error) { + var x bool + x, err = strconv.ParseBool(in) + if err != nil { + return "", err + } + + return c.FormatBooleanAsNumber(x), nil +} + +func parseAndFormatInteger(in string) (out string, err error) { + _, err = number.ParseInt(in) + if err != nil { + return "", err + } + + return in, nil +} diff --git a/pkg/Models/Hashing/HashingResult.go b/pkg/Models/Hashing/HashingResult.go new file mode 100644 index 0000000..928cfee --- /dev/null +++ b/pkg/Models/Hashing/HashingResult.go @@ -0,0 +1,94 @@ +package h + +import ( + "bytes" + "encoding/hex" + "strconv" + "strings" + + c "github.com/vault-thirteen/Hasher/pkg/Models/common" +) + +type HashingResult struct { + ResultType HashingResultType + + Binary []byte + Integer int + Boolean bool +} + +func NewHashingResult(data any, resultType HashingResultType) (hr *HashingResult, err error) { + hr = &HashingResult{ + ResultType: resultType, + } + + var ok bool + switch resultType { + case HashingResultType_Binary: + hr.Binary, ok = data.([]byte) + + case HashingResultType_Integer: + hr.Integer, ok = data.(int) + + case HashingResultType_Boolean: + hr.Boolean, ok = data.(bool) + + default: + return nil, c.Error(ErrUnknownHashingResultType) + } + if !ok { + return nil, c.Error(ErrTypeAssertion) + } + + return hr, nil +} + +func (hr *HashingResult) Compare(value any) (isEqual bool, err error) { + switch hr.ResultType { + case HashingResultType_Binary: + x, ok := value.([]byte) + if !ok { + return false, c.Error(ErrTypeAssertion) + } + + isEqual = bytes.Equal(hr.Binary, x) + return isEqual, nil + + case HashingResultType_Integer: + x, ok := value.(int) + if !ok { + return false, c.Error(ErrTypeAssertion) + } + + isEqual = (hr.Integer == x) + return isEqual, nil + + case HashingResultType_Boolean: + x, ok := value.(bool) + if !ok { + return false, c.Error(ErrTypeAssertion) + } + + isEqual = (hr.Boolean == x) + return isEqual, nil + + default: + return false, c.Error(ErrUnknownHashingResultType) + } +} + +func (hr *HashingResult) ToString() (s string) { + switch hr.ResultType { + case HashingResultType_Binary: + return strings.ToUpper(hex.EncodeToString(hr.Binary)) + + case HashingResultType_Integer: + return strconv.FormatInt(int64(hr.Integer), 10) + + case HashingResultType_Boolean: + return c.FormatBooleanAsNumber(hr.Boolean) + + default: + panic(ErrUnknownHashingResultType) + } +} diff --git a/pkg/Models/Hashing/HashingResultType.go b/pkg/Models/Hashing/HashingResultType.go new file mode 100644 index 0000000..d85a8c5 --- /dev/null +++ b/pkg/Models/Hashing/HashingResultType.go @@ -0,0 +1,14 @@ +package h + +type HashingResultType byte + +const ( + HashingResultType_Binary = HashingResultType(1) + HashingResultType_Integer = HashingResultType(2) + HashingResultType_Boolean = HashingResultType(3) +) + +const ( + ErrUnknownHashingResultType = "unknown hashing result type" + ErrTypeAssertion = "type assertion has failed" +) diff --git a/pkg/Models/Hashing/calculate.go b/pkg/Models/Hashing/calculate.go new file mode 100644 index 0000000..1b9c2de --- /dev/null +++ b/pkg/Models/Hashing/calculate.go @@ -0,0 +1,56 @@ +package h + +import ( + "os" + + ht "github.com/vault-thirteen/Hasher/pkg/Models/HashType" + af "github.com/vault-thirteen/auxie/file" + ah "github.com/vault-thirteen/auxie/hash" +) + +func calculateBinaryFileHash(filePath string, hti ht.HashTypeId) (sum []byte, err error) { + var data []byte + data, err = af.GetFileContents(filePath) + if err != nil { + return sum, err + } + + switch hti { + case ht.Id_CRC32: + x, _ := ah.CalculateCrc32(data) + sum = x[:] + + case ht.Id_MD5: + x, _ := ah.CalculateMd5(data) + sum = x[:] + + case ht.Id_SHA256: + x, _ := ah.CalculateSha256(data) + sum = x[:] + } + + return sum, nil +} + +func checkFileExistence(filePath string) (fileExists bool, err error) { + var exists bool + exists, err = af.FileExists(filePath) + if err != nil { + return false, err + } + + return exists, nil +} + +func getFileSize(filePath string) (fileSize int, err error) { + var fi os.FileInfo + fi, err = os.Stat(filePath) + if err != nil { + return 0, err + } + + x := fi.Size() + fileSize = int(x) + + return fileSize, nil +} diff --git a/pkg/Models/ObjectType/ObjectType.go b/pkg/Models/ObjectType/ObjectType.go index a295735..6b38247 100644 --- a/pkg/Models/ObjectType/ObjectType.go +++ b/pkg/Models/ObjectType/ObjectType.go @@ -1,59 +1,43 @@ package ot import ( - "fmt" "strings" -) - -const ( - IdFile = 1 - IdFolder = 2 -) -const ( - NameFile = "FILE" - NameFolder = "FOLDER" - NameDirectory = "DIRECTORY" + c "github.com/vault-thirteen/Hasher/pkg/Models/common" ) const ( - ErrUnknown = "object type is unknown: %v" + ErrUnknownObjectType = "unknown object type" ) type ObjectType struct { - id byte - name string + id ObjectTypeId + name ObjectTypeName } -func New(objectTypeName string) (objectType *ObjectType, err error) { - switch strings.ToUpper(objectTypeName) { - case NameFile: - return &ObjectType{ - id: IdFile, - name: NameFile, - }, nil - - case NameFolder: - return &ObjectType{ - id: IdFolder, - name: NameFolder, - }, nil - - case NameDirectory: - return &ObjectType{ - id: IdFolder, - name: NameFolder, - }, nil +func New(objectTypeName ObjectTypeName) (ot *ObjectType, err error) { + return NewByName(objectTypeName) +} +func NewByName(objectTypeName ObjectTypeName) (ot *ObjectType, err error) { + x := ObjectTypeName(strings.ToUpper(string(objectTypeName))) + switch x { + case Name_File: + ot = &ObjectType{id: Id_File, name: Name_File} + case Name_Folder: + ot = &ObjectType{id: Id_Folder, name: Name_Folder} + case Name_Directory: + ot = &ObjectType{id: Id_Folder, name: Name_Folder} default: - return nil, fmt.Errorf(ErrUnknown, objectTypeName) + return nil, c.ErrorS1(ErrUnknownObjectType, objectTypeName) } + return ot, nil } -func (ot *ObjectType) ID() (id byte) { +func (ot *ObjectType) ID() (id ObjectTypeId) { return ot.id } -func (ot *ObjectType) Name() (name string) { +func (ot *ObjectType) Name() (name ObjectTypeName) { return ot.name } diff --git a/pkg/Models/ObjectType/ObjectTypeId.go b/pkg/Models/ObjectType/ObjectTypeId.go new file mode 100644 index 0000000..80d86aa --- /dev/null +++ b/pkg/Models/ObjectType/ObjectTypeId.go @@ -0,0 +1,8 @@ +package ot + +type ObjectTypeId byte + +const ( + Id_File = ObjectTypeId(1) + Id_Folder = ObjectTypeId(2) +) diff --git a/pkg/Models/ObjectType/ObjectTypeName.go b/pkg/Models/ObjectType/ObjectTypeName.go new file mode 100644 index 0000000..9bb3497 --- /dev/null +++ b/pkg/Models/ObjectType/ObjectTypeName.go @@ -0,0 +1,9 @@ +package ot + +type ObjectTypeName string + +const ( + Name_File = ObjectTypeName("FILE") + Name_Folder = ObjectTypeName("FOLDER") + Name_Directory = ObjectTypeName("DIRECTORY") +) diff --git a/pkg/Models/common/error.go b/pkg/Models/common/error.go new file mode 100644 index 0000000..b3d4821 --- /dev/null +++ b/pkg/Models/common/error.go @@ -0,0 +1,50 @@ +package common + +import ( + "errors" + "fmt" +) + +// Go language is very lame. Methods for errors are placed in different +// packages making the process of error creation very boring. These functions +// try to make this process a little bit easier. + +// Placeholders. +const ( + FmtPlaceHolder_String = "%s" + FmtPlaceHolder_Any = "%v" +) + +// Separators. +const ( + FmtErrorSeparatorA = ": " + FmtErrorSeparatorB = "; " +) + +// FmtErrorExtender_S1 is an addition to an error message for showing a single +// textual value after the message. +const FmtErrorExtender_S1 = FmtErrorSeparatorA + FmtPlaceHolder_String + +// FmtErrorExtender_S2 is an addition to an error message for showing two +// textual values after the message. +const FmtErrorExtender_S2 = FmtErrorSeparatorA + FmtPlaceHolder_String + FmtErrorSeparatorB + FmtPlaceHolder_String + +// FmtErrorExtender_A1 is an addition to an error message for showing a single +// value (of any type) after the message. +const FmtErrorExtender_A1 = FmtErrorSeparatorA + FmtPlaceHolder_Any + +func Error(errMsg string) error { + return errors.New(errMsg) +} + +func ErrorS1(errMsg string, strValue any) error { + return fmt.Errorf(errMsg+FmtErrorExtender_S1, strValue) +} + +func ErrorS2(errMsg string, strValue1, strValue2 any) error { + return fmt.Errorf(errMsg+FmtErrorExtender_S2, strValue1, strValue2) +} + +func ErrorA1(errMsg string, anyValue any) error { + return fmt.Errorf(errMsg+FmtErrorExtender_A1, anyValue) +} diff --git a/pkg/Models/common/format.go b/pkg/Models/common/format.go new file mode 100644 index 0000000..c6161fa --- /dev/null +++ b/pkg/Models/common/format.go @@ -0,0 +1,19 @@ +package common + +import "fmt" + +const ( + OutputFormat = "%s %s\r\n" // [1]=Sum, [2]=ObjectName. +) + +func FormatBooleanAsNumber(b bool) string { + if b == true { + return "1" + } else { + return "0" + } +} + +func PrintHashLine(hashSumText string, fileRelPath string) { + fmt.Printf(OutputFormat, hashSumText, fileRelPath) +} diff --git a/pkg/hash/hash.go b/pkg/hash/hash.go deleted file mode 100644 index 9cd92a3..0000000 --- a/pkg/hash/hash.go +++ /dev/null @@ -1,165 +0,0 @@ -package hash - -import ( - "crypto/md5" - "crypto/sha256" - "hash/crc32" - "io" - "os" - - ae "github.com/vault-thirteen/auxie/errors" - "github.com/vault-thirteen/auxie/file" -) - -const ( - ReadBufferSize = 1_048_576 // 1 MiB. -) - -func GetFileHashCRC32(filePath string) (sum uint32, err error) { - var f *os.File - f, err = os.Open(filePath) - if err != nil { - return sum, err - } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - h := crc32.New(crc32.IEEETable) - - var n int - var buf = make([]byte, ReadBufferSize) - var readErr, writeErr error - - for { - n, readErr = f.Read(buf) - if readErr == nil { - _, writeErr = h.Write(buf[:n]) - if writeErr != nil { - return sum, writeErr - } - continue - } - - if readErr == io.EOF { - _, writeErr = h.Write(buf[:n]) - if writeErr != nil { - return sum, writeErr - } - break - } - - return sum, readErr - } - - return h.Sum32(), nil -} - -func GetFileHashMD5(filePath string) (sum []byte, err error) { - var f *os.File - f, err = os.Open(filePath) - if err != nil { - return sum, err - } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - h := md5.New() - - var n int - var buf = make([]byte, ReadBufferSize) - var readErr, writeErr error - - for { - n, readErr = f.Read(buf) - if readErr == nil { - _, writeErr = h.Write(buf[:n]) - if writeErr != nil { - return sum, writeErr - } - continue - } - - if readErr == io.EOF { - _, writeErr = h.Write(buf[:n]) - if writeErr != nil { - return sum, writeErr - } - break - } - - return sum, readErr - } - - return h.Sum(nil), nil -} - -func GetFileHashSHA256(filePath string) (sum []byte, err error) { - var f *os.File - f, err = os.Open(filePath) - if err != nil { - return sum, err - } - defer func() { - derr := f.Close() - if derr != nil { - err = ae.Combine(err, derr) - } - }() - - h := sha256.New() - - var n int - var buf = make([]byte, ReadBufferSize) - var readErr, writeErr error - - for { - n, readErr = f.Read(buf) - if readErr == nil { - _, writeErr = h.Write(buf[:n]) - if writeErr != nil { - return sum, writeErr - } - continue - } - - if readErr == io.EOF { - _, writeErr = h.Write(buf[:n]) - if writeErr != nil { - return sum, writeErr - } - break - } - - return sum, readErr - } - - return h.Sum(nil), nil -} - -func GetFileHashFileSize(filePath string) (sum int64, err error) { - var fi os.FileInfo - fi, err = os.Stat(filePath) - if err != nil { - return sum, err - } - - return fi.Size(), nil -} - -func GetFileHashFileExistence(filePath string) (sum bool, err error) { - var exists bool - exists, err = file.FileExists(filePath) - if err != nil { - return false, err - } - - return exists, nil -} diff --git a/pkg/strconv/bool.go b/pkg/strconv/bool.go deleted file mode 100644 index c1afb7b..0000000 --- a/pkg/strconv/bool.go +++ /dev/null @@ -1,9 +0,0 @@ -package strconv - -func FormatBooleanAsNumber(b bool) string { - if b == true { - return "1" - } else { - return "0" - } -} diff --git a/test/1.txt b/test/1.txt deleted file mode 100644 index 7c4a013..0000000 --- a/test/1.txt +++ /dev/null @@ -1 +0,0 @@ -aaa \ No newline at end of file diff --git a/test/2.txt b/test/2.txt deleted file mode 100644 index 71165b0..0000000 --- a/test/2.txt +++ /dev/null @@ -1 +0,0 @@ -bbbbb \ No newline at end of file diff --git a/test/3.txt b/test/3.txt deleted file mode 100644 index 26ca48f..0000000 --- a/test/3.txt +++ /dev/null @@ -1 +0,0 @@ -ccccccc \ No newline at end of file diff --git a/test/e.txt b/test/e.txt deleted file mode 100644 index 0841baf..0000000 --- a/test/e.txt +++ /dev/null @@ -1,7 +0,0 @@ -1 1.txt -1 2.txt -1 3.txt -1 fake.txt -0 5.txt -0 6.txt -0 7.txt