Annotation of embedaddon/rsync/fileio.c, revision 1.1.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>