File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / fileio.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:51:14 2013 UTC (10 years, 8 months ago) by misho
Branches: rsync, MAIN
CVS tags: RSYNC3_1_0, HEAD
v 3.1.0

    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-2013 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: #include "inums.h"
   24: 
   25: #ifndef ENODATA
   26: #define ENODATA EAGAIN
   27: #endif
   28: 
   29: /* We want all reads to be aligned on 1K boundries. */
   30: #define ALIGN_BOUNDRY 1024
   31: /* How far past the boundary is an offset? */
   32: #define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDRY-1))
   33: /* Round up a length to the next boundary */
   34: #define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1)
   35: 
   36: extern int sparse_files;
   37: 
   38: static OFF_T sparse_seek = 0;
   39: 
   40: int sparse_end(int f, OFF_T size)
   41: {
   42: 	int ret;
   43: 
   44: 	if (!sparse_seek)
   45: 		return 0;
   46: 
   47: #ifdef HAVE_FTRUNCATE
   48: 	ret = do_ftruncate(f, size);
   49: #else
   50: 	if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
   51: 		ret = -1;
   52: 	else {
   53: 		do {
   54: 			ret = write(f, "", 1);
   55: 		} while (ret < 0 && errno == EINTR);
   56: 
   57: 		ret = ret <= 0 ? -1 : 0;
   58: 	}
   59: #endif
   60: 
   61: 	sparse_seek = 0;
   62: 
   63: 	return ret;
   64: }
   65: 
   66: 
   67: static int write_sparse(int f, char *buf, int len)
   68: {
   69: 	int l1 = 0, l2 = 0;
   70: 	int ret;
   71: 
   72: 	for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
   73: 	for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
   74: 
   75: 	sparse_seek += l1;
   76: 
   77: 	if (l1 == len)
   78: 		return len;
   79: 
   80: 	if (sparse_seek)
   81: 		do_lseek(f, sparse_seek, SEEK_CUR);
   82: 	sparse_seek = l2;
   83: 
   84: 	while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
   85: 		if (ret < 0 && errno == EINTR)
   86: 			continue;
   87: 		sparse_seek = 0;
   88: 		return ret;
   89: 	}
   90: 
   91: 	if (ret != (int)(len - (l1+l2))) {
   92: 		sparse_seek = 0;
   93: 		return l1+ret;
   94: 	}
   95: 
   96: 	return len;
   97: }
   98: 
   99: 
  100: static char *wf_writeBuf;
  101: static size_t wf_writeBufSize;
  102: static size_t wf_writeBufCnt;
  103: 
  104: int flush_write_file(int f)
  105: {
  106: 	int ret = 0;
  107: 	char *bp = wf_writeBuf;
  108: 
  109: 	while (wf_writeBufCnt > 0) {
  110: 		if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
  111: 			if (errno == EINTR)
  112: 				continue;
  113: 			return ret;
  114: 		}
  115: 		wf_writeBufCnt -= ret;
  116: 		bp += ret;
  117: 	}
  118: 	return ret;
  119: }
  120: 
  121: 
  122: /*
  123:  * write_file does not allow incomplete writes.  It loops internally
  124:  * until len bytes are written or errno is set.
  125:  */
  126: int write_file(int f, char *buf, int len)
  127: {
  128: 	int ret = 0;
  129: 
  130: 	while (len > 0) {
  131: 		int r1;
  132: 		if (sparse_files > 0) {
  133: 			int len1 = MIN(len, SPARSE_WRITE_SIZE);
  134: 			r1 = write_sparse(f, buf, len1);
  135: 		} else {
  136: 			if (!wf_writeBuf) {
  137: 				wf_writeBufSize = WRITE_SIZE * 8;
  138: 				wf_writeBufCnt  = 0;
  139: 				wf_writeBuf = new_array(char, wf_writeBufSize);
  140: 				if (!wf_writeBuf)
  141: 					out_of_memory("write_file");
  142: 			}
  143: 			r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt);
  144: 			if (r1) {
  145: 				memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
  146: 				wf_writeBufCnt += r1;
  147: 			}
  148: 			if (wf_writeBufCnt == wf_writeBufSize) {
  149: 				if (flush_write_file(f) < 0)
  150: 					return -1;
  151: 				if (!r1 && len)
  152: 					continue;
  153: 			}
  154: 		}
  155: 		if (r1 <= 0) {
  156: 			if (ret > 0)
  157: 				return ret;
  158: 			return r1;
  159: 		}
  160: 		len -= r1;
  161: 		buf += r1;
  162: 		ret += r1;
  163: 	}
  164: 	return ret;
  165: }
  166: 
  167: 
  168: /* This provides functionality somewhat similar to mmap() but using read().
  169:  * It gives sliding window access to a file.  mmap() is not used because of
  170:  * the possibility of another program (such as a mailer) truncating the
  171:  * file thus giving us a SIGBUS. */
  172: struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size)
  173: {
  174: 	struct map_struct *map;
  175: 
  176: 	if (!(map = new0(struct map_struct)))
  177: 		out_of_memory("map_file");
  178: 
  179: 	if (blk_size && (read_size % blk_size))
  180: 		read_size += blk_size - (read_size % blk_size);
  181: 
  182: 	map->fd = fd;
  183: 	map->file_size = len;
  184: 	map->def_window_size = ALIGNED_LENGTH(read_size);
  185: 
  186: 	return map;
  187: }
  188: 
  189: 
  190: /* slide the read window in the file */
  191: char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
  192: {
  193: 	OFF_T window_start, read_start;
  194: 	int32 window_size, read_size, read_offset, align_fudge;
  195: 
  196: 	if (len == 0)
  197: 		return NULL;
  198: 	if (len < 0) {
  199: 		rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
  200: 			(long)len);
  201: 		exit_cleanup(RERR_FILEIO);
  202: 	}
  203: 
  204: 	/* in most cases the region will already be available */
  205: 	if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
  206: 		return map->p + (offset - map->p_offset);
  207: 
  208: 	/* nope, we are going to have to do a read. Work out our desired window */
  209: 	align_fudge = (int32)ALIGNED_OVERSHOOT(offset);
  210: 	window_start = offset - align_fudge;
  211: 	window_size = map->def_window_size;
  212: 	if (window_start + window_size > map->file_size)
  213: 		window_size = (int32)(map->file_size - window_start);
  214: 	if (window_size < len + align_fudge)
  215: 		window_size = ALIGNED_LENGTH(len + align_fudge);
  216: 
  217: 	/* make sure we have allocated enough memory for the window */
  218: 	if (window_size > map->p_size) {
  219: 		map->p = realloc_array(map->p, char, window_size);
  220: 		if (!map->p)
  221: 			out_of_memory("map_ptr");
  222: 		map->p_size = window_size;
  223: 	}
  224: 
  225: 	/* Now try to avoid re-reading any bytes by reusing any bytes from the previous buffer. */
  226: 	if (window_start >= map->p_offset && window_start < map->p_offset + map->p_len
  227: 	 && window_start + window_size >= map->p_offset + map->p_len) {
  228: 		read_start = map->p_offset + map->p_len;
  229: 		read_offset = (int32)(read_start - window_start);
  230: 		read_size = window_size - read_offset;
  231: 		memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
  232: 	} else {
  233: 		read_start = window_start;
  234: 		read_size = window_size;
  235: 		read_offset = 0;
  236: 	}
  237: 
  238: 	if (read_size <= 0) {
  239: 		rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
  240: 			(long)read_size);
  241: 		exit_cleanup(RERR_FILEIO);
  242: 	}
  243: 
  244: 	if (map->p_fd_offset != read_start) {
  245: 		OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
  246: 		if (ret != read_start) {
  247: 			rsyserr(FERROR, errno, "lseek returned %s, not %s",
  248: 				big_num(ret), big_num(read_start));
  249: 			exit_cleanup(RERR_FILEIO);
  250: 		}
  251: 		map->p_fd_offset = read_start;
  252: 	}
  253: 	map->p_offset = window_start;
  254: 	map->p_len = window_size;
  255: 
  256: 	while (read_size > 0) {
  257: 		int32 nread = read(map->fd, map->p + read_offset, read_size);
  258: 		if (nread <= 0) {
  259: 			if (!map->status)
  260: 				map->status = nread ? errno : ENODATA;
  261: 			/* The best we can do is zero the buffer -- the file
  262: 			 * has changed mid transfer! */
  263: 			memset(map->p + read_offset, 0, read_size);
  264: 			break;
  265: 		}
  266: 		map->p_fd_offset += nread;
  267: 		read_offset += nread;
  268: 		read_size -= nread;
  269: 	}
  270: 
  271: 	return map->p + align_fudge;
  272: }
  273: 
  274: 
  275: int unmap_file(struct map_struct *map)
  276: {
  277: 	int	ret;
  278: 
  279: 	if (map->p) {
  280: 		free(map->p);
  281: 		map->p = NULL;
  282: 	}
  283: 	ret = map->status;
  284: 	memset(map, 0, sizeof map[0]);
  285: 	free(map);
  286: 
  287: 	return ret;
  288: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>