4
* Copyright (c) 2008 Arnaud Ysmal. All Rights Reserved.
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
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.
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
28
#include <sys/syslimits.h>
41
#include <rump/ukfs.h>
43
#include <fsu_mount.h>
45
#include "fsu_flist.h"
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)
55
#define BUFSIZE (8192)
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 *,
65
static int copy_to_file(struct ukfs *, const char *, struct stat *,
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);
72
main(int argc, char *argv[])
75
int cur_arg, flags, rv;
77
FSU_MOUNT(argc, argv, ukfs);
79
flags = fsu_ecp_parse_arg(&argc, &argv);
80
if (flags == -1 || argc < 2) {
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);
96
fsu_ecp_parse_arg(int *argc, char ***argv)
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;
109
while ((rv = getopt(*argc, *argv, "gPpRv")) != -1) {
112
flags |= FSU_ECP_GET;
113
flags &= ~FSU_ECP_PUT;
116
flags |= FSU_ECP_COPY_LINK;
119
flags |= FSU_ECP_PUT;
120
flags &= ~FSU_ECP_GET;
123
flags |= FSU_ECP_RECURSIVE;
126
flags |= FSU_ECP_VERBOSE;
136
if ((flags & (FSU_ECP_GET | FSU_ECP_PUT)) == 0) {
137
warnx("-g or -p should be specified");
145
fsu_ecp(struct ukfs *fs, const char *from, const char *to, int flags)
147
struct stat from_stat, to_stat;
150
if (flags & FSU_ECP_PUT)
151
rv = lstat(from, &from_stat);
153
rv = ukfs_lstat(fs, from, &from_stat);
159
if (S_ISDIR(from_stat.st_mode)) {
160
if (!(flags & FSU_ECP_RECURSIVE)) {
161
fprintf(stderr, "%s: is a directory\n", from);
164
return copy_dir(fs, from, to, flags);
167
if (flags & FSU_ECP_GET)
168
rv = stat(to, &to_stat);
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);
174
if (from_stat.st_ino == to_stat.st_ino) {
175
fprintf(stderr, "%s and %s are identical (not copied).\n",
179
return copy_to_file(fs, from, &from_stat, to, flags);
183
copy_dir(struct ukfs *fs, const char *from, const char *to, int flags)
185
const char *filename;
187
struct stat file_stat;
188
char to_p[PATH_MAX + 1];
192
rv = strlcpy(to_p, to, PATH_MAX + 1);
193
if (rv != (int)tlen) {
198
if (flags & FSU_ECP_GET)
199
rv = lstat(to, &file_stat);
201
rv = ukfs_lstat(fs, to, &file_stat);
203
if (S_ISDIR(file_stat.st_mode)) {
204
filename = strrchr(from, '/');
205
if (filename == NULL)
208
printf("filename = \"%s\"\n", filename);
209
if (filename[1] == '\0') {
211
for (rv = strlen(from) - 2;
212
rv >= 0 && from[rv] != '/';
219
if (to_p[tlen - 1] != '/') {
220
if (filename[0] != '/') {
222
to_p[tlen + 1] = '\0';
227
flen = strlen(filename);
229
rv = strlcat(to_p, filename, PATH_MAX + 1);
230
if (rv != (int)(flen + tlen + 1)) {
231
warn("%s/%s", to_p, filename);
235
warnx("%s: not a directory", to);
240
res = copy_dir_rec(fs, from, to_p, flags);
246
copy_dir_rec(struct ukfs *fs, const char *from_p, char *to_p, int flags)
248
FSU_FENT *root, *cur;
250
int flist_options, res, rv, off;
254
if (flags & FSU_ECP_COPY_LINK)
255
flist_options = FSU_FLIST_STATLINK;
259
if (flags & FSU_ECP_RECURSIVE)
260
flist_options |= FSU_FLIST_RECURSIVE;
262
if (flags & FSU_ECP_PUT)
263
flist_options |= FSU_FLIST_REALFS;
265
len = strlen(to_p) - 1;
267
root = fsu_flist_build(fs, from_p, flist_options);
272
if (flags & FSU_ECP_GET)
273
rv = mkdir(to_p, root->sb.st_mode);
275
rv = ukfs_mkdir(fs, to_p, root->sb.st_mode);
281
if (!(flags & FSU_ECP_GET)) {
282
rv = ukfs_chown(fs, to_p, root->sb.st_uid, root->sb.st_gid);
291
for (cur = root->next; cur != NULL; cur = cur->next) {
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);
300
if (S_ISDIR(cur->sb.st_mode)) {
301
if (flags & FSU_ECP_GET) {
302
rv = mkdir(to_p, cur->sb.st_mode);
309
rv = ukfs_mkdir(fs, to_p, cur->sb.st_mode);
316
rv = ukfs_chown(fs, to_p, cur->sb.st_uid,
325
res |= copy_to_file(fs, cur->path, &(cur->sb), to_p,
327
if (errno == ENOSPC) {
332
to_p[len + 1] = '\0';
336
fsu_flist_free(root);
342
copy_to_dir(struct ukfs *fs, const char *from, struct stat *frstat,
343
const char *to, int flags)
345
char path[PATH_MAX+1];
346
const char *filename;
349
filename = strrchr(from, '/');
350
if (filename == NULL)
355
len = snprintf(path, PATH_MAX, "%s/%s", to, filename);
358
return copy_to_file(fs, from, frstat, path, flags);
362
copy_to_file(struct ukfs *fs, const char *from, struct stat *frstat,
363
const char *to, int flags)
367
switch ((frstat->st_mode & S_IFMT)) {
369
rv = copy_fifo(fs, from, to, flags);
372
if (flags & FSU_ECP_COPY_LINK)
373
rv = copy_link(fs, from, to, flags);
375
rv = copy_file(fs, from, to, flags);
377
case S_IFCHR: /* FALLTHROUGH */
379
rv = copy_special(fs, from, to, flags);
382
rv = copy_file(fs, from, to, flags);
392
if (flags & FSU_ECP_GET)
395
if (flags & FSU_ECP_COPY_LINK)
396
rv = ukfs_lchown(fs, to, frstat->st_uid, frstat->st_gid);
398
rv = ukfs_chown(fs, to, frstat->st_uid, frstat->st_gid);
408
copy_file(struct ukfs *fs, const char *from, const char *to, int flags)
410
uint8_t buf[BUFSIZE];
414
struct stat from_stat;
418
if (flags & FSU_ECP_VERBOSE)
419
printf("%s -> %s\n", from, to);
421
if (flags & FSU_ECP_PUT)
422
rv = stat(from, &from_stat);
424
rv = ukfs_stat(fs, from, &from_stat);
430
if (flags & FSU_ECP_GET) {
431
rv = open(to, O_WRONLY|O_CREAT|O_EXCL, 0777);
433
} else if (flags & FSU_ECP_PUT) {
434
rv = open(from, O_RDONLY, from_stat.st_mode);
436
rv = ukfs_create(fs, to, from_stat.st_mode);
438
rv = ukfs_create(fs, to, from_stat.st_mode);
447
if (flags & FSU_ECP_PUT)
448
rd = read(fd, buf, BUFSIZE);
450
rd = ukfs_read(fs, from, off, buf, BUFSIZE);
456
if (flags & FSU_ECP_GET)
457
wr = write(fd, buf, rd);
459
wr = ukfs_write(fs, to, off, buf, rd);
460
if (wr == -1 || wr != rd) {
466
} while (rd == BUFSIZE);
470
if (flags & (FSU_ECP_GET | FSU_ECP_PUT))
477
copy_fifo(struct ukfs *fs, const char *from, const char *to, int flags)
480
struct stat file_stat;
482
if (flags & FSU_ECP_VERBOSE)
483
printf("Copying fifo %s -> %s\n", from, to);
485
if (flags & FSU_ECP_GET)
486
rv = lstat(to, &file_stat);
488
rv = ukfs_lstat(fs, to, &file_stat);
490
if (flags & FSU_ECP_GET)
493
rv = ukfs_remove(fs, to);
500
if (flags & FSU_ECP_PUT)
501
rv = lstat(from, &file_stat);
503
rv = ukfs_lstat(fs, from, &file_stat);
509
if (flags & FSU_ECP_GET)
510
rv = mkfifo(to, file_stat.st_mode);
512
rv = ukfs_mkfifo(fs, to, file_stat.st_mode);
522
copy_special(struct ukfs *fs, const char *from, const char *to, int flags)
525
struct stat file_stat;
527
if (flags & FSU_ECP_VERBOSE)
528
printf("%s -> %s\n", from, to);
530
if (flags & FSU_ECP_GET)
531
rv = lstat(to, &file_stat);
533
rv = ukfs_lstat(fs, to, &file_stat);
535
rv = ukfs_remove(fs, to);
542
if (flags & FSU_ECP_PUT)
543
rv = lstat(from, &file_stat);
545
rv = ukfs_lstat(fs, from, &file_stat);
551
if (flags & FSU_ECP_GET)
552
rv = mknod(to, file_stat.st_mode, file_stat.st_rdev);
554
rv = ukfs_mknod(fs, to, file_stat.st_mode, file_stat.st_rdev);
564
copy_link(struct ukfs *fs, const char *from, const char *to, int flags)
566
char target[PATH_MAX+1];
568
struct stat file_stat;
570
if (flags & FSU_ECP_PUT)
571
rv = readlink(from, target, PATH_MAX);
573
rv = ukfs_readlink(fs, from, target, PATH_MAX);
580
if (flags & FSU_ECP_VERBOSE)
581
printf("%s -> %s : %s", from, to, target);
583
if (flags & FSU_ECP_GET)
584
rv = lstat(to, &file_stat);
586
rv = ukfs_lstat(fs, to, &file_stat);
588
if (flags & FSU_ECP_GET)
591
rv = ukfs_remove(fs, to);
598
if (flags & FSU_ECP_GET)
599
rv = symlink(target, to);
601
rv = ukfs_symlink(fs, target, to);
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());