int sparse_end(int f, OFF_T size) { int ret; if (!sparse_seek) return 0; #ifdef HAVE_FTRUNCATE ret = do_ftruncate(f, size); #else if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1) ret = -1; else { do { ret = write(f, "", 1); } while (ret < 0 && errno == EINTR); ret = ret <= 0 ? -1 : 0; } #endif sparse_seek = 0; return ret; }
/** * Overwrites the contents of the disk image managed by this device with the * contents as they were at the point the snapshot was made. */ static int nand_dev_load_disk_state(QEMUFile *f, nand_dev *dev) { #ifndef ANDROID_QCOW int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE; uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0}; int ret; /* File size for restore and truncate */ uint64_t total_size = qemu_get_be64(f); if (total_size > dev->max_size) { XLOG("%s, restore failed: size required (%lld) exceeds device limit (%lld)\n", __FUNCTION__, total_size, dev->max_size); return -EIO; } /* overwrite disk contents with snapshot contents */ uint64_t next_offset = 0; ret = do_lseek(dev->fd, 0, SEEK_SET); if (ret < 0) { XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno)); return -EIO; } while (next_offset < total_size) { /* snapshot buffer may not be an exact multiple of buf_size * if necessary, adjust buffer size for last copy operation */ if (total_size - next_offset < buf_size) { buf_size = total_size - next_offset; } ret = qemu_get_buffer(f, buffer, buf_size); if (ret != buf_size) { XLOG("%s read failed: expected %d bytes but got %d\n", __FUNCTION__, buf_size, ret); return -EIO; } ret = do_write(dev->fd, buffer, buf_size); if (ret != buf_size) { XLOG("%s, write failed: %s\n", __FUNCTION__, strerror(errno)); return -EIO; } next_offset += buf_size; } ret = do_ftruncate(dev->fd, total_size); if (ret < 0) { XLOG("%s ftruncate failed: %s\n", __FUNCTION__, strerror(errno)); return -EIO; } #endif return 0; }
/* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file. * Otherwise, it just writes to and closes the provided file descriptor. * In either case, if --xattrs are being preserved, the dest file will * have its xattrs set from the source file. * * This is used in conjunction with the --temp-dir, --backup, and * --copy-dest options. */ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) { int ifd; char buf[1024 * 8]; int len; /* Number of bytes read into `buf'. */ #ifdef PREALLOCATE_NEEDS_TRUNCATE OFF_T preallocated_len = 0, offset = 0; #endif if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "open %s", full_fname(source)); errno = save_errno; return -1; } if (ofd < 0) { if (robust_unlink(dest) && errno != ENOENT) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest)); errno = save_errno; return -1; } #ifdef SUPPORT_XATTRS if (preserve_xattrs) mode |= S_IWUSR; #endif mode &= INITACCESSPERMS; if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); close(ifd); errno = save_errno; return -1; } } #ifdef SUPPORT_PREALLOCATION if (preallocate_files) { STRUCT_STAT srcst; /* Try to preallocate enough space for file's eventual length. Can * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */ if (do_fstat(ifd, &srcst) < 0) rsyserr(FWARNING, errno, "fstat %s", full_fname(source)); else if (srcst.st_size > 0) { if (do_fallocate(ofd, 0, srcst.st_size) == 0) { #ifdef PREALLOCATE_NEEDS_TRUNCATE preallocated_len = srcst.st_size; #endif } else rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest)); } } #endif while ((len = safe_read(ifd, buf, sizeof buf)) > 0) { if (full_write(ofd, buf, len) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest)); close(ifd); close(ofd); errno = save_errno; return -1; } #ifdef PREALLOCATE_NEEDS_TRUNCATE offset += len; #endif } if (len < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "read %s", full_fname(source)); close(ifd); close(ofd); errno = save_errno; return -1; } if (close(ifd) < 0) { rsyserr(FWARNING, errno, "close failed on %s", full_fname(source)); } #ifdef PREALLOCATE_NEEDS_TRUNCATE /* Source file might have shrunk since we fstatted it. * Cut off any extra preallocated zeros from dest file. */ if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) { /* If we fail to truncate, the dest file may be wrong, so we * must trigger the "partial transfer" error. */ rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); } #endif if (close(ofd) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "close failed on %s", full_fname(dest)); errno = save_errno; return -1; } #ifdef SUPPORT_XATTRS if (preserve_xattrs) copy_xattrs(source, dest); #endif return 0; }
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, const char *fname, int fd, OFF_T total_size, struct sum_struct *sum, int numMatchTokens, int nextToken, char *nextData, char *file_sum2) { static char file_sum1[MAX_DIGEST_LEN]; struct map_struct *mapbuf; int32 len, sum_len; OFF_T offset = 0; OFF_T offset2; int offsetDefer; char *data; int32 i; char *map = NULL; int replayTokenCnt = 0; if (fd_r >= 0 && size_r > 0) { int32 read_size = MAX(sum->blength * 2, 16*1024); mapbuf = map_file(fd_r, size_r, read_size, sum->blength); if (verbose > 2) { rprintf(FINFO, "recv mapped %s of size %.0f\n", fname_r, (double)size_r); } } else mapbuf = NULL; sum_init(checksum_seed); if (append_mode > 0) { OFF_T j; sum->flength = (OFF_T)sum->count * sum->blength; if (sum->remainder) sum->flength -= sum->blength - sum->remainder; if (append_mode == 2) { for (j = CHUNK_SIZE; j < sum->flength; j += CHUNK_SIZE) { if (do_progress) show_progress(offset, total_size); sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE), CHUNK_SIZE); offset = j; } if (offset < sum->flength) { int32 len = (int32)(sum->flength - offset); if (do_progress) show_progress(offset, total_size); sum_update(map_ptr(mapbuf, offset, len), len); } } offset = sum->flength; if (fd != -1 && (j = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)j, (double)offset); exit_cleanup(RERR_FILEIO); } } offsetDefer = 0; while ( 1 ) { /* * We have to replay any tokens that were potentially read-ahead * to see if the file was identical. * numMatchTokens < 0 means there are no replay tokens * numMatchTokens >= 0 means there are numMatchTokens from -1 * to -numMatchTokens, followed by * (nextToken, *nextData). * * If numMatchTokens >= 0 and nextToken == 0, then then file_sum * was already ready from f_in. Otherwise, we need to read it * here. */ if ( replayTokenCnt >= 0 && numMatchTokens >= 0 ) { if ( replayTokenCnt < numMatchTokens ) { /* * replay -1, -2, ..., -numMatchTokens */ i = -replayTokenCnt - 1; replayTokenCnt++; } else { /* * replay the next token - after this we are * up to date. */ i = nextToken; data = nextData; replayTokenCnt = -1; } } else { i = recv_token(f_in, &data); } if ( i == 0 ) break; if (do_progress) show_progress(offset, total_size); if (i > 0) { if (verbose > 3) { rprintf(FINFO,"data recv %d at %.0f\n", i,(double)offset); } stats.literal_data += i; cleanup_got_literal = 1; sum_update(data, i); if ( offsetDefer ) { OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; if ((pos = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } offsetDefer = 0; } if (fd != -1 && write_file(fd,data,i) != i) goto report_write_error; offset += i; continue; } i = -(i+1); offset2 = i * (OFF_T)sum->blength; len = sum->blength; if (i == (int)sum->count-1 && sum->remainder != 0) len = sum->remainder; stats.matched_data += len; if (verbose > 3) { rprintf(FINFO, "chunk[%d] of size %ld at %.0f offset=%.0f%s\n", i, (long)len, (double)offset2, (double)offset, updating_basis_or_equiv && offset == offset2 ? " (seek)" : ""); } if (mapbuf) { map = map_ptr(mapbuf,offset2,len); see_token(map, len); sum_update(map, len); } if (updating_basis_or_equiv) { if (offset == offset2 && fd != -1) { offset += len; offsetDefer = 1; continue; } } if (fd != -1 && map) { if ( offsetDefer ) { OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; if ((pos = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } offsetDefer = 0; } if ( write_file(fd, map, len) != (int)len) goto report_write_error; } offset += len; } if ( offsetDefer ) { OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; if ((pos = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } offsetDefer = 0; } if (flush_write_file(fd) < 0) goto report_write_error; #ifdef HAVE_FTRUNCATE if (fd != -1 && do_ftruncate(fd, offset) < 0) { rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", full_fname(fname)); } #endif if (do_progress) end_progress(total_size); if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) { report_write_error: rsyserr(FERROR_XFER, errno, "write failed on %s", full_fname(fname)); exit_cleanup(RERR_FILEIO); } sum_len = sum_end(file_sum1); if (mapbuf) unmap_file(mapbuf); if ( numMatchTokens < 0 || nextToken != 0 ) { /* * If numMatchTokens >= 0 and nextToken == 0, then the caller already * read ahead to the digest. Otherwise we have to read it here. */ read_buf(f_in, file_sum2, sum_len); } if (verbose > 2) rprintf(FINFO,"got file_sum\n"); if (fd != -1 && memcmp(file_sum1, file_sum2, sum_len) != 0) return 0; return 1; }