Skip to content

Commit 6b334e4

Browse files
authored
feat: v2 (#2)
* feat: v2 * chore: use package replace it * fix: fix xml bug * fix: fix hash check * fix: fix path & workdir * fix: base dir & file
1 parent 6ae9cc7 commit 6b334e4

File tree

17 files changed

+457
-1192
lines changed

17 files changed

+457
-1192
lines changed

README.md

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1-
# kcheck
1+
# KCheck
22

3-
Check K files from Hash
3+
Check K files from hash
44

5-
## Structure
5+
## 📄 Supported format
66

7-
make `all.list`
8-
```
9-
da1bc727b3cee04420068c445c77fead boot.exe
10-
24b4c28d9cb55917256bf95bb0a7926d config.exe
11-
....
12-
```
13-
or
7+
- KCheck
8+
- metadata
9+
- filepath
10+
11+
## 📝 KCheck format
12+
13+
### example
14+
make `kcheck.list`
1415
```
15-
da1bc727b3cee04420068c445c77fead D:\boot.exe
16-
24b4c28d9cb55917256bf95bb0a7926d D:\config.exe
17-
....
16+
{
17+
"createdAt": 1619071970000,
18+
"files": [
19+
{
20+
"path": "/foo/bar/baz.png",
21+
"sha1": "1a2b3c4d5e1a2b3c4d5e1a2b3c4d5e1a2b3c4d5e",
22+
"size": 12345
23+
}
24+
...
25+
]
26+
}
1827
```
19-
If check fail,it will be make `failed.list` automatically
28+
## ⤴️ Output
29+
If some files got failed, a `failed.list` file will be generated automatically
30+
31+
## License
32+
33+
GPLv3
34+
35+
PR Welcome

cmd/kcheck/handler.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"log"
7+
"os"
8+
)
9+
10+
type CheckResult struct {
11+
Success bool
12+
Error error
13+
Path string
14+
}
15+
16+
func handler(res chan *CheckResult) {
17+
file, err := os.OpenFile("failed.list", os.O_APPEND|os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
18+
if err != nil {
19+
log.Fatalf("failed creating result log: %s", err)
20+
}
21+
dataWriter := bufio.NewWriter(file)
22+
for r := range res {
23+
_, _ = dataWriter.WriteString(fmt.Sprintf("[%s]: %s\n", r.Error, r.Path))
24+
dataWriter.Flush()
25+
}
26+
file.Close()
27+
}

cmd/kcheck/judge.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"encoding/binary"
6+
"github.com/littlecxm/kcheck/configs"
7+
"io/ioutil"
8+
"log"
9+
"os"
10+
"path/filepath"
11+
"strings"
12+
)
13+
14+
// guessListPath get the relative path of the list file
15+
func guessListPath() string {
16+
allLstDefaultPath := "allfiles.lst"
17+
metaDefaultPath := filepath.Join("data", "__metadata.metatxt")
18+
kbinDefaultPath := filepath.Join("prop", "filepath.xml")
19+
if _, err := os.Stat(allLstDefaultPath); err == nil {
20+
log.Println("use default allfiles list:", allLstDefaultPath)
21+
return allLstDefaultPath
22+
}
23+
if _, err := os.Stat(metaDefaultPath); err == nil {
24+
log.Println("use default metadata list:", metaDefaultPath)
25+
return metaDefaultPath
26+
}
27+
if _, err := os.Stat(kbinDefaultPath); err == nil {
28+
log.Println("use default filepath list:", kbinDefaultPath)
29+
return kbinDefaultPath
30+
}
31+
return ""
32+
}
33+
34+
func guessType() (string, error) {
35+
file, err := os.Open(filepath.Join(configs.WorkDir, listPath))
36+
bufr := bufio.NewReader(file)
37+
// kbin
38+
magicNumber := make([]byte, 2)
39+
_, err = bufr.Read(magicNumber)
40+
if err != nil {
41+
return "", err
42+
}
43+
if binary.BigEndian.Uint16(magicNumber) == configs.KBinMagicNumber {
44+
return configs.KBinType, nil
45+
}
46+
// ioutil
47+
bf, err := ioutil.ReadFile(listPath)
48+
if err != nil {
49+
return "", err
50+
}
51+
if strings.Contains(string(bf), "<?xml version") {
52+
return configs.XMLType, nil
53+
}
54+
if strings.Contains(string(bf), "createdAt") {
55+
return configs.MetadataType, nil
56+
}
57+
log.Println("unknown file type, use default:", configs.KCheckType)
58+
return configs.KCheckType, nil
59+
}

