~cfuhrman/+junk/netbsd-othersrc-trunk

« back to all changes in this revision

Viewing changes to bin/fsu_ecp/fsu_ecp.c

  • Committer: stacktic
  • Date: 2009-03-23 21:04:00 UTC
  • Revision ID: svn-v4:288d5a72-fed7-e111-8680-000c29dcf8fe:trunk:1946
ImportedĀ fs-utilsĀ binaries

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $NetBSD$ */
 
2
 
 
3
/*
 
4
 * Copyright (c) 2008 Arnaud Ysmal.  All Rights Reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
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 ``AS IS'' AND ANY EXPRESS
 
16
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
17
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
18
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
21
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
25
 * SUCH DAMAGE.
 
26
 */
 
27
 
 
28
#include <sys/syslimits.h>
 
29
#include <sys/stat.h>
 
30
 
 
31
#include <dirent.h>
 
32
#include <err.h>
 
33
#include <errno.h>
 
34
#include <fcntl.h>
 
35
#include <getopt.h>
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <string.h>
 
39
#include <unistd.h>
 
40
 
 
41
#include <rump/ukfs.h>
 
42
 
 
43
#include <fsu_mount.h>
 
44
 
 
45
#include "fsu_flist.h"
 
46
 
 
47
#define FSU_ECP_COPY_LINK (0x01)
 
48
#define FSU_ECP_RECURSIVE (FSU_ECP_COPY_LINK<<1)
 
49
#define FSU_ECP_VERBOSE (FSU_ECP_RECURSIVE<<1)
 
50
#define FSU_ECP_GET (FSU_ECP_VERBOSE<<1)
 
51
#define FSU_ECP_PUT (FSU_ECP_GET<<1)
 
52
 
 
53
DECLARE_UKFS(ukfs)
 
54
 
 
55
#define BUFSIZE (8192)
 
56
 
 
57
static int copy_dir(struct ukfs *, const char *, const char *, int);
 
58
static int copy_dir_rec(struct ukfs *, const char *, char *, int);
 
59
static int copy_fifo(struct ukfs *, const char *, const char *, int);
 
60
static int copy_file(struct ukfs *, const char *, const char *, int);
 
61
static int copy_link(struct ukfs *, const char *, const char *, int);
 
62
static int copy_special(struct ukfs *, const char *, const char *, int);
 
63
static int copy_to_dir(struct ukfs *, const char *, struct stat *,
 
64
                       const char *, int);
 
65
static int copy_to_file(struct ukfs *, const char *, struct stat *,
 
66
                        const char *, int);
 
67
static int fsu_ecp(struct ukfs *, const char *, const char *, int);
 
68
static int fsu_ecp_parse_arg(int *, char ***);
 
69
static void usage(void);
 
70
 
 
71
int
 
72
main(int argc, char *argv[])
 
73
{
 
74
        size_t len;
 
75
        int cur_arg, flags, rv;
 
76
 
 
77
        FSU_MOUNT(argc, argv, ukfs);
 
78
 
 
79
        flags = fsu_ecp_parse_arg(&argc, &argv);
 
80
        if (flags == -1 || argc < 2) {
 
81
                usage();
 
82
                return -1;
 
83
        }
 
84
 
 
85
        for (rv = 0, cur_arg = 0; cur_arg < argc-1; ++cur_arg) {
 
86
                len = strlen(argv[cur_arg]);
 
87
                while (argv[cur_arg][--len] == '/')
 
88
                        argv[cur_arg][len] = '\0';
 
89
                rv |= fsu_ecp(ukfs, argv[cur_arg], argv[argc-1], flags);
 
90
        }
 
91
 
 
92
        return rv;
 
93
}
 
94
 
 
95
static int
 
96
fsu_ecp_parse_arg(int *argc, char ***argv)
 
