func coalesce(parentFile *os.File, childFile *os.File) error { blockSize, err := getFileSystemBlockSize(childFile) if err != nil { panic("can't get FS block size, error: " + err.Error()) } var data, hole int64 for { data, err = syscall.Seek(int(childFile.Fd()), hole, seekData) if err != nil { // reaches EOF errno := err.(syscall.Errno) if errno == syscall.ENXIO { break } else { // unexpected errors log.Fatal("Failed to syscall.Seek SEEK_DATA") return err } } hole, err = syscall.Seek(int(childFile.Fd()), data, seekHole) if err != nil { log.Fatal("Failed to syscall.Seek SEEK_HOLE") return err } // now we have a data start offset and length(hole - data) // let's read from child and write to parent file block by block _, err = parentFile.Seek(data, os.SEEK_SET) if err != nil { log.Fatal("Failed to os.Seek os.SEEK_SET") return err } offset := data buffer := fio.AllocateAligned(blockSize) for offset != hole { // read a block from child, maybe use bufio or Reader stream n, err := fio.ReadAt(childFile, buffer, offset) if n != len(buffer) || err != nil { log.Fatal("Failed to read from childFile") return err } // write a block to parent n, err = fio.WriteAt(parentFile, buffer, offset) if n != len(buffer) || err != nil { log.Fatal("Failed to write to parentFile") return err } offset += int64(n) } } return nil }
func (d *directFile) WriteAt(buf []byte, offset int64) (int, error) { return directfio.WriteAt(d.File, buf, offset) }