Example #1
0
func (plan *PatchPlan) appendFilePlan(srcFile *fs.File, dstPath string) error {
	match, err := MatchIndex(plan.srcStore.Index(), plan.dstStore.Resolve(dstPath))
	if match == nil {
		return err
	}
	match.SrcSize = srcFile.Size

	// Create a local temporary file in which to effect changes
	localTemp := &LocalTemp{
		Path: &LocalPath{
			LocalStore: plan.dstStore,
			RelPath:    dstPath},
		Size: match.SrcSize}
	plan.Cmds = append(plan.Cmds, localTemp)

	for _, blockMatch := range match.BlockMatches {
		plan.Cmds = append(plan.Cmds, &LocalTempCopy{
			Temp:        localTemp,
			LocalOffset: blockMatch.SrcBlock.Offset(),
			TempOffset:  blockMatch.DstOffset,
			Length:      int64(fs.BLOCKSIZE)})
	}

	for _, srcRange := range match.NotMatched() {
		plan.Cmds = append(plan.Cmds, &SrcTempCopy{
			Temp:       localTemp,
			SrcStrong:  srcFile.Strong(),
			SrcOffset:  srcRange.From,
			TempOffset: srcRange.From,
			Length:     srcRange.To - srcRange.From})
	}

	// Replace dst file with temp
	plan.Cmds = append(plan.Cmds, &ReplaceWithTemp{Temp: localTemp})

	return nil
}
Example #2
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
}