97
{
 
98
        int flags, rv;
 
99
 
 
100
        flags = 0;
 
101
 
 
102
        if (strcmp((*argv)[0], "get") == 0 ||
 
103
            strcmp((*argv)[0], "fsu_get") == 0)
 
104
                flags |= FSU_ECP_GET;
 
105
        else if (strcmp((*argv)[0], "put") == 0 ||
 
106
                 strcmp((*argv)[0], "fsu_put") == 0)
 
107
                flags |= FSU_ECP_PUT;
 
108
 
 
109
        while ((rv = getopt(*argc, *argv, "gPpRv")) != -1) {
 
110
                switch (rv) {
 
111
                case 'g':
 
112
                        flags |= FSU_ECP_GET;
 
113
                        flags &= ~FSU_ECP_PUT;
 
114
                        break;
 
115
                case 'P':
 
116
                        flags |= FSU_ECP_COPY_LINK;
 
117
                        break;
 
118
                case 'p':
 
119
                        flags |= FSU_ECP_PUT;
 
120
                        flags &= ~FSU_ECP_GET;
 
121
                        break;
 
122
                case 'R':
 
123
                        flags |= FSU_ECP_RECURSIVE;
 
124
                        break;
 
125
                case 'v':
 
126
                        flags |= FSU_ECP_VERBOSE;
 
127
                        break;
 
128
                case '?':
 
129
                default:
 
130
                        return -1;
 
131
                }
 
132
        }
 
133
        *argc -= optind;
 
134
        *argv += optind;
 
135
 
 
136
        if ((flags & (FSU_ECP_GET | FSU_ECP_PUT)) == 0) {
 
137
                warnx("-g or -p should be specified");
 
138
                return -1;
 
139
        }
 
140
 
 
141
        return flags;
 
142
}
 
143
 
 
144
static int
 
145
fsu_ecp(struct ukfs *fs, const char *from, const char *to, int flags)
 
146
{
 
147
        struct stat from_stat, to_stat;
 
148
        int rv;
 
149
        
 
150
        if (flags & FSU_ECP_PUT)
 
151
                rv = lstat(from, &from_stat);
 
152
        else
 
153
                rv = ukfs_lstat(fs, from, &from_stat);
 
154
        if (rv == -1) {
 
155
                warn("%s", from);
 
156
                return -1;
 
157
        }
 
158
 
 
159
        if (S_ISDIR(from_stat.st_mode)) {
 
160
                if (!(flags & FSU_ECP_RECURSIVE)) {
 
161
                        fprintf(stderr, "%s: is a directory\n", from);
 
162
                        return -1;
 
163
                }
 
164
                return copy_dir(fs, from, to, flags);
 
165
        }
 
166
 
 
167
        if (flags & FSU_ECP_GET)
 
168
                rv = stat(to, &to_stat);
 
169
        else
 
170
                rv = ukfs_stat(fs, to, &to_stat);
 
171
        if (rv == 0 && S_ISDIR(to_stat.st_mode))
 
172
                return copy_to_dir(fs, from, &from_stat, to, flags);
 
173
 
 
174
        if (from_stat.st_ino == to_stat.st_ino) {
 
175
                fprintf(stderr, "%s and %s are identical (not copied).\n",
 
176
                        from, to);
 
177
                return -1;
 
178
        }
 
179
        return copy_to_file(fs, from, &from_stat, to, flags);
 
180
}
 
181
 
 
182
static int
 
183
copy_dir(struct ukfs *fs, const char *from, const char *to, int flags)
 
