~sergei.glushchenko/+junk/page-scan-hack

« back to all changes in this revision

Viewing changes to src/libarchive/contrib/shar/shar.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2008 Jaakko Heinonen
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer
 
10
 *    in this position and unchanged.
 
11
 * 2. Redistributions in binary form must reproduce the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer in the
 
13
 *    documentation and/or other materials provided with the distribution.
 
14
 *
 
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
18
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 */
 
26
 
 
27
#include <sys/cdefs.h>
 
28
#ifdef __FBSDID
 
29
__FBSDID("$FreeBSD$");
 
30
#endif
 
31
 
 
32
#include <sys/stat.h>
 
33
#include <sys/types.h>
 
34
 
 
35
#include <archive.h>
 
36
#include <archive_entry.h>
 
37
#include <assert.h>
 
38
#include <err.h>
 
39
#include <errno.h>
 
40
#include <fcntl.h>
 
41
#include <limits.h>
 
42
#include <stdio.h>
 
43
#include <stdlib.h>
 
44
#include <string.h>
 
45
#include <sysexits.h>
 
46
#include <unistd.h>
 
47
 
 
48
#include "tree.h"
 
49
 
 
50
/* command line options */
 
51
static int      b_opt;  /* use alternative shar binary format */
 
52
static int      r_opt;  /* recurse into subdirectories */
 
53
static char     *o_arg; /* output file name */
 
54
 
 
55
static void
 
56
usage(void)
 
57
{
 
58
        fprintf(stderr, "Usage: shar [-br] [-o filename] file ...\n");
 
59
        exit(EX_USAGE);
 
60
}
 
61
 
 
62
/*
 
63
 * Initialize archive structure and create a shar archive.
 
64
 */
 
65
static struct archive *
 
66
shar_create(void)
 
67
{
 
68
        struct archive *a;
 
69
 
 
70
        if ((a = archive_write_new()) == NULL)
 
71
                errx(EXIT_FAILURE, "%s", archive_error_string(a));
 
72
 
 
73
        if (b_opt)
 
74
                archive_write_set_format_shar_dump(a);
 
75
        else
 
76
                archive_write_set_format_shar(a);
 
77
        archive_write_set_compression_none(a);
 
78
 
 
79
        if (archive_write_open_filename(a, o_arg) != ARCHIVE_OK)
 
80
                errx(EX_CANTCREAT, "%s", archive_error_string(a));
 
81
 
 
82
        return (a);
 
83
}
 
84
 
 
85
/* buffer for file data */
 
86
static char buffer[32768];
 
87
 
 
88
/*
 
89
 * Write file data to an archive entry.
 
90
 */
 
91
static int
 
92
shar_write_entry_data(struct archive *a, const int fd)
 
93
{
 
94
        ssize_t bytes_read, bytes_written;
 
95
 
 
96
        assert(a != NULL);
 
97
        assert(fd >= 0);
 
98
 
 
99
        bytes_read = read(fd, buffer, sizeof(buffer));
 
100
        while (bytes_read != 0) {
 
101
                if (bytes_read < 0) {
 
102
                        archive_set_error(a, errno, "Read failed");
 
103
                        return (ARCHIVE_WARN);
 
104
                }
 
105
                bytes_written = archive_write_data(a, buffer, bytes_read);
 
106
                if (bytes_written < 0)
 
107
                        return (ARCHIVE_WARN);
 
108
                bytes_read = read(fd, buffer, sizeof(buffer));
 
109
        }
 
110
 
 
111
        return (ARCHIVE_OK);
 
112
}
 
113
 
 
114
/*
 
115
 * Write a file to the archive. We have special handling for symbolic links.
 
116
 */
 
117
static int
 
118
shar_write_entry(struct archive *a, const char *pathname, const char *accpath,
 
119
    const struct stat *st)
 
120
{
 
121
        struct archive_entry *entry;
 
122
        int fd = -1;
 
123
        int ret = ARCHIVE_OK;
 
124
 
 
125
        assert(a != NULL);
 
126
        assert(pathname != NULL);
 
127
        assert(accpath != NULL);
 
128
        assert(st != NULL);
 
129
 
 
130
        entry = archive_entry_new();
 
131
 
 
132
        if (S_ISREG(st->st_mode) && st->st_size > 0) {
 
133
                /* regular file */
 
134
                if ((fd = open(accpath, O_RDONLY)) == -1) {
 
135
                        warn("%s", accpath);
 
136
                        ret = ARCHIVE_WARN;
 
137
                        goto out;
 
138
                }
 
139
        } else if (S_ISLNK(st->st_mode)) {
 
140
                /* symbolic link */
 
141
                char lnkbuff[PATH_MAX + 1];
 
142
                int lnklen;
 
143
                if ((lnklen = readlink(accpath, lnkbuff, PATH_MAX)) == -1) {
 
144
                        warn("%s", accpath);
 
145
                        ret = ARCHIVE_WARN;
 
146
                        goto out;
 
147
                }
 
148
                lnkbuff[lnklen] = '\0';
 
149
                archive_entry_set_symlink(entry, lnkbuff);
 
150
        }
 
151
        archive_entry_copy_stat(entry, st);
 
152
        archive_entry_set_pathname(entry, pathname);
 
153
        if (!S_ISREG(st->st_mode) || st->st_size == 0)
 
154
                archive_entry_set_size(entry, 0);
 
155
        if (archive_write_header(a, entry) != ARCHIVE_OK) {
 
156
                warnx("%s: %s", pathname, archive_error_string(a));
 
157
                ret = ARCHIVE_WARN;
 
158
                goto out;
 
159
        }
 
160
        if (fd >= 0) {
 
161
                if ((ret = shar_write_entry_data(a, fd)) != ARCHIVE_OK)
 
162
                        warnx("%s: %s", accpath, archive_error_string(a));
 
163
        }
 
164
out:
 
165
        archive_entry_free(entry);
 
166
        if (fd >= 0)
 
167
                close(fd);
 
168
 
 
169
        return (ret);
 
170
}
 
