Annotation of embedaddon/rsync/fileio.c, revision 1.1
1.1 ! misho 1: /*
! 2: * File IO utilities used in rsync.
! 3: *
! 4: * Copyright (C) 1998 Andrew Tridgell
! 5: * Copyright (C) 2002 Martin Pool
! 6: * Copyright (C) 2004-2009 Wayne Davison
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify
! 9: * it under the terms of the GNU General Public License as published by
! 10: * the Free Software Foundation; either version 3 of the License, or
! 11: * (at your option) any later version.
! 12: *
! 13: * This program is distributed in the hope that it will be useful,
! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 16: * GNU General Public License for more details.
! 17: *
! 18: * You should have received a copy of the GNU General Public License along
! 19: * with this program; if not, visit the http://fsf.org website.
! 20: */
! 21:
! 22: #include "rsync.h"
! 23:
! 24: #ifndef ENODATA
! 25: #define ENODATA EAGAIN
! 26: #endif
! 27:
! 28: extern int sparse_files;
! 29:
! 30: static OFF_T sparse_seek = 0;
! 31:
! 32: int sparse_end(int f, OFF_T size)
! 33: {
! 34: int ret;
! 35:
! 36: if (!sparse_seek)
! 37: return 0;
! 38:
! 39: #ifdef HAVE_FTRUNCATE
! 40: ret = do_ftruncate(f, size);
! 41: #else
! 42: if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
! 43: ret = -1;
! 44: else {
! 45: do {
! 46: ret = write(f, "", 1);
! 47: } while (ret < 0 && errno == EINTR);
! 48:
! 49: ret = ret <= 0 ? -1 : 0;
! 50: }
! 51: #endif
! 52:
! 53: sparse_seek = 0;
! 54:
! 55: return ret;
! 56: }
! 57:
! 58:
! 59: static int write_sparse(int f, char *buf, int len)
! 60: {
! 61: int l1 = 0, l2 = 0;
! 62: int ret;
! 63:
! 64: for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
! 65: for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
! 66:
! 67: sparse_seek += l1;
! 68:
! 69: if (l1 == len)
! 70: return len;
! 71:
! 72: if (sparse_seek)
! 73: do_lseek(f, sparse_seek, SEEK_CUR);
! 74: sparse_seek = l2;
! 75:
! 76: while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
! 77: if (ret < 0 && errno == EINTR)
! 78: continue;
! 79: return ret;
! 80: }
! 81:
! 82: if (ret != (int)(len - (l1+l2)))
! 83: return l1+ret;
! 84:
! 85: return len;
! 86: }
! 87:
! 88:
! 89: static char *wf_writeBuf;
! 90: static size_t wf_writeBufSize;
! 91: static size_t wf_writeBufCnt;
! 92:
! 93: int flush_write_file(int f)
! 94: {
! 95: int ret = 0;
! 96: char *bp = wf_writeBuf;
! 97:
! 98: while (wf_writeBufCnt > 0) {
! 99: if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
! 100: if (errno == EINTR)
! 101: continue;
! 102: return ret;
! 103: }
! 104: wf_writeBufCnt -= ret;
! 105: bp += ret;
! 106: }
! 107: return ret;
! 108: }
! 109:
! 110:
! 111: /*
! 112: * write_file does not allow incomplete writes. It loops internally
! 113: * until len bytes are written or errno is set.
! 114: */
! 115: int write_file(int f, char *buf, int len)
! 116: {
! 117: int ret = 0;
! 118:
! 119: while (len > 0) {
! 120: int r1;
! 121: if (sparse_files > 0) {
! 122: int len1 = MIN(len, SPARSE_WRITE_SIZE);
! 123: r1 = write_sparse(f, buf, len1);
! 124: } else {
! 125: if (!wf_writeBuf) {
! 126: wf_writeBufSize = WRITE_SIZE * 8;
! 127: wf_writeBufCnt = 0;
! 128: wf_writeBuf = new_array(char, wf_writeBufSize);
! 129: if (!wf_writeBuf)
! 130: out_of_memory("write_file");
! 131: }
! 132: r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt);
! 133: if (r1) {
! 134: memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
! 135: wf_writeBufCnt += r1;
! 136: }
! 137: if (wf_writeBufCnt == wf_writeBufSize) {
! 138: if (flush_write_file(f) < 0)
! 139: return -1;
! 140: if (!r1 && len)
! 141: continue;
! 142: }
! 143: }
! 144: if (r1 <= 0) {
! 145: if (ret > 0)
! 146: return ret;
! 147: return r1;
! 148: }
! 149: len -= r1;
! 150: buf += r1;
! 151: ret += r1;
! 152: }
! 153: return ret;
! 154: }
! 155:
! 156:
! 157: /* This provides functionality somewhat similar to mmap() but using read().
! 158: * It gives sliding window access to a file. mmap() is not used because of
! 159: * the possibility of another program (such as a mailer) truncating the
! 160: * file thus giving us a SIGBUS. */
! 161: struct map_struct *map_file(int fd, OFF_T len, int32 read_size,
! 162: int32 blk_size)
! 163: {
! 164: struct map_struct *map;
! 165:
! 166: if (!(map = new0(struct map_struct)))
! 167: out_of_memory("map_file");
! 168:
! 169: if (blk_size && (read_size % blk_size))
! 170: read_size += blk_size - (read_size % blk_size);
! 171:
! 172: map->fd = fd;
! 173: map->file_size = len;
! 174: map->def_window_size = read_size;
! 175:
! 176: return map;
! 177: }
! 178:
! 179:
! 180: /* slide the read window in the file */
! 181: char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
! 182: {
! 183: int32 nread;
! 184: OFF_T window_start, read_start;
! 185: int32 window_size, read_size, read_offset;
! 186:
! 187: if (len == 0)
! 188: return NULL;
! 189: if (len < 0) {
! 190: rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
! 191: (long)len);
! 192: exit_cleanup(RERR_FILEIO);
! 193: }
! 194:
! 195: /* in most cases the region will already be available */
! 196: if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
! 197: return map->p + (offset - map->p_offset);
! 198:
! 199: /* nope, we are going to have to do a read. Work out our desired window */
! 200: window_start = offset;
! 201: window_size = map->def_window_size;
! 202: if (window_start + window_size > map->file_size)
! 203: window_size = (int32)(map->file_size - window_start);
! 204: if (len > window_size)
! 205: window_size = len;
! 206:
! 207: /* make sure we have allocated enough memory for the window */
! 208: if (window_size > map->p_size) {
! 209: map->p = realloc_array(map->p, char, window_size);
! 210: if (!map->p)
! 211: out_of_memory("map_ptr");
! 212: map->p_size = window_size;
! 213: }
! 214:
! 215: /* Now try to avoid re-reading any bytes by reusing any bytes
! 216: * from the previous buffer. */
! 217: if (window_start >= map->p_offset &&
! 218: window_start < map->p_offset + map->p_len &&
! 219: window_start + window_size >= map->p_offset + map->p_len) {
! 220: read_start = map->p_offset + map->p_len;
! 221: read_offset = (int32)(read_start - window_start);
! 222: read_size = window_size - read_offset;
! 223: memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
! 224: } else {
! 225: read_start = window_start;
! 226: read_size = window_size;
! 227: read_offset = 0;
! 228: }
! 229:
! 230: if (read_size <= 0) {
! 231: rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
! 232: (long)read_size);
! 233: exit_cleanup(RERR_FILEIO);
! 234: }
! 235:
! 236: if (map->p_fd_offset != read_start) {
! 237: OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
! 238: if (ret != read_start) {
! 239: rsyserr(FERROR, errno, "lseek returned %.0f, not %.0f",
! 240: (double)ret, (double)read_start);
! 241: exit_cleanup(RERR_FILEIO);
! 242: }
! 243: map->p_fd_offset = read_start;
! 244: }
! 245: map->p_offset = window_start;
! 246: map->p_len = window_size;
! 247:
! 248: while (read_size > 0) {
! 249: nread = read(map->fd, map->p + read_offset, read_size);
! 250: if (nread <= 0) {
! 251: if (!map->status)
! 252: map->status = nread ? errno : ENODATA;
! 253: /* The best we can do is zero the buffer -- the file
! 254: * has changed mid transfer! */
! 255: memset(map->p + read_offset, 0, read_size);
! 256: break;
! 257: }
! 258: map->p_fd_offset += nread;
! 259: read_offset += nread;
! 260: read_size -= nread;
! 261: }
! 262:
! 263: return map->p;
! 264: }
! 265:
! 266:
! 267: int unmap_file(struct map_struct *map)
! 268: {
! 269: int ret;
! 270:
! 271: if (map->p) {
! 272: free(map->p);
! 273: map->p = NULL;
! 274: }
! 275: ret = map->status;
! 276: memset(map, 0, sizeof map[0]);
! 277: free(map);
! 278:
! 279: return ret;
! 280: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>