184
{
 
185
        const char *filename;
 
186
        int res, rv;
 
187
        struct stat file_stat;
 
188
        char to_p[PATH_MAX + 1];
 
189
        size_t tlen, flen;
 
190
 
 
191
        tlen = strlen(to);
 
192
        rv = strlcpy(to_p, to, PATH_MAX + 1);
 
193
        if (rv != (int)tlen) {
 
194
                warn("%s", to);
 
195
                return -1;
 
196
        }
 
197
        
 
198
        if (flags & FSU_ECP_GET)
 
199
                rv = lstat(to, &file_stat);
 
200
        else
 
201
                rv = ukfs_lstat(fs, to, &file_stat);
 
202
        if (rv == 0) {
 
203
                if (S_ISDIR(file_stat.st_mode)) {
 
204
                        filename = strrchr(from, '/');
 
205
                        if (filename == NULL)
 
206
                                filename = from;
 
207
                        else {
 
208
                                printf("filename = \"%s\"\n", filename);
 
209
                                if (filename[1] == '\0') {
 
210
                                        printf("brdl\n");
 
211
                                        for (rv = strlen(from) - 2;
 
212
                                             rv >= 0 && from[rv] != '/';
 
213
                                             --rv)
 
214
                                                continue;
 
215
                                }
 
216
                                ++filename;
 
217
                        }
 
218
                        
 
219
                        if (to_p[tlen - 1] != '/') {
 
220
                                if (filename[0] != '/') {
 
221
                                        to_p[tlen] = '/';
 
222
                                        to_p[tlen + 1] = '\0';
 
223
                                }
 
224
                        } else
 
225
                                --tlen;
 
226
 
 
227
                        flen = strlen(filename);
 
228
                        
 
229
                        rv = strlcat(to_p, filename, PATH_MAX + 1);
 
230
                        if (rv != (int)(flen + tlen + 1)) {
 
231
                                warn("%s/%s", to_p, filename);
 
232
                                return -1;
 
233
                        }
 
234
                } else {
 
235
                        warnx("%s: not a directory", to);
 
236
                        return -1;
 
237
                }
 
238
        }
 
239
 
 
240
        res = copy_dir_rec(fs, from, to_p, flags);
 
241
 
 
242
        return res;
 
243
}
 
244
 
 
245
static int
 
246
copy_dir_rec(struct ukfs *fs, const char *from_p, char *to_p, int flags)
 
247
{
 
248
        FSU_FENT *root, *cur;
 
249
        size_t len;
 
250
        int flist_options, res, rv, off;
 
251
 
 
252
        res = 0;
 
253
 
 
254
        if (flags & FSU_ECP_COPY_LINK)
 
255
                flist_options = FSU_FLIST_STATLINK;
 
256
        else
 
257
                flist_options = 0;
 
258
 
 
259
        if (flags & FSU_ECP_RECURSIVE)
 
260
                flist_options |= FSU_FLIST_RECURSIVE;
 
261
 
 
262
        if (flags & FSU_ECP_PUT)
 
263
                flist_options |= FSU_FLIST_REALFS;
 
264
 
 
265
        len = strlen(to_p) - 1;
 
266
        
 
267
        root = fsu_flist_build(fs, from_p, flist_options);
 
268
 
 
269
        if (root == NULL)
 
270
                return -1;
 
271
        
 
272
        if (flags & FSU_ECP_GET)
 
273
                rv = mkdir(to_p, root->sb.st_mode);
 
274
        else
 
275
                rv = ukfs_mkdir(fs, to_p, root->sb.st_mode);
 
276
        if (rv == -1) {
 
277
                warn("%s", to_p);
 
278
                goto out;
 
279
        }
 
280
 
 
281
        if (!(flags & FSU_ECP_GET)) {
 
282
                rv = ukfs_chown(fs, to_p, root->sb.st_uid, root->sb.st_gid);
 
283
                if (rv == -1) {
 
284
                        warn("%s", from_p);
 
285
                        goto out;
 
286
                }
 
287
        }
 
288
 
 
289
        off = root->pathlen;
 
290
 
 
291
        for (cur = root->next; cur != NULL; cur = cur->next) {
 
292
                
 
293
                rv = strlcat(to_p, cur->path + off, PATH_MAX+1);
 
294
                if (rv != (int)(len + cur->pathlen - off + 1)) {
 
295
                        warn("%s%s", to_p, cur->path + off);
 
296
                        res = -1;
 
297
                        break;
 
298
                }
 
299
 
 
300
                if (S_ISDIR(cur->sb.st_mode)) {
 
301
                        if (flags & FSU_ECP_GET) {
 
302
                                rv = mkdir(to_p, cur->sb.st_mode);
 
303
                                if (rv == -1) {
 
304
                                        warn("%s", to_p);
 
305
                                        res = -1;
 
306
                                        break;
 
307
                                }
 
308
                        } else {
 
309
                                rv = ukfs_mkdir(fs, to_p, cur->sb.st_mode);
 
310
                                if (rv == -1) {
 
311
                                        warn("%s", to_p);
 
312
                                        res = -1;
 
313
                                        break;
 
314
                                }
 
315
                                
 
316
                                rv = ukfs_chown(fs, to_p, cur->sb.st_uid,
 
317
                                                cur->sb.st_gid);
 
318
                                if (rv == -1) {
 
319
                                        warn("%s", to_p);
 
320
                                        res = -1;
 
321
                                        break;
 
322
                                }
 
323
                        }
 
324
                } else {
 
325
                        res |= copy_to_file(fs, cur->path, &(cur->sb), to_p,
 
326
                                          flags);
 
327
                        if (errno == ENOSPC) {
 
328
                                warn(NULL);
 
329
                                goto out;
 
330
                        }
 
331
                }
 
332
                to_p[len + 1] = '\0';
 
333
        }
 
334
        
 
335
out:
 
336
        fsu_flist_free(root);
 
337
 
 
338
        return res;
 
339
}
 
