Beispiel #1
0
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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}