Annotation of embedaddon/rsync/fileio.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * File IO utilities used in rsync.
                      3:  *
                      4:  * Copyright (C) 1998 Andrew Tridgell
                      5:  * Copyright (C) 2002 Martin Pool
1.1.1.2 ! misho       6:  * Copyright (C) 2004-2013 Wayne Davison
1.1       misho       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"
1.1.1.2 ! misho      23: #include "inums.h"
1.1       misho      24: 
                     25: #ifndef ENODATA
                     26: #define ENODATA EAGAIN
                     27: #endif
                     28: 
1.1.1.2 ! misho      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: 
1.1       misho      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;
1.1.1.2 ! misho      87:                sparse_seek = 0;
1.1       misho      88:                return ret;
                     89:        }
                     90: 
1.1.1.2 ! misho      91:        if (ret != (int)(len - (l1+l2))) {
        !            92:                sparse_seek = 0;
1.1       misho      93:                return l1+ret;
1.1.1.2 ! misho      94:        }
1.1       misho      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. */
1.1.1.2 ! misho     172: struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size)
1.1       misho     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;
1.1.1.2 ! misho     184:        map->def_window_size = ALIGNED_LENGTH(read_size);
1.1       misho     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;
1.1.1.2 ! misho     194:        int32 window_size, read_size, read_offset, align_fudge;
1.1       misho     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 */
1.1.1.2 ! misho     209:        align_fudge = (int32)ALIGNED_OVERSHOOT(offset);
        !           210:        window_start = offset - align_fudge;
1.1       misho     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);
1.1.1.2 ! misho     214:        if (window_size < len + align_fudge)
        !           215:                window_size = ALIGNED_LENGTH(len + align_fudge);
1.1       misho     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: 
1.1.1.2 ! misho     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) {
1.1       misho     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) {
1.1.1.2 ! misho     247:                        rsyserr(FERROR, errno, "lseek returned %s, not %s",
        !           248:                                big_num(ret), big_num(read_start));
1.1       misho     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) {
1.1.1.2 ! misho     257:                int32 nread = read(map->fd, map->p + read_offset, read_size);
1.1       misho     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: 
1.1.1.2 ! misho     271:        return map->p + align_fudge;
1.1       misho     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>