*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
- * Copyright (C) 2004-2013 Wayne Davison
+ * Copyright (C) 2004-2020 Wayne Davison
*
* 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
#define ENODATA EAGAIN
#endif
-/* We want all reads to be aligned on 1K boundries. */
-#define ALIGN_BOUNDRY 1024
+/* 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_BOUNDRY-1))
+#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDARY-1))
/* Round up a length to the next boundary */
-#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1)
+#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDARY-1)) + 1)
extern int sparse_files;
+OFF_T preallocated_len = 0;
+
static OFF_T sparse_seek = 0;
+static OFF_T sparse_past_write = 0;
int sparse_end(int f, OFF_T size)
{
int ret;
+ sparse_past_write = 0;
+
if (!sparse_seek)
return 0;
return ret;
}
-
-static int write_sparse(int f, char *buf, int len)
+/* Note that the offset is just the caller letting us know where
+ * 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 ret;
if (l1 == len)
return len;
- if (sparse_seek)
- do_lseek(f, sparse_seek, SEEK_CUR);
+ if (sparse_seek) {
+ 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_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) {
if (ret < 0 && errno == EINTR)
continue;
+ sparse_seek = 0;
return ret;
}
- if (ret != (int)(len - (l1+l2)))
+ if (ret != (int)(len - (l1+l2))) {
+ sparse_seek = 0;
return l1+ret;
+ }
return len;
}
-
static char *wf_writeBuf;
static size_t wf_writeBufSize;
static size_t wf_writeBufCnt;
return ret;
}
-
-/*
- * write_file does not allow incomplete writes. It loops internally
- * until len bytes are written or errno is set.
- */
-int write_file(int f, char *buf, int len)
+/* write_file does not allow incomplete writes. It loops internally
+ * until len bytes are written or errno is set. Note that use_seek and
+ * offset are only used in sparse processing (see write_sparse()). */
+int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len)
{
int ret = 0;
int r1;
if (sparse_files > 0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
- r1 = write_sparse(f, buf, len1);
+ r1 = write_sparse(f, use_seek, offset, buf, len1);
+ offset += r1;
} else {
if (!wf_writeBuf) {
wf_writeBufSize = WRITE_SIZE * 8;
wf_writeBufCnt = 0;
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);
if (r1) {
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().
* It gives sliding window access to a file. mmap() is not used because of
{
struct map_struct *map;
- if (!(map = new0(struct map_struct)))
- out_of_memory("map_file");
+ map = new0(struct map_struct);
if (blk_size && (read_size % blk_size))
read_size += blk_size - (read_size % blk_size);
/* make sure we have allocated enough memory for the window */
if (window_size > map->p_size) {
map->p = realloc_array(map->p, char, window_size);
- if (!map->p)
- out_of_memory("map_ptr");
map->p_size = window_size;
}
return map->p + align_fudge;
}
-
int unmap_file(struct map_struct *map)
{
int ret;
map->p = NULL;
}
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);
return ret;