340
 
 
341
static int
 
342
copy_to_dir(struct ukfs *fs, const char *from, struct stat *frstat,
 
343
            const char *to, int flags)
 
344
{
 
345
        char path[PATH_MAX+1];
 
346
        const char *filename;
 
347
        int len;
 
348
 
 
349
        filename = strrchr(from, '/');
 
350
        if (filename == NULL)
 
351
                filename = from;
 
352
        else
 
353
                ++filename;
 
354
 
 
355
        len = snprintf(path, PATH_MAX, "%s/%s", to, filename);
 
356
        path[len] = '\0';
 
357
 
 
358
        return copy_to_file(fs, from, frstat, path, flags);
 
359
}
 
360
 
 
361
static int
 
362
copy_to_file(struct ukfs *fs, const char *from, struct stat *frstat,
 
363
             const char *to, int flags)
 
364
{
 
365
        int rv;
 
366
 
 
367
        switch ((frstat->st_mode & S_IFMT)) {
 
368
        case S_IFIFO:
 
369
                rv = copy_fifo(fs, from, to, flags);
 
370
                break;
 
371
        case S_IFLNK:
 
372
                if (flags & FSU_ECP_COPY_LINK)
 
373
                        rv = copy_link(fs, from, to, flags);
 
374
                else
 
375
                        rv = copy_file(fs, from, to, flags);
 
376
                break;
 
377
        case S_IFCHR: /* FALLTHROUGH */
 
378
        case S_IFBLK:
 
379
                rv = copy_special(fs, from, to, flags);
 
380
                break;
 
381
        case S_IFREG:
 
382
                rv = copy_file(fs, from, to, flags);
 
383
                break;
 
384
        default:
 
385
                return -1;
 
386
                /* NOTREACHED */
 
387
        }
 
388
 
 
389
        if (rv != 0)
 
390
                return -1;
 
391
 
 
392
        if (flags & FSU_ECP_GET)
 
393
                return rv;
 
394
 
 
395
        if (flags & FSU_ECP_COPY_LINK)
 
396
                rv = ukfs_lchown(fs, to, frstat->st_uid, frstat->st_gid);
 
397
        else
 
398
                rv = ukfs_chown(fs, to, frstat->st_uid, frstat->st_gid);
 
399
        if (rv == -1) {
 
400
                warn("%s", to);
 
401
                return -1;
 
402
        }
 
403
 
 
404
        return 0;
 
405
}
 
406
 
 
407
static int
 
408
copy_file(struct ukfs *fs, const char *from, const char *to, int flags)
 
