// FoldFile folds child snapshot data into its parent func FoldFile(childFileName, parentFileName string) error { childFInfo, err := os.Stat(childFileName) if err != nil { panic("os.Stat(childFileName) failed, error: " + err.Error()) } parentFInfo, err := os.Stat(parentFileName) if err != nil { panic("os.Stat(parentFileName) failed, error: " + err.Error()) } // ensure no directory if childFInfo.IsDir() || parentFInfo.IsDir() { panic("at least one file is directory, not a normal file") } // ensure file sizes are equal if childFInfo.Size() != parentFInfo.Size() { panic("file sizes are not equal") } // open child and parent files childFile, err := fio.OpenFile(childFileName, os.O_RDONLY, 0) if err != nil { panic("Failed to open childFile, error: " + err.Error()) } defer childFile.Close() parentFile, err := fio.OpenFile(parentFileName, os.O_WRONLY, 0) if err != nil { panic("Failed to open parentFile, error: " + err.Error()) } defer parentFile.Close() return coalesce(parentFile, childFile) }
func syncFile(localPath string, addr TCPEndPoint, remotePath string, timeout int, retry bool) ([]byte, error) { file, err := fio.OpenFile(localPath, os.O_RDONLY, 0) if err != nil { log.Error("Failed to open local source file:", localPath) return nil, err } defer file.Close() size, err := file.Seek(0, os.SEEK_END) if err != nil { log.Error("Failed to get size of local source file:", localPath, err) return nil, err } SetupFileIO(size%Blocks == 0) conn := connect(addr.Host, strconv.Itoa(int(addr.Port)), timeout) if nil == conn { err = fmt.Errorf("Failed to connect to %v", addr) log.Error(err) return nil, err } defer conn.Close() encoder := gob.NewEncoder(conn) decoder := gob.NewDecoder(conn) // Use unix time as hash salt salt := make([]byte, binary.MaxVarintLen64) binary.PutVarint(salt, time.Now().UnixNano()) status := sendSyncRequest(encoder, decoder, remotePath, size, salt) if !status { err = fmt.Errorf("Sync request to %v failed", remotePath) log.Error(err) return nil, err } abortStream := make(chan error) layoutStream := make(chan FileInterval, 128) errStream := make(chan error) // Initiate interval loading... err = loadFileLayout(abortStream, file, layoutStream, errStream) if err != nil { log.Error("Failed to retrieve local file layout:", err) return nil, err } fileStream := make(chan FileInterval, 128) unorderedStream := make(chan HashedDataInterval, 128) orderedStream := make(chan HashedDataInterval, 128) go IntervalSplitter(layoutStream, fileStream) FileReaderGroup(fileReaders, salt, fileStream, localPath, unorderedStream) go OrderIntervals("src:", unorderedStream, orderedStream) // Get remote file intervals and their hashes netInStream := make(chan HashedInterval, 128) netInStreamDone := make(chan bool) go netDstReceiver(decoder, netInStream, netInStreamDone) return processDiff(salt, abortStream, errStream, encoder, decoder, orderedStream, netInStream, netInStreamDone, retry) }