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>