cmd/kcheck/main.go

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package main
2+
3+
import (
4+
"crypto/md5"
5+
"crypto/sha1"
6+
"fmt"
7+
"github.com/beevik/etree"
8+
"github.com/fatih/color"
9+
jsoniter "github.com/json-iterator/go"
10+
"github.com/littlecxm/kbinxml-go"
11+
"github.com/littlecxm/kcheck/configs"
12+
"github.com/littlecxm/kcheck/pkg/checksum"
13+
"github.com/urfave/cli/v2"
14+
"io/ioutil"
15+
"log"
16+
"os"
17+
"path/filepath"
18+
"sort"
19+
"strings"
20+
"time"
21+
)
22+
23+
var json = jsoniter.ConfigCompatibleWithStandardLibrary
24+
var (
25+
workDir string
26+
version, buildDate, commitID string
27+
listType, listPath string
28+
)
29+
30+
func main() {
31+
fmt.Printf("kcheck %s\n", version)
32+
configs.WorkDir, _ = os.Getwd()
33+
app := &cli.App{
34+
Name: "kcheck",
35+
Usage: "check files through list",
36+
Version: fmt.Sprintf("%s (built: %s)", commitID, buildDate),
37+
Flags: []cli.Flag{
38+
&cli.StringFlag{
39+
Name: "type",
40+
Aliases: []string{"t"},
41+
Usage: "input list `TYPE`, support: `kbin`,`xml`,`metadata`,`kcheck`",
42+
Destination: &listType,
43+
},
44+
},
45+
Action: func(c *cli.Context) error {
46+
if c.NArg() == 0 {
47+
listPath = guessListPath()
48+
if listPath == "" {
49+
fmt.Println("failed to guess input list, please specify the path")
50+
fmt.Fprintln(color.Output, "use",
51+
color.GreenString("help"),
52+
"to get more info",
53+
)
54+
os.Exit(-1)
55+
}
56+
}
57+
if c.NArg() > 0 {
58+
manualPath := c.Args().Get(0)
59+
listPath = filepath.Base(manualPath)
60+
configs.WorkDir = filepath.Dir(manualPath)
61+
}
62+
log.Println("current work dir:", configs.WorkDir)
63+
log.Println("list path:", listPath)
64+
65+
f, err := os.Open(filepath.Join(configs.WorkDir, listPath))
66+
inByte, err := ioutil.ReadAll(f)
67+
if err != nil {
68+
log.Fatalf("load file error: %s", err)
69+
}
70+
if listType == "" {
71+
listType, err = guessType()
72+
if err != nil {
73+
log.Fatalf("get list type error: %s", err)
74+
}
75+
}
76+
77+
// report handler
78+
res := make(chan *CheckResult, 999)
79+
go handler(res)
80+
var fCount, passCount, failCount = 0, 0, 0
81+
switch listType {
82+
case configs.KBinType:
83+
kxml, _, err := kbinxml.DeserializeKbin(inByte)
84+
if err != nil {
85+
log.Fatalf("cannot unmarshal kbin: %s", err)
86+
}
87+
inByte = kxml
88+
fallthrough
89+
case configs.XMLType:
90+
doc := etree.NewDocument()
91+
if err := doc.ReadFromBytes(inByte); err != nil {
92+
log.Fatal("load xml list err:", err)
93+
}
94+
// check
95+
listNode := doc.FindElement("list")
96+
fCount = len(listNode.ChildElements())
97+
for _, fNode := range listNode.SelectElements("file") {
98+
dstPath := fNode.SelectElement("dst_path").Text()
99+
dstMd5 := fNode.SelectElement("dst_md5").Text()
100+
formatPath := strings.TrimPrefix(filepath.FromSlash(dstPath), string(os.PathSeparator))
101+
if err := checksum.CheckByHash(formatPath, dstMd5, md5.New()); err != nil {
102+
failCount++
103+
res <- &CheckResult{
104+
false,
105+
err,
106+
formatPath,
107+
}
108+
printStatus(false, formatPath)
109+
} else {
110+
passCount++
111+
printStatus(true, formatPath)
112+
}
113+
}
114+
close(res)
115+
case configs.MetadataType:
116+
var metaStruct configs.MetaData
117+
err = json.Unmarshal(inByte, &metaStruct)
118+
if err != nil {
119+
log.Fatal("load metadata list err:", err)
120+
}
121+
metaCreateAt := time.Unix(0, metaStruct.CreatedAt*int64(time.Millisecond))
122+
fCount = len(metaStruct.Files)
123+
log.Println("metadata created at:", metaCreateAt)
124+
for _, files := range metaStruct.Files {
125+
var (
126+
fileSHA1 = files.SHA1
127+
filePath = files.Path
128+
)
129+
if fileSHA1 == "" {
130+
fileSHA1 = files.SSHA1
131+
}
132+
if filePath == "" {
133+
filePath = files.SPath
134+
}
135+
formatPath := filepath.Join(
136+
"data",
137+
strings.TrimPrefix(filepath.FromSlash(filePath), string(os.PathSeparator)),
138+
)
139+
if err := checksum.CheckByHash(formatPath, fileSHA1, sha1.New()); err != nil {
140+
failCount++
141+
res <- &CheckResult{
142+
false,
143+
err,
144+
formatPath,
145+
}
146+
printStatus(false, formatPath)
147+
} else {
148+
passCount++
149+
printStatus(true, formatPath)
150+
}
151+
}
152+
case configs.KCheckType:
153+
var kcheckList configs.KCheckList
154+
err = json.Unmarshal(inByte, &kcheckList)
155+
if err != nil {
156+
log.Fatal("load KCheck list err:", err)
157+
}
158+
metaCreateAt := time.Unix(0, kcheckList.CreatedAt*int64(time.Millisecond))
159+
fCount = len(kcheckList.Files)
160+
fmt.Println("KCheck list created at:", metaCreateAt)
161+
for _, files := range kcheckList.Files {
162+
formatPath := strings.TrimPrefix(filepath.FromSlash(files.Path), string(os.PathSeparator))
163+
if err := checksum.CheckByHash(formatPath, files.SHA1, sha1.New()); err != nil {
164+
failCount++
165+
res <- &CheckResult{
166+
false,
167+
err,
168+
formatPath,
169+
}
170+
printStatus(false, formatPath)
171+
} else {
172+
passCount++
173+
printStatus(true, formatPath)
174+
}
175+
}
176+
default:
177+
log.Fatalf("unknown type: %s", listType)
178+
}
179+
fmt.Println("Finished.")
180+
fmt.Println("ALL:", fCount, "/", "PASS:", passCount, "/", "FAIL:", failCount)
181+
fmt.Println("Exit after 5 seconds...")
182+
time.Sleep(5 * time.Second)
183+
return nil
184+
},
185+
}
186+
187+
sort.Sort(cli.FlagsByName(app.Flags))
188+
sort.Sort(cli.CommandsByName(app.Commands))
189+
190+
err := app.Run(os.Args)
191+
if err != nil {
192+
log.Println(err)
193+
os.Exit(1)
194+
}
195+
}
196+
197+
func printStatus(isSuccess bool, path string) {
198+
successDisp := color.New(color.Bold, color.FgWhite, color.BgGreen).FprintfFunc()
199+
failedDisp := color.New(color.Bold, color.FgWhite, color.BgRed).FprintfFunc()
200+
if isSuccess {
201+
successDisp(color.Output, "[PASSED]")
202+
} else {
203+
failedDisp(color.Output, "[FAILED]")
204+
}
205+
fmt.Println(" ", path)
206+
}

