github.com/qjfoidnh/BaiduPCS-Go@v0.0.0-20231011165705-caa18a3765f3/pcsutil/checksum/checksum.go (about) 1 // Package checksum 校验本地文件包 2 package checksum 3 4 import ( 5 "crypto/md5" 6 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/cachepool" 7 "github.com/qjfoidnh/BaiduPCS-Go/pcsutil/converter" 8 "hash/crc32" 9 "io" 10 "os" 11 ) 12 13 const ( 14 // DefaultBufSize 默认的bufSize 15 DefaultBufSize = int(256 * converter.KB) 16 ) 17 18 const ( 19 // CHECKSUM_MD5 获取文件的 md5 值 20 CHECKSUM_MD5 int = 1 << iota 21 // CHECKSUM_SLICE_MD5 获取文件前 sliceSize 切片的 md5 值 22 CHECKSUM_SLICE_MD5 23 // CHECKSUM_CRC32 获取文件的 crc32 值 24 CHECKSUM_CRC32 25 ) 26 27 type ( 28 // LocalFileMeta 本地文件元信息 29 LocalFileMeta struct { 30 Path string `json:"path"` // 本地路径 31 Length int64 `json:"length"` // 文件大小 32 SliceMD5 []byte `json:"slicemd5"` // 文件前 requiredSliceLen (256KB) 切片的 md5 值 33 MD5 []byte `json:"md5"` // 文件的 md5 34 CRC32 uint32 `json:"crc32"` // 文件的 crc32 35 ModTime int64 `json:"modtime"` // 修改日期 36 } 37 38 // LocalFileChecksum 校验本地文件 39 LocalFileChecksum struct { 40 LocalFileMeta 41 bufSize int 42 sliceSize int 43 buf []byte 44 file *os.File // 文件 45 } 46 ) 47 48 func NewLocalFileChecksum(localPath string, sliceSize int) *LocalFileChecksum { 49 return NewLocalFileChecksumWithBufSize(localPath, DefaultBufSize, sliceSize) 50 } 51 52 func NewLocalFileChecksumWithBufSize(localPath string, bufSize, sliceSize int) *LocalFileChecksum { 53 return &LocalFileChecksum{ 54 LocalFileMeta: LocalFileMeta{ 55 Path: localPath, 56 }, 57 bufSize: bufSize, 58 sliceSize: sliceSize, 59 } 60 } 61 62 // OpenPath 检查文件状态并获取文件的大小 (Length) 63 func (lfc *LocalFileChecksum) OpenPath() error { 64 if lfc.file != nil { 65 lfc.file.Close() 66 } 67 68 var err error 69 lfc.file, err = os.Open(lfc.Path) 70 if err != nil { 71 return err 72 } 73 74 info, err := lfc.file.Stat() 75 if err != nil { 76 return err 77 } 78 79 lfc.Length = info.Size() 80 lfc.ModTime = info.ModTime().Unix() 81 return nil 82 } 83 84 // GetFile 获取文件 85 func (lfc *LocalFileChecksum) GetFile() *os.File { 86 return lfc.file 87 } 88 89 // Close 关闭文件 90 func (lfc *LocalFileChecksum) Close() error { 91 if lfc.file == nil { 92 return ErrFileIsNil 93 } 94 95 return lfc.file.Close() 96 } 97 98 func (lfc *LocalFileChecksum) initBuf() { 99 if lfc.buf == nil { 100 lfc.buf = cachepool.RawMallocByteSlice(lfc.bufSize) 101 } 102 } 103 104 func (lfc *LocalFileChecksum) writeChecksum(data []byte, wus ...*ChecksumWriteUnit) (err error) { 105 doneCount := 0 106 for _, wu := range wus { 107 _, err := wu.Write(data) 108 switch err { 109 case ErrChecksumWriteStop: 110 doneCount++ 111 continue 112 case nil: 113 default: 114 return err 115 } 116 } 117 if doneCount == len(wus) { 118 return ErrChecksumWriteAllStop 119 } 120 return nil 121 } 122 123 func (lfc *LocalFileChecksum) GetSliceDataContent(offset, length int64) (dataContent []byte, readLength int64, err error) { 124 dataContent = make([]byte, length) 125 ret, err := lfc.file.ReadAt(dataContent, offset) 126 if err != nil && err != io.EOF { 127 return 128 } 129 readLength = int64(ret) 130 dataContent = dataContent[:ret] 131 return dataContent, readLength, nil 132 } 133 134 func (lfc *LocalFileChecksum) repeatRead(wus ...*ChecksumWriteUnit) (err error) { 135 if lfc.file == nil { 136 return ErrFileIsNil 137 } 138 139 lfc.initBuf() 140 141 defer func() { 142 _, err = lfc.file.Seek(0, os.SEEK_SET) // 恢复文件指针 143 if err != nil { 144 return 145 } 146 }() 147 148 // 读文件 149 var ( 150 n int 151 ) 152 read: 153 for { 154 n, err = lfc.file.Read(lfc.buf) 155 switch err { 156 case io.EOF: 157 err = lfc.writeChecksum(lfc.buf[:n], wus...) 158 break read 159 case nil: 160 err = lfc.writeChecksum(lfc.buf[:n], wus...) 161 default: 162 return 163 } 164 } 165 switch err { 166 case ErrChecksumWriteAllStop: // 全部结束 167 err = nil 168 } 169 return 170 } 171 172 func (lfc *LocalFileChecksum) createChecksumWriteUnit(cw ChecksumWriter, isAll, isSlice bool, getSumFunc func(sliceSum interface{}, sum interface{})) (wu *ChecksumWriteUnit, deferFunc func(err error)) { 173 wu = &ChecksumWriteUnit{ 174 ChecksumWriter: cw, 175 End: lfc.LocalFileMeta.Length, 176 OnlySliceSum: !isAll, 177 } 178 179 if isSlice { 180 wu.SliceEnd = int64(lfc.sliceSize) 181 } 182 183 return wu, func(err error) { 184 if err != nil { 185 return 186 } 187 getSumFunc(wu.SliceSum, wu.Sum) 188 } 189 } 190 191 // Sum 计算文件摘要值 192 func (lfc *LocalFileChecksum) Sum(checkSumFlag int) (err error) { 193 lfc.fix() 194 wus := make([]*ChecksumWriteUnit, 0, 2) 195 if (checkSumFlag & (CHECKSUM_MD5 | CHECKSUM_SLICE_MD5)) != 0 { 196 md5w := md5.New() 197 wu, d := lfc.createChecksumWriteUnit( 198 NewHashChecksumWriter(md5w), 199 (checkSumFlag&CHECKSUM_MD5) != 0, 200 (checkSumFlag&CHECKSUM_SLICE_MD5) != 0, 201 func(sliceSum interface{}, sum interface{}) { 202 if sliceSum != nil { 203 lfc.SliceMD5 = sliceSum.([]byte) 204 } 205 if sum != nil { 206 lfc.MD5 = sum.([]byte) 207 } 208 }, 209 ) 210 211 wus = append(wus, wu) 212 defer d(err) 213 } 214 if (checkSumFlag & CHECKSUM_CRC32) != 0 { 215 crc32w := crc32.NewIEEE() 216 wu, d := lfc.createChecksumWriteUnit( 217 NewHash32ChecksumWriter(crc32w), 218 true, 219 false, 220 func(sliceSum interface{}, sum interface{}) { 221 if sum != nil { 222 lfc.CRC32 = sum.(uint32) 223 } 224 }, 225 ) 226 227 wus = append(wus, wu) 228 defer d(err) 229 } 230 231 err = lfc.repeatRead(wus...) 232 return 233 } 234 235 func (lfc *LocalFileChecksum) fix() { 236 if lfc.sliceSize <= 0 { 237 lfc.sliceSize = DefaultBufSize 238 } 239 if lfc.bufSize < DefaultBufSize { 240 lfc.bufSize = DefaultBufSize 241 } 242 }