409
{
 
410
        uint8_t buf[BUFSIZE];
 
411
        ssize_t rd, wr;
 
412
        off_t off;
 
413
        int fd, rv;
 
414
        struct stat from_stat;
 
415
 
 
416
        fd = -1;
 
417
 
 
418
        if (flags & FSU_ECP_VERBOSE)
 
419
                printf("%s -> %s\n", from, to);
 
420
 
 
421
        if (flags & FSU_ECP_PUT)
 
422
                rv = stat(from, &from_stat);
 
423
        else
 
424
                rv = ukfs_stat(fs, from, &from_stat);
 
425
        if (rv == -1) {
 
426
                warn("%s", from);
 
427
                return -1;
 
428
        }
 
429
 
 
430
        if (flags & FSU_ECP_GET) {
 
431
                rv = open(to, O_WRONLY|O_CREAT|O_EXCL, 0777);
 
432
                fd = rv;
 
433
        } else if (flags & FSU_ECP_PUT) {
 
434
                rv = open(from, O_RDONLY, from_stat.st_mode);
 
435
                fd = rv;
 
436
                rv = ukfs_create(fs, to, from_stat.st_mode);
 
437
        } else {
 
438
                rv = ukfs_create(fs, to, from_stat.st_mode);
 
439
        }
 
440
        if (rv == -1) {
 
441
                warn("%s", to);
 
442
                return -1;
 
443
        }
 
444
        
 
445
        off = 0;
 
446
        do {
 
447
                if (flags & FSU_ECP_PUT)
 
448
                        rd = read(fd, buf, BUFSIZE);
 
449
                else
 
450
                        rd = ukfs_read(fs, from, off, buf, BUFSIZE);
 
451
                if (rd == -1) {
 
452
                        warn("%s", from);
 
453
                        rv = -1;
 
454
                        goto out;
 
455
                }
 
456
                if (flags & FSU_ECP_GET)
 
457
                        wr = write(fd, buf, rd);
 
458
                else
 
459
                        wr = ukfs_write(fs, to, off, buf, rd);
 
460
                if (wr == -1 || wr != rd) {
 
461
                        warn("%s", to);
 
462
                        rv = -1;
 
463
                        goto out;
 
464
                }
 
465
                off += rd;
 
466
        } while (rd == BUFSIZE);
 
467
 
 
468
        rv = 0;
 
469
out:
 
470
        if (flags & (FSU_ECP_GET | FSU_ECP_PUT))
 
471
                close(fd);
 
472
        return rv;
 
473
 
 
474
}
 
475
 
 
476
static int
 
477
copy_fifo(struct ukfs *fs, const char *from, const char *to, int flags)
 
478
{
 
479
        int rv;
 
480
        struct stat file_stat;
 
481
 
 
482
        if (flags & FSU_ECP_VERBOSE)
 
483
                printf("Copying fifo %s -> %s\n", from, to);
 
484
 
 
485
        if (flags & FSU_ECP_GET)
 
486
                rv = lstat(to, &file_stat);
 
487
        else
 
488
                rv = ukfs_lstat(fs, to, &file_stat);
 
489
        if (rv != -1) {
 
490
                if (flags & FSU_ECP_GET)
 
491
                        rv = remove(to);
 
492
                else
 
493
                        rv = ukfs_remove(fs, to);
 
494
                if (rv == -1) {
 
495
                        warn("%s", to);
 
496
                        return -1;
 
497
                }
 
498
        }
 
499
 
 
500
        if (flags & FSU_ECP_PUT)
 
501
                rv = lstat(from, &file_stat);
 
502
        else
 
503
                rv = ukfs_lstat(fs, from, &file_stat);
 
504
        if (rv == -1) {
 
505
                warn("%s", from);
 
506
                return -1;
 
507
        }
 
508
 
 
509
        if (flags & FSU_ECP_GET)
 
510
                rv = mkfifo(to, file_stat.st_mode);
 
511
        else
 
512
                rv = ukfs_mkfifo(fs, to, file_stat.st_mode);
 
513
        if (rv == -1) {
 
514
                warn("%s", to);
 
515
                return -1;
 
516
        }
 
517
        
 
518
        return 0;
 
519
}
 
