~ubuntu-branches/ubuntu/raring/cmake/raring

« back to all changes in this revision

Viewing changes to Utilities/cmlibarchive/libarchive/archive_read_open_fd.c

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2012-04-30 12:14:32 UTC
  • mfrom: (3.1.30 sid)
  • Revision ID: package-import@ubuntu.com-20120430121432-rqh2fjl3zcblehh5
Tags: 2.8.8-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add xfail_compiler_flag.diff: Mark compiler flag tests as expected
    failures.
  - Add ubuntu_qt_import_dir_variable.diff: define QT_IMPORTS_DIR even
    when that dir does not exist.
* Remove increase_ctest_test_timeout.diff, merged upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
 */
25
25
 
26
26
#include "archive_platform.h"
27
 
__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_fd.c,v 1.13 2007/06/26 03:06:48 kientzle Exp $");
 
27
__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_fd.c 201103 2009-12-28 03:13:49Z kientzle $");
28
28
 
29
29
#ifdef HAVE_SYS_STAT_H
30
30
#include <sys/stat.h>
51
51
#include "archive.h"
52
52
 
53
53
struct read_fd_data {
54
 
    int  fd;
55
 
    size_t   block_size;
56
 
    char     can_skip;
57
 
    void    *buffer;
 
54
        int      fd;
 
55
        size_t   block_size;
 
56
        char     use_lseek;
 
57
        void    *buffer;
58
58
};
59
59
 
60
 
static int  file_close(struct archive *, void *);
61
 
static ssize_t  file_read(struct archive *, void *, const void **buff);
62
 
#if ARCHIVE_API_VERSION < 2
63
 
static ssize_t  file_skip(struct archive *, void *, size_t request);
64
 
#else
65
 
static off_t    file_skip(struct archive *, void *, off_t request);
66
 
#endif
 
60
static int      file_close(struct archive *, void *);
 
61
static ssize_t  file_read(struct archive *, void *, const void **buff);
 
62
static int64_t  file_skip(struct archive *, void *, int64_t request);
67
63
 
68
64
int
69
65
archive_read_open_fd(struct archive *a, int fd, size_t block_size)
70
66
{
71
 
    struct stat st;
72
 
    struct read_fd_data *mine;
73
 
    void *b;
74
 
 
75
 
    archive_clear_error(a);
76
 
    if (fstat(fd, &st) != 0) {
77
 
        archive_set_error(a, errno, "Can't stat fd %d", fd);
78
 
        return (ARCHIVE_FATAL);
79
 
    }
80
 
 
81
 
    mine = (struct read_fd_data *)malloc(sizeof(*mine));
82
 
    b = malloc(block_size);
83
 
    if (mine == NULL || b == NULL) {
84
 
        archive_set_error(a, ENOMEM, "No memory");
85
 
        free(mine);
86
 
        free(b);
87
 
        return (ARCHIVE_FATAL);
88
 
    }
89
 
    mine->block_size = block_size;
90
 
    mine->buffer = b;
91
 
    mine->fd = fd;
92
 
    /*
93
 
     * Skip support is a performance optimization for anything
94
 
     * that supports lseek().  On FreeBSD, only regular files and
95
 
     * raw disk devices support lseek() and there's no portable
96
 
     * way to determine if a device is a raw disk device, so we
97
 
     * only enable this optimization for regular files.
98
 
     */
99
 
    if (S_ISREG(st.st_mode)) {
100
 
        archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
101
 
        mine->can_skip = 1;
102
 
    } else
103
 
        mine->can_skip = 0;
104
 
#if defined(__CYGWIN__) || defined(__BORLANDC__)
105
 
    setmode(mine->fd, O_BINARY);
106
 
#elif defined(_WIN32)
107
 
    _setmode(mine->fd, _O_BINARY);
 
67
        struct stat st;
 
68
        struct read_fd_data *mine;
 
69
        void *b;
 
70
 
 
71
        archive_clear_error(a);
 
72
        if (fstat(fd, &st) != 0) {
 
73
                archive_set_error(a, errno, "Can't stat fd %d", fd);
 
74
                return (ARCHIVE_FATAL);
 
75
        }
 
76
 
 
77
        mine = (struct read_fd_data *)calloc(1, sizeof(*mine));
 
78
        b = malloc(block_size);
 
79
        if (mine == NULL || b == NULL) {
 
80
                archive_set_error(a, ENOMEM, "No memory");
 
81
                free(mine);
 
82
                free(b);
 
83
                return (ARCHIVE_FATAL);
 
84
        }
 
85
        mine->block_size = block_size;
 
86
        mine->buffer = b;
 
87
        mine->fd = fd;
 
88
        /*
 
89
         * Skip support is a performance optimization for anything
 
90
         * that supports lseek().  On FreeBSD, only regular files and
 
91
         * raw disk devices support lseek() and there's no portable
 
92
         * way to determine if a device is a raw disk device, so we
 
93
         * only enable this optimization for regular files.
 
94
         */
 
95
        if (S_ISREG(st.st_mode)) {
 
96
                archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
 
97
                mine->use_lseek = 1;
 
98
        }
 
99
#if defined(__CYGWIN__) || defined(_WIN32)
 
100
        setmode(mine->fd, O_BINARY);
108
101
#endif
109
102
 
110
 
    return (archive_read_open2(a, mine,
111
 
        NULL, file_read, file_skip, file_close));
 
103
        archive_read_set_read_callback(a, file_read);
 
104
        archive_read_set_skip_callback(a, file_skip);
 
105
        archive_read_set_close_callback(a, file_close);
 
106
        archive_read_set_callback_data(a, mine);
 
107
        return (archive_read_open1(a));
112
108
}
113
109
 