171
 
 
172
/*
 
173
 * Write singe path to the archive. The path can be a regular file, directory
 
174
 * or device. Symbolic links are followed.
 
175
 */
 
176
static int
 
177
shar_write_path(struct archive *a, const char *pathname)
 
178
{
 
179
        struct stat st;
 
180
 
 
181
        assert(a != NULL);
 
182
        assert(pathname != NULL);
 
183
 
 
184
        if ((stat(pathname, &st)) == -1) {
 
185
                warn("%s", pathname);
 
186
                return (ARCHIVE_WARN);
 
187
        }
 
188
 
 
189
        return (shar_write_entry(a, pathname, pathname, &st));
 
190
}
 
191
 
 
192
/*
 
193
 * Write tree to the archive. If pathname is a symbolic link it will be
 
194
 * followed. Other symbolic links are stored as such to the archive.
 
195
 */
 
196
static int
 
197
shar_write_tree(struct archive *a, const char *pathname)
 
198
{
 
199
        struct tree *t;
 
200
        const struct stat *lst, *st;
 
201
        int error = 0;
 
202
        int tree_ret;
 
203
        int first;
 
204
 
 
205
        assert(a != NULL);
 
206
        assert(pathname != NULL);
 
207
 
 
208
        t = tree_open(pathname);
 
209
        for (first = 1; (tree_ret = tree_next(t)); first = 0) {
 
210
                if (tree_ret == TREE_ERROR_DIR) {
 
211
                        warnx("%s: %s", tree_current_path(t),
 
212
                            strerror(tree_errno(t)));
 
213
                        error = 1;
 
214
                        continue;
 
215
                } else if (tree_ret != TREE_REGULAR)
 
216
                        continue;
 
217
                if ((lst = tree_current_lstat(t)) == NULL) {
 
218
                        warn("%s", tree_current_path(t));
 
219
                        error = 1;
 
220
                        continue;
 
221
                }
 
222
                /*
 
223
                 * If the symlink was given on command line then
 
224
                 * follow it rather than write it as symlink.
 
225
                 */
 
226
                if (first && S_ISLNK(lst->st_mode)) {
 
227
                        if ((st = tree_current_stat(t)) == NULL) {
 
228
                                warn("%s", tree_current_path(t));
 
229
                                error = 1;
 
230
                                continue;
 
231
                        }
 
232
                } else
 
233
                        st = lst;
 
234
 
 
235
                if (shar_write_entry(a, tree_current_path(t),
 
236
                    tree_current_access_path(t), st) != ARCHIVE_OK)
 
237
                        error = 1;
 
238
 
 
239
                tree_descend(t);
 
240
        }
 
241
 
 
242
        tree_close(t);
 
243
 
 
244
        return ((error != 0) ? ARCHIVE_WARN : ARCHIVE_OK);
 
245
}
 
246
 
 
247
/*
 
248
 * Create a shar archive and write files/trees into it.
 
249
 */
 
250
static int
 
251
shar_write(char **fn, size_t nfn)
 
252
{
 
253
        struct archive *a;
 
254
        size_t i;
 
255
        int error = 0;
 
256
 
 
257
        assert(fn != NULL);
 
258
        assert(nfn > 0);
 
259
 
 
260
        a = shar_create();
 
261
 
 
262
        for (i = 0; i < nfn; i++) {
 
263
                if (r_opt) {
 
264
                        if (shar_write_tree(a, fn[i]) !=  ARCHIVE_OK)
 
265
                                error = 1;
 
266
                } else {
 
267
                        if (shar_write_path(a, fn[i]) != ARCHIVE_OK)
 
268
                                error = 1;
 
269
                }
 
270
        }
 
271
 
 
272
        if (archive_write_finish(a) != ARCHIVE_OK)
 
273
                errx(EXIT_FAILURE, "%s", archive_error_string(a));
 
274
 
 
275
        if (error != 0)
 
276
                warnx("Error exit delayed from previous errors.");
 
277
 
 
278
        return (error);
 
279
}
 
280
 
 
281
int
 
282
main(int argc, char **argv)
 
283
{
 
284
        int opt;
 
285
 
 
286
        while ((opt = getopt(argc, argv, "bro:")) != -1) {
 
287
                switch (opt) {
 
288
                case 'b':
 
289
                        b_opt = 1;
 
290
                        break;
 
291
                case 'o':
 
292
                        o_arg = optarg;
 
293
                        break;
 
294
                case 'r':
 
295
                        r_opt = 1;
 
296
                        break;
 
297
                default:
 
298
                        usage();
 
299
                        /* NOTREACHED */
 
300
                }
 
301
        }
 
302
        argc -= optind;
 
303
        argv += optind;
 
304
 
 
305
        if(argc < 1)
 
306
                usage();
 
307
 
 
308
        if (shar_write(argv, argc) != 0)
 
309
                exit(EXIT_FAILURE);
 
310
        else
 
311
                exit(EXIT_SUCCESS);
 
312
        /* NOTREACHED */
 
313
}
 
314