version 1.1, 2012/02/17 15:09:30
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) 1998 Andrew Tridgell |
* Copyright (C) 1998 Andrew Tridgell |
* Copyright (C) 2002 Martin Pool |
* Copyright (C) 2002 Martin Pool |
* Copyright (C) 2004-2009 Wayne Davison | * Copyright (C) 2004-2020 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 20
|
Line 20
|
*/ |
*/ |
|
|
#include "rsync.h" |
#include "rsync.h" |
|
#include "inums.h" |
|
|
#ifndef ENODATA |
#ifndef ENODATA |
#define ENODATA EAGAIN |
#define ENODATA EAGAIN |
#endif |
#endif |
|
|
|
/* We want all reads to be aligned on 1K boundaries. */ |
|
#define ALIGN_BOUNDARY 1024 |
|
/* How far past the boundary is an offset? */ |
|
#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDARY-1)) |
|
/* Round up a length to the next boundary */ |
|
#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDARY-1)) + 1) |
|
|
extern int sparse_files; |
extern int sparse_files; |
|
extern int sparse_files_block_size; |
|
|
|
OFF_T preallocated_len = 0; |
|
|
static OFF_T sparse_seek = 0; |
static OFF_T sparse_seek = 0; |
|
static OFF_T sparse_past_write = 0; |
|
|
int sparse_end(int f, OFF_T size) |
int sparse_end(int f, OFF_T size) |
{ |
{ |
int ret; |
int ret; |
|
|
|
sparse_past_write = 0; |
|
|
if (!sparse_seek) |
if (!sparse_seek) |
return 0; |
return 0; |
|
|
Line 55 int sparse_end(int f, OFF_T size)
|
Line 69 int sparse_end(int f, OFF_T size)
|
return ret; |
return ret; |
} |
} |
|
|
| /* Note that the offset is just the caller letting us know where |
static int write_sparse(int f, char *buf, int len) | * the current file position is in the file. The use_seek arg tells |
| * us that we should seek over matching data instead of writing it. */ |
| static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int len) |
{ |
{ |
int l1 = 0, l2 = 0; |
int l1 = 0, l2 = 0; |
int ret; |
int ret; |
Line 69 static int write_sparse(int f, char *buf, int len)
|
Line 85 static int write_sparse(int f, char *buf, int len)
|
if (l1 == len) |
if (l1 == len) |
return len; |
return len; |
|
|
if (sparse_seek) | if (sparse_seek) { |
do_lseek(f, sparse_seek, SEEK_CUR); | if (sparse_past_write >= preallocated_len) { |
| if (do_lseek(f, sparse_seek, SEEK_CUR) < 0) |
| return -1; |
| } else if (do_punch_hole(f, sparse_past_write, sparse_seek) < 0) { |
| sparse_seek = 0; |
| return -1; |
| } |
| } |
sparse_seek = l2; |
sparse_seek = l2; |
|
sparse_past_write = offset + len - l2; |
|
|
|
if (use_seek) { |
|
/* The in-place data already matches. */ |
|
if (do_lseek(f, len - (l1+l2), SEEK_CUR) < 0) |
|
return -1; |
|
return len; |
|
} |
|
|
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) { |
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) { |
if (ret < 0 && errno == EINTR) |
if (ret < 0 && errno == EINTR) |
continue; |
continue; |
|
sparse_seek = 0; |
return ret; |
return ret; |
} |
} |
|
|
if (ret != (int)(len - (l1+l2))) | if (ret != (int)(len - (l1+l2))) { |
| sparse_seek = 0; |
return l1+ret; |
return l1+ret; |
|
} |
|
|
return len; |
return len; |
} |
} |
|
|
|
|
static char *wf_writeBuf; |
static char *wf_writeBuf; |
static size_t wf_writeBufSize; |
static size_t wf_writeBufSize; |
static size_t wf_writeBufCnt; |
static size_t wf_writeBufCnt; |
Line 107 int flush_write_file(int f)
|
Line 140 int flush_write_file(int f)
|
return ret; |
return ret; |
} |
} |
|
|
| /* write_file does not allow incomplete writes. It loops internally |
/* | * until len bytes are written or errno is set. Note that use_seek and |
* write_file does not allow incomplete writes. It loops internally | * offset are only used in sparse processing (see write_sparse()). */ |
* until len bytes are written or errno is set. | int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len) |
*/ | |
int write_file(int f, char *buf, int len) | |
{ |
{ |
int ret = 0; |
int ret = 0; |
|
|
while (len > 0) { |
while (len > 0) { |
int r1; |
int r1; |
if (sparse_files > 0) { |
if (sparse_files > 0) { |
int len1 = MIN(len, SPARSE_WRITE_SIZE); | int len1 = MIN(len, sparse_files_block_size); |
r1 = write_sparse(f, buf, len1); | r1 = write_sparse(f, use_seek, offset, buf, len1); |
| offset += r1; |
} else { |
} else { |
if (!wf_writeBuf) { |
if (!wf_writeBuf) { |
wf_writeBufSize = WRITE_SIZE * 8; |
wf_writeBufSize = WRITE_SIZE * 8; |
wf_writeBufCnt = 0; |
wf_writeBufCnt = 0; |
wf_writeBuf = new_array(char, wf_writeBufSize); |
wf_writeBuf = new_array(char, wf_writeBufSize); |
if (!wf_writeBuf) |
|
out_of_memory("write_file"); |
|
} |
} |
r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt); |
r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt); |
if (r1) { |
if (r1) { |
Line 153 int write_file(int f, char *buf, int len)
|
Line 183 int write_file(int f, char *buf, int len)
|
return ret; |
return ret; |
} |
} |
|
|
|
/* An in-place update found identical data at an identical location. We either |
|
* just seek past it, or (for an in-place sparse update), we give the data to |
|
* the sparse processor with the use_seek flag set. */ |
|
int skip_matched(int fd, OFF_T offset, const char *buf, int len) |
|
{ |
|
OFF_T pos; |
|
|
|
if (sparse_files > 0) { |
|
if (write_file(fd, 1, offset, buf, len) != len) |
|
return -1; |
|
return 0; |
|
} |
|
|
|
if (flush_write_file(fd) < 0) |
|
return -1; |
|
|
|
if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset + len) { |
|
rsyserr(FERROR_XFER, errno, "lseek returned %s, not %s", |
|
big_num(pos), big_num(offset)); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
/* This provides functionality somewhat similar to mmap() but using read(). |
/* This provides functionality somewhat similar to mmap() but using read(). |
* It gives sliding window access to a file. mmap() is not used because of |
* It gives sliding window access to a file. mmap() is not used because of |
* the possibility of another program (such as a mailer) truncating the |
* the possibility of another program (such as a mailer) truncating the |
* file thus giving us a SIGBUS. */ |
* file thus giving us a SIGBUS. */ |
struct map_struct *map_file(int fd, OFF_T len, int32 read_size, | struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size) |
int32 blk_size) | |
{ |
{ |
struct map_struct *map; |
struct map_struct *map; |
|
|
if (!(map = new0(struct map_struct))) | map = new0(struct map_struct); |
out_of_memory("map_file"); | |
|
|
if (blk_size && (read_size % blk_size)) |
if (blk_size && (read_size % blk_size)) |
read_size += blk_size - (read_size % blk_size); |
read_size += blk_size - (read_size % blk_size); |
|
|
map->fd = fd; |
map->fd = fd; |
map->file_size = len; |
map->file_size = len; |
map->def_window_size = read_size; | map->def_window_size = ALIGNED_LENGTH(read_size); |
|
|
return map; |
return map; |
} |
} |
Line 180 struct map_struct *map_file(int fd, OFF_T len, int32 r
|
Line 232 struct map_struct *map_file(int fd, OFF_T len, int32 r
|
/* slide the read window in the file */ |
/* slide the read window in the file */ |
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len) |
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len) |
{ |
{ |
int32 nread; |
|
OFF_T window_start, read_start; |
OFF_T window_start, read_start; |
int32 window_size, read_size, read_offset; | int32 window_size, read_size, read_offset, align_fudge; |
|
|
if (len == 0) |
if (len == 0) |
return NULL; |
return NULL; |
Line 197 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
Line 248 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
return map->p + (offset - map->p_offset); |
return map->p + (offset - map->p_offset); |
|
|
/* nope, we are going to have to do a read. Work out our desired window */ |
/* nope, we are going to have to do a read. Work out our desired window */ |
window_start = offset; | align_fudge = (int32)ALIGNED_OVERSHOOT(offset); |
| window_start = offset - align_fudge; |
window_size = map->def_window_size; |
window_size = map->def_window_size; |
if (window_start + window_size > map->file_size) |
if (window_start + window_size > map->file_size) |
window_size = (int32)(map->file_size - window_start); |
window_size = (int32)(map->file_size - window_start); |
if (len > window_size) | if (window_size < len + align_fudge) |
window_size = len; | window_size = ALIGNED_LENGTH(len + align_fudge); |
|
|
/* make sure we have allocated enough memory for the window */ |
/* make sure we have allocated enough memory for the window */ |
if (window_size > map->p_size) { |
if (window_size > map->p_size) { |
map->p = realloc_array(map->p, char, window_size); |
map->p = realloc_array(map->p, char, window_size); |
if (!map->p) |
|
out_of_memory("map_ptr"); |
|
map->p_size = window_size; |
map->p_size = window_size; |
} |
} |
|
|
/* Now try to avoid re-reading any bytes by reusing any bytes | /* Now try to avoid re-reading any bytes by reusing any bytes from the previous buffer. */ |
* from the previous buffer. */ | if (window_start >= map->p_offset && window_start < map->p_offset + map->p_len |
if (window_start >= map->p_offset && | && window_start + window_size >= map->p_offset + map->p_len) { |
window_start < map->p_offset + map->p_len && | |
window_start + window_size >= map->p_offset + map->p_len) { | |
read_start = map->p_offset + map->p_len; |
read_start = map->p_offset + map->p_len; |
read_offset = (int32)(read_start - window_start); |
read_offset = (int32)(read_start - window_start); |
read_size = window_size - read_offset; |
read_size = window_size - read_offset; |
Line 236 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
Line 284 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
if (map->p_fd_offset != read_start) { |
if (map->p_fd_offset != read_start) { |
OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET); |
OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET); |
if (ret != read_start) { |
if (ret != read_start) { |
rsyserr(FERROR, errno, "lseek returned %.0f, not %.0f", | rsyserr(FERROR, errno, "lseek returned %s, not %s", |
(double)ret, (double)read_start); | big_num(ret), big_num(read_start)); |
exit_cleanup(RERR_FILEIO); |
exit_cleanup(RERR_FILEIO); |
} |
} |
map->p_fd_offset = read_start; |
map->p_fd_offset = read_start; |
Line 246 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
Line 294 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
map->p_len = window_size; |
map->p_len = window_size; |
|
|
while (read_size > 0) { |
while (read_size > 0) { |
nread = read(map->fd, map->p + read_offset, read_size); | int32 nread = read(map->fd, map->p + read_offset, read_size); |
if (nread <= 0) { |
if (nread <= 0) { |
if (!map->status) |
if (!map->status) |
map->status = nread ? errno : ENODATA; |
map->status = nread ? errno : ENODATA; |
Line 260 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
Line 308 char *map_ptr(struct map_struct *map, OFF_T offset, in
|
read_size -= nread; |
read_size -= nread; |
} |
} |
|
|
return map->p; | return map->p + align_fudge; |
} |
} |
|
|
|
|
int unmap_file(struct map_struct *map) |
int unmap_file(struct map_struct *map) |
{ |
{ |
int ret; |
int ret; |
Line 273 int unmap_file(struct map_struct *map)
|
Line 320 int unmap_file(struct map_struct *map)
|
map->p = NULL; |
map->p = NULL; |
} |
} |
ret = map->status; |
ret = map->status; |
memset(map, 0, sizeof map[0]); | #if 0 /* I don't think we really need this. */ |
| force_memzero(map, sizeof map[0]); |
| #endif |
free(map); |
free(map); |
|
|
return ret; |
return ret; |