File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / fileio.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: rsync3_0_9p0, RSYNC3_0_9, HEAD
rsync

    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>