cmd/makechk/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package makechk

configs/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package configs
2+
3+
var WorkDir string
4+
5+
const KBinMagicNumber = 0xa042
6+
const KBinType = "kbin"
7+
const XMLType = "xml"
8+
const KCheckType = "kcheck"
9+
const MetadataType = "metadata"

kstruct/metajson.go renamed to configs/type.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package kstruct
1+
package configs
22

33
type MetaData struct {
44
CreatedAt int64 `json:"createdAt"`
@@ -18,3 +18,11 @@ type MetaData struct {
1818
} `json:"files"`
1919
}
2020

21+
type KCheckList struct {
22+
CreatedAt int64 `json:"createdAt"`
23+
Files []struct {
24+
Path string `json:"path"`
25+
SHA1 string `json:"sha1"`
26+
Size int64 `json:"size"`
27+
} `json:"files"`
28+
}

go.mod

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ go 1.14
44

55
require (
66
github.com/beevik/etree v1.1.0
7-
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e
8-
golang.org/x/net v0.0.0-20200513185701-a91f0712d120
9-
golang.org/x/text v0.3.0
7+
github.com/fatih/color v1.13.0
8+
github.com/json-iterator/go v1.1.12
9+
github.com/littlecxm/kbinxml-go v1.0.0
10+
github.com/urfave/cli/v2 v2.6.0
1011
)

0 commit comments

Comments
 (0)