Exemple #1
0
func MatchFile(srcFile fs.File, dst string) (match *FileMatch, err os.Error) {
	match = &FileMatch{SrcSize: srcFile.Info().Size}
	var dstOffset int64

	dstF, err := os.Open(dst)
	if dstF == nil {
		return nil, err
	}
	defer dstF.Close()

	if dstInfo, err := dstF.Stat(); dstInfo == nil {
		return nil, err
	} else if !dstInfo.IsRegular() {
		return nil, os.NewError(fmt.Sprintf("%s: not a regular file", dst))
	} else {
		match.DstSize = dstInfo.Size
	}

	dstWeak := new(fs.WeakChecksum)
	var buf [fs.BLOCKSIZE]byte
	var sbuf [1]byte
	var window []byte

	// Scan a block,
	// then roll checksum a byte at a time until match or eof
	// repeat above until eof
SCAN:
	for {
		switch rd, err := dstF.Read(buf[:]); true {
		case rd < 0:
			return nil, err

		case rd == 0:
			break SCAN

		case rd > 0:
			blocksize := rd
			dstOffset += int64(rd)
			window = buf[:rd]

			dstWeak.Reset()
			dstWeak.Write(window[:])

			for {
				// Check for a weak checksum match
				if matchBlock, has := srcFile.Repo().WeakBlock(dstWeak.Get()); has {

					// Double-check with the strong checksum
					if fs.StrongChecksum(window[:blocksize]) == matchBlock.Info().Strong {

						// We've got a block match in dest
						match.BlockMatches = append(match.BlockMatches, &BlockMatch{
							SrcBlock:  matchBlock,
							DstOffset: dstOffset - int64(blocksize)})
						break
					}
				}

				// Read the next byte
				switch srd, err := dstF.Read(sbuf[:]); true {
				case srd < 0:
					return nil, err

				case srd == 0:
					break SCAN

				case srd == 1:
					dstOffset++

					// Roll the weak checksum & the buffer
					dstWeak.Roll(window[0], sbuf[0])
					window = append(window[1:], sbuf[0])
					break

				case srd > 1:
					return nil, os.NewError("Internal read error trying advance one byte.")
				}
			}
		}
	}

	return match, nil
}