520
 
 
521
static int
 
522
copy_special(struct ukfs *fs, const char *from, const char *to, int flags)
 
523
{
 
524
        int rv;
 
525
        struct stat file_stat;
 
526
 
 
527
        if (flags & FSU_ECP_VERBOSE)
 
528
                printf("%s -> %s\n", from, to);
 
529
 
 
530
        if (flags & FSU_ECP_GET)
 
531
                rv = lstat(to, &file_stat);
 
532
        else
 
533
                rv = ukfs_lstat(fs, to, &file_stat);
 
534
        if (rv != -1) {
 
535
                rv = ukfs_remove(fs, to);
 
536
                if (rv == -1) {
 
537
                        warn("%s", to);
 
538
                        return -1;
 
539
                }
 
540
        }
 
541
 
 
542
        if (flags & FSU_ECP_PUT)
 
543
                rv = lstat(from, &file_stat);
 
544
        else
 
545
                rv = ukfs_lstat(fs, from, &file_stat);
 
546
        if (rv == -1) {
 
547
                warn("%s", from);
 
548
                return -1;
 
549
        }
 
550
 
 
551
        if (flags & FSU_ECP_GET)
 
552
                rv = mknod(to, file_stat.st_mode, file_stat.st_rdev);
 
553
        else
 
554
                rv = ukfs_mknod(fs, to, file_stat.st_mode, file_stat.st_rdev);
 
555
        if (rv == -1) {
 
556
                warn("%s", to);
 
557
                return -1;
 
558
        }
 
559
        
 
560
        return 0;
 
561
}
 
562
 
 
563
static int
 
564
copy_link(struct ukfs *fs, const char *from, const char *to, int flags)
 
565
{
 
566
        char target[PATH_MAX+1];
 
567
        int rv;
 
568
        struct stat file_stat;
 
569
 
 
570
        if (flags & FSU_ECP_PUT)
 
571
                rv = readlink(from, target, PATH_MAX);
 
572
        else
 
573
                rv = ukfs_readlink(fs, from, target, PATH_MAX);
 
574
        if (rv == -1) {
 
575
                warn("%s", from);
 
576
                return -1;
 
577
        }
 
578
        target[rv] = '\0';
 
579
 
 
580
        if (flags & FSU_ECP_VERBOSE)
 
581
                printf("%s -> %s : %s", from, to, target);
 
582
 
 
583
        if (flags & FSU_ECP_GET)
 
584
                rv = lstat(to, &file_stat);
 
585
        else
 
586
                rv = ukfs_lstat(fs, to, &file_stat);
 
587
        if (rv != -1) {
 
588
                if (flags & FSU_ECP_GET)
 
589
                        rv = remove(to);
 
590
                else
 
591
                        rv = ukfs_remove(fs, to);
 
592
                if (rv == -1) {
 
593
                        warn("%s", to);
 
594
                        return -1;
 
595
                }
 
596
        }
 
597
 
 
598
        if (flags & FSU_ECP_GET)
 
599
                rv = symlink(target, to);
 
600
        else
 
601
                rv = ukfs_symlink(fs, target, to);
 
602
        if (rv == -1) {
 
603
                warn("%s", target);
 
604
                return -1;
 
605
        }
 
606
        return 0;
 
607
}
 
608
 
 
609
static void
 
610
usage(void)
 
611
{
 
612
 
 
613
        fprintf(stderr, "usage: %s %s [-gPpRv] src target\n"
 
614
                "usage: %s %s [-gPpRv] src... directory\n",
 
615
                getprogname(), fsu_mount_usage(),
 
616
                getprogname(), fsu_mount_usage());
 
617
 
 
618
        exit(EXIT_FAILURE);
 
619
}