114
110
static ssize_t
115
111
file_read(struct archive *a, void *client_data, const void **buff)
116
112
{
117
 
    struct read_fd_data *mine = (struct read_fd_data *)client_data;
118
 
    ssize_t bytes_read;
 
113
        struct read_fd_data *mine = (struct read_fd_data *)client_data;
 
114
        ssize_t bytes_read;
119
115
 
120
 
    *buff = mine->buffer;
121
 
    bytes_read = read(mine->fd, mine->buffer, mine->block_size);
122
 
    if (bytes_read < 0) {
123
 
        archive_set_error(a, errno, "Error reading fd %d", mine->fd);
124
 
    }
125
 
    return (bytes_read);
 
116
        *buff = mine->buffer;
 
117
        for (;;) {
 
118
                bytes_read = read(mine->fd, mine->buffer, mine->block_size);
 
119
                if (bytes_read < 0) {
 
120
                        if (errno == EINTR)
 
121
                                continue;
 
122
                        archive_set_error(a, errno, "Error reading fd %d", mine->fd);
 
123
                }
 
124
                return (bytes_read);
 
125
        }
126
126
}
127
127
 
128
 
#if ARCHIVE_API_VERSION < 2
129
 
static ssize_t
130
 
file_skip(struct archive *a, void *client_data, size_t request)
131
 
#else
132
 
static off_t
133
 
file_skip(struct archive *a, void *client_data, off_t request)
134
 
#endif
 
128
static int64_t
 
129
file_skip(struct archive *a, void *client_data, int64_t request)
135
130
{
136
 
    struct read_fd_data *mine = (struct read_fd_data *)client_data;
137
 
    off_t old_offset, new_offset;
138
 
 
139
 
    if (!mine->can_skip)
140
 
        return (0);
141
 
 
142
 
    /* Reduce request to the next smallest multiple of block_size */
143
 
    request = (request / mine->block_size) * mine->block_size;
144
 
    if (request == 0)
145
 
        return (0);
146
 
 
147
 
    /*
148
 
     * Hurray for lazy evaluation: if the first lseek fails, the second
149
 
     * one will not be executed.
150
 
     */
151
 
    if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
152
 
        ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
153
 
    {
154
 
        /* If seek failed once, it will probably fail again. */
155
 
        mine->can_skip = 0;
156
 
 
157
 
        if (errno == ESPIPE)
158
 
        {
159
 
            /*
160
 
             * Failure to lseek() can be caused by the file
161
 
             * descriptor pointing to a pipe, socket or FIFO.
162
 
             * Return 0 here, so the compression layer will use
163
 
             * read()s instead to advance the file descriptor.
164
 
             * It's slower of course, but works as well.
165
 
             */
166
 
            return (0);
167
 
        }
168
 
        /*
169
 
         * There's been an error other than ESPIPE. This is most
170
 
         * likely caused by a programmer error (too large request)
171
 
         * or a corrupted archive file.
172
 
         */
173
 
        archive_set_error(a, errno, "Error seeking");
174
 
        return (-1);
175
 
    }
176
 
    return (new_offset - old_offset);
 
131
        struct read_fd_data *mine = (struct read_fd_data *)client_data;
 
132
        off_t skip = (off_t)request;
 
133
        off_t old_offset, new_offset;
 
134
        int skip_bits = sizeof(skip) * 8 - 1;  /* off_t is a signed type. */
 
135
 
 
136
        if (!mine->use_lseek)
 
137
                return (0);
 
138
 
 
139
        /* Reduce a request that would overflow the 'skip' variable. */
 
140
        if (sizeof(request) > sizeof(skip)) {
 
141
                int64_t max_skip =
 
142
                    (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
 
143
                if (request > max_skip)
 
144
                        skip = max_skip;
 
145
        }
 
146
 
 
147
        /* Reduce request to the next smallest multiple of block_size */
 
148
        request = (request / mine->block_size) * mine->block_size;
 
149
        if (request == 0)
 
150
                return (0);
 
151
 
 
152
        if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) &&
 
153
            ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0))
 
154
                return (new_offset - old_offset);
 
155
 
 
156
        /* If seek failed once, it will probably fail again. */
 
157
        mine->use_lseek = 0;
 
158
 
 
159
        /* Let libarchive recover with read+discard. */
 
160
        if (errno == ESPIPE)
 
161
                return (0);
 
162
 
 
163
        /*
 
164
         * There's been an error other than ESPIPE. This is most
 
165
         * likely caused by a programmer error (too large request)
 
166
         * or a corrupted archive file.
 
167
         */
 
168
        archive_set_error(a, errno, "Error seeking");
 
169
        return (-1);
177
170
}
178
171
 
179
172
static int
180
173
file_close(struct archive *a, void *client_data)
181
174
{
182
 
    struct read_fd_data *mine = (struct read_fd_data *)client_data;
 
175
        struct read_fd_data *mine = (struct read_fd_data *)client_data;
183
176
 
184
 
    (void)a; /* UNUSED */
185
 
    free(mine->buffer);
186
 
    free(mine);
187
 
    return (ARCHIVE_OK);
 
177
        (void)a; /* UNUSED */
 
178
        free(mine->buffer);
 
179
        free(mine);
 
180
        return (ARCHIVE_OK);
188
181
}