X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=bin%2Fad%2Fad_cp.c;h=ef995ce8cf3f159c6346a5e32a4858e9cfad8948;hb=253027f8607b535a682d0972b323bacb4750e4ed;hp=dfb2b7362d788010ea3bff61871ab10b5d8fd8b7;hpb=869777e486e0cf24c3cef64b57765a18c0c227de;p=netatalk.git diff --git a/bin/ad/ad_cp.c b/bin/ad/ad_cp.c index dfb2b736..ef995ce8 100644 --- a/bin/ad/ad_cp.c +++ b/bin/ad/ad_cp.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -66,11 +67,10 @@ #include #include #include -#include #include #include #include - + #include "ad.h" #define STRIP_TRAILING_SLASH(p) { \ @@ -83,7 +83,7 @@ static char emptystring[] = ""; PATH_T to = { to.p_path, emptystring, "" }; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; -int fflag, iflag, lflag, nflag, pflag, vflag; +int fflag, iflag, nflag, pflag, vflag; mode_t mask; cnid_t ppdid, pdid, did; /* current dir CNID and parent did*/ @@ -91,7 +91,7 @@ cnid_t ppdid, pdid, did; /* current dir CNID and parent did*/ static afpvol_t svolume, dvolume; static enum op type; static int Rflag; -volatile sig_atomic_t sigint; +static volatile sig_atomic_t alarmed; static int badcp, rval; static int ftw_options = FTW_MOUNT | FTW_PHYS | FTW_ACTIONRETVAL; @@ -104,7 +104,6 @@ static char *netatalk_dirs[] = { /* Forward declarations */ static int copy(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf); -static void siginfo(int _U_); static int ftw_copy_file(const struct FTW *, const char *, const struct stat *, int); static int ftw_copy_link(const struct FTW *, const char *, const struct stat *, int); static int setfile(const struct stat *, int); @@ -132,16 +131,87 @@ static void upfunc(void) pdid = ppdid; } +/* + SIGNAL handling: + catch SIGINT and SIGTERM which cause clean exit. Ignore anything else. +*/ + +static void sig_handler(int signo) +{ + alarmed = 1; + return; +} + +static void set_signal(void) +{ + struct sigaction sv; + + sv.sa_handler = sig_handler; + sv.sa_flags = SA_RESTART; + sigemptyset(&sv.sa_mask); + if (sigaction(SIGTERM, &sv, NULL) < 0) + ERROR("error in sigaction(SIGTERM): %s", strerror(errno)); + + if (sigaction(SIGINT, &sv, NULL) < 0) + ERROR("error in sigaction(SIGINT): %s", strerror(errno)); + + memset(&sv, 0, sizeof(struct sigaction)); + sv.sa_handler = SIG_IGN; + sigemptyset(&sv.sa_mask); + + if (sigaction(SIGABRT, &sv, NULL) < 0) + ERROR("error in sigaction(SIGABRT): %s", strerror(errno)); + + if (sigaction(SIGHUP, &sv, NULL) < 0) + ERROR("error in sigaction(SIGHUP): %s", strerror(errno)); + + if (sigaction(SIGQUIT, &sv, NULL) < 0) + ERROR("error in sigaction(SIGQUIT): %s", strerror(errno)); +} + static void usage_cp(void) { printf( - "Usage: ad cp [-R [-P]] [-pvf] \n" - "Usage: ad cp [-R [-P]] [-pvfx] \n" + "Usage: ad cp [-R] [-aipvf] \n" + " ad cp [-R] [-aipvfx] \n\n" + "In the first synopsis form, the cp utility copies the contents of the source_file to the\n" + "target_file. In the second synopsis form, the contents of each named source_file is copied to the\n" + "destination target_directory. The names of the files themselves are not changed. If cp detects an\n" + "attempt to copy a file to itself, the copy will fail.\n\n" + "Netatalk AFP volumes are detected by means of their \".AppleDesktop\" directory\n" + "which is located in their volume root. When a copy targetting an AFP volume\n" + "is detected, its CNID database daemon is connected and all copies will also\n" + "go through the CNID database.\n" + "AppleDouble files are also copied and created as needed when the target is\n" + "an AFP volume.\n\n" + "The following options are available:\n\n" + " -a Archive mode. Same as -Rp.\n\n" + " -f For each existing destination pathname, remove it and create a new\n" + " file, without prompting for confirmation regardless of its permis-\n" + " sions. (The -f option overrides any previous -i or -n options.)\n\n" + " -i Cause cp to write a prompt to the standard error output before\n" + " copying a file that would overwrite an existing file. If the\n" + " response from the standard input begins with the character 'y' or\n" + " 'Y', the file copy is attempted. (The -i option overrides any pre-\n" + " vious -f or -n options.)\n\n" + " -n Do not overwrite an existing file. (The -n option overrides any\n" + " previous -f or -i options.)\n\n" + " -p Cause cp to preserve the following attributes of each source file\n" + " in the copy: modification time, access time, file flags, file mode,\n" + " user ID, and group ID, as allowed by permissions.\n" + " If the user ID and group ID cannot be preserved, no error message\n" + " is displayed and the exit value is not altered.\n\n" + " -R If source_file designates a directory, cp copies the directory and\n" + " the entire subtree connected at that point.If the source_file\n" + " ends in a /, the contents of the directory are copied rather than\n" + " the directory itself.\n\n" + " -v Cause cp to be verbose, showing files as they are copied.\n\n" + " -x File system mount points are not traversed.\n\n" ); exit(EXIT_FAILURE); } -int ad_cp(int argc, char *argv[]) +int ad_cp(int argc, char *argv[], AFPObj *obj) { struct stat to_stat, tmp_stat; int r, ch, have_trailing_slash; @@ -154,11 +224,8 @@ int ad_cp(int argc, char *argv[]) ppdid = pdid = htonl(1); did = htonl(2); - while ((ch = getopt(argc, argv, "Rafilnpvx")) != -1) + while ((ch = getopt(argc, argv, "afinpRvx")) != -1) switch (ch) { - case 'R': - Rflag = 1; - break; case 'a': pflag = 1; Rflag = 1; @@ -171,9 +238,6 @@ int ad_cp(int argc, char *argv[]) iflag = 1; fflag = nflag = 0; break; - case 'l': - lflag = 1; - break; case 'n': nflag = 1; fflag = iflag = 0; @@ -181,6 +245,9 @@ int ad_cp(int argc, char *argv[]) case 'p': pflag = 1; break; + case 'R': + Rflag = 1; + break; case 'v': vflag = 1; break; @@ -197,8 +264,7 @@ int ad_cp(int argc, char *argv[]) if (argc < 2) usage_cp(); - (void)signal(SIGINT, siginfo); - + set_signal(); cnid_init(); /* Save the target base in "to". */ @@ -285,18 +351,21 @@ int ad_cp(int argc, char *argv[]) #endif /* Load .volinfo file for destination*/ - openvol(to.p_path, &dvolume); + openvol(obj, to.p_path, &dvolume); - for (int i = 0; argv[i] != NULL; i++) { + for (int i = 0; argv[i] != NULL; i++) { /* Load .volinfo file for source */ - openvol(argv[i], &svolume); + openvol(obj, argv[i], &svolume); if (nftw(argv[i], copy, upfunc, 20, ftw_options) == -1) { - ERROR("%s: %s", argv[i], strerror(errno)); - exit(EXIT_FAILURE); + if (alarmed) { + SLOG("...break"); + } else { + SLOG("Error: %s: %s", argv[i], strerror(errno)); + } + closevol(&svolume); + closevol(&dvolume); } - - } return rval; } @@ -314,12 +383,19 @@ static int copy(const char *path, const char *p; char *target_mid; + if (alarmed) + return -1; + + /* This currently doesn't work with "." */ + if (strcmp(path, ".") == 0) { + ERROR("\".\" not supported"); + } const char *dir = strrchr(path, '/'); if (dir == NULL) dir = path; else dir++; - if (check_netatalk_dirs(dir) != NULL) + if (!dvolume.vol->vfs->vfs_validupath(dvolume.vol, dir)) return FTW_SKIP_SUBTREE; /* @@ -379,24 +455,33 @@ static int copy(const char *path, else { if (to_stat.st_dev == statp->st_dev && to_stat.st_ino == statp->st_ino) { - SLOG("%s and %s are identical (not copied).", - to.p_path, path); + SLOG("%s and %s are identical (not copied).", to.p_path, path); badcp = rval = 1; if (S_ISDIR(statp->st_mode)) /* without using glibc extension FTW_ACTIONRETVAL cant handle this */ - return -1; + return FTW_SKIP_SUBTREE; + return 0; } if (!S_ISDIR(statp->st_mode) && S_ISDIR(to_stat.st_mode)) { SLOG("cannot overwrite directory %s with " - "non-directory %s", - to.p_path, path); - badcp = rval = 1; - return 0; + "non-directory %s", + to.p_path, path); + badcp = rval = 1; + return 0; } dne = 0; } + /* Convert basename to appropiate volume encoding */ + if (dvolume.vol->v_path) { + if ((convert_dots_encoding(&svolume, &dvolume, to.p_path, MAXPATHLEN)) == -1) { + SLOG("Error converting name for %s", to.p_path); + badcp = rval = 1; + return -1; + } + } + switch (statp->st_mode & S_IFMT) { case S_IFLNK: if (ftw_copy_link(ftw, path, statp, !dne)) @@ -425,19 +510,19 @@ static int copy(const char *path, } /* Create ad dir and copy ".Parent" */ - if (dvolume.volinfo.v_path && dvolume.volinfo.v_adouble == AD_VERSION2) { - - /* Create ".AppleDouble" dir */ + if (dvolume.vol->v_path && ADVOL_V2_OR_EA(dvolume.vol->v_adouble)) { mode_t omask = umask(0); - bstring addir = bfromcstr(to.p_path); - bcatcstr(addir, "/.AppleDouble"); - mkdir(cfrombstr(addir), 02777); - bdestroy(addir); - - if (svolume.volinfo.v_path && svolume.volinfo.v_adouble == AD_VERSION2) { - /* copy ".Parent" file */ - SLOG("Copying adouble for %s -> %s", path, to.p_path); - if (dvolume.volume.vfs->vfs_copyfile(&dvolume.volume, -1, path, to.p_path)) { + if (dvolume.vol->v_adouble == AD_VERSION2) { + /* Create ".AppleDouble" dir */ + bstring addir = bfromcstr(to.p_path); + bcatcstr(addir, "/.AppleDouble"); + mkdir(cfrombstr(addir), 02777); + bdestroy(addir); + } + + if (svolume.vol->v_path && ADVOL_V2_OR_EA(svolume.vol->v_adouble)) { + /* copy metadata file */ + if (dvolume.vol->vfs->vfs_copyfile(dvolume.vol, -1, path, to.p_path)) { SLOG("Error copying adouble for %s -> %s", path, to.p_path); badcp = rval = 1; break; @@ -446,27 +531,31 @@ static int copy(const char *path, /* Get CNID of Parent and add new childir to CNID database */ ppdid = pdid; - did = cnid_for_path(&dvolume.volinfo, &dvolume.volume, to.p_path, &pdid); + if ((did = cnid_for_path(&dvolume, to.p_path, &pdid)) == CNID_INVALID) { + SLOG("Error resolving CNID for %s", to.p_path); + badcp = rval = 1; + return -1; + } struct adouble ad; struct stat st; - if (stat(to.p_path, &st) != 0) { + if (lstat(to.p_path, &st) != 0) { badcp = rval = 1; break; } - ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options); - if (ad_open_metadata(to.p_path, ADFLAGS_DIR, O_RDWR | O_CREAT, &ad) != 0) { + ad_init(&ad, dvolume.vol); + if (ad_open(&ad, to.p_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0) { ERROR("Error opening adouble for: %s", to.p_path); } - SLOG("Setting CNID %u for %s", ntohl(did), to.p_path); ad_setid( &ad, st.st_dev, st.st_ino, did, pdid, dvolume.db_stamp); - ad_setname(&ad, utompath(&dvolume.volinfo, basename(to.p_path))); + if (dvolume.vol->v_adouble == AD_VERSION2) + ad_setname(&ad, utompath(dvolume.vol, basename(to.p_path))); ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime); ad_setdate(&ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime); ad_setdate(&ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime); ad_setdate(&ad, AD_DATE_BACKUP, AD_DATE_START); ad_flush(&ad); - ad_close_metadata(&ad); + ad_close(&ad, ADFLAGS_HF); umask(omask); } @@ -495,12 +584,12 @@ static int copy(const char *path, if (ftw_copy_file(ftw, path, statp, dne)) badcp = rval = 1; - if (dvolume.volinfo.v_path && dvolume.volinfo.v_adouble == AD_VERSION2) { + if (dvolume.vol->v_path && ADVOL_V2_OR_EA(dvolume.vol->v_adouble)) { mode_t omask = umask(0); - if (svolume.volinfo.v_path && svolume.volinfo.v_adouble == AD_VERSION2) { + if (svolume.vol->v_path && ADVOL_V2_OR_EA(svolume.vol->v_adouble)) { /* copy ad-file */ - if (dvolume.volume.vfs->vfs_copyfile(&dvolume.volume, -1, path, to.p_path)) { + if (dvolume.vol->vfs->vfs_copyfile(dvolume.vol, -1, path, to.p_path)) { SLOG("Error copying adouble for %s -> %s", path, to.p_path); badcp = rval = 1; break; @@ -509,27 +598,32 @@ static int copy(const char *path, /* Get CNID of Parent and add new childir to CNID database */ pdid = did; - cnid_t cnid = cnid_for_path(&dvolume.volinfo, &dvolume.volume, to.p_path, &did); + cnid_t cnid; + if ((cnid = cnid_for_path(&dvolume, to.p_path, &did)) == CNID_INVALID) { + SLOG("Error resolving CNID for %s", to.p_path); + badcp = rval = 1; + return -1; + } struct adouble ad; struct stat st; - if (stat(to.p_path, &st) != 0) { + if (lstat(to.p_path, &st) != 0) { badcp = rval = 1; break; } - ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options); - if (ad_open_metadata(to.p_path, 0, O_RDWR | O_CREAT, &ad) != 0) { + ad_init(&ad, dvolume.vol); + if (ad_open(&ad, to.p_path, ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0) { ERROR("Error opening adouble for: %s", to.p_path); } - SLOG("setid: DID: %u, CNID: %u, %s", ntohl(did), ntohl(cnid), to.p_path); ad_setid( &ad, st.st_dev, st.st_ino, cnid, did, dvolume.db_stamp); - ad_setname(&ad, utompath(&dvolume.volinfo, basename(to.p_path))); + if (dvolume.vol->v_adouble == AD_VERSION2) + ad_setname(&ad, utompath(dvolume.vol, basename(to.p_path))); ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime); ad_setdate(&ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime); ad_setdate(&ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime); ad_setdate(&ad, AD_DATE_BACKUP, AD_DATE_START); ad_flush(&ad); - ad_close_metadata(&ad); + ad_close(&ad, ADFLAGS_HF); umask(omask); } break; @@ -540,11 +634,6 @@ static int copy(const char *path, return 0; } -static void siginfo(int sig _U_) -{ - sigint = 1; -} - /* Memory strategy threshold, in pages: if physmem is larger then this, use a large buffer */ #define PHYSPAGES_THRESHOLD (32*1024) @@ -590,7 +679,7 @@ static int ftw_copy_file(const struct FTW *entp, (void)close(from_fd); return (0); } else if (iflag) { - (void)fprintf(stderr, "overwrite %s? %s", + (void)fprintf(stderr, "overwrite %s? %s", to.p_path, YESNO); checkch = ch = getchar(); while (ch != '\n' && ch != EOF) @@ -601,26 +690,23 @@ static int ftw_copy_file(const struct FTW *entp, return (1); } } - + if (fflag) { - /* remove existing destination file name, + /* remove existing destination file name, * create a new file */ (void)unlink(to.p_path); - (void)dvolume.volume.vfs->vfs_deletefile(&dvolume.volume, -1, to.p_path); - if (!lflag) - to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, - sp->st_mode & ~(S_ISUID | S_ISGID)); + (void)dvolume.vol->vfs->vfs_deletefile(dvolume.vol, -1, to.p_path); + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + sp->st_mode & ~(S_ISUID | S_ISGID)); } else { - if (!lflag) - /* overwrite existing destination file name */ - to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + /* overwrite existing destination file name */ + to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); } } else { - if (!lflag) - to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, - sp->st_mode & ~(S_ISUID | S_ISGID)); + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + sp->st_mode & ~(S_ISUID | S_ISGID)); } - + if (to_fd == -1) { SLOG("%s: %s", to.p_path, strerror(errno)); (void)close(from_fd); @@ -629,22 +715,58 @@ static int ftw_copy_file(const struct FTW *entp, rval = 0; - if (!lflag) { - /* - * Mmap and write if less than 8M (the limit is so we don't totally - * trash memory on big files. This is really a minor hack, but it - * wins some CPU back. - * Some filesystems, such as smbnetfs, don't support mmap, - * so this is a best-effort attempt. - */ + /* + * Mmap and write if less than 8M (the limit is so we don't totally + * trash memory on big files. This is really a minor hack, but it + * wins some CPU back. + * Some filesystems, such as smbnetfs, don't support mmap, + * so this is a best-effort attempt. + */ - if (S_ISREG(sp->st_mode) && sp->st_size > 0 && - sp->st_size <= 8 * 1024 * 1024 && - (p = mmap(NULL, (size_t)sp->st_size, PROT_READ, - MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) { - wtotal = 0; - for (bufp = p, wresid = sp->st_size; ; - bufp += wcount, wresid -= (size_t)wcount) { + if (S_ISREG(sp->st_mode) && sp->st_size > 0 && + sp->st_size <= 8 * 1024 * 1024 && + (p = mmap(NULL, (size_t)sp->st_size, PROT_READ, + MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) { + wtotal = 0; + for (bufp = p, wresid = sp->st_size; ; + bufp += wcount, wresid -= (size_t)wcount) { + wcount = write(to_fd, bufp, wresid); + if (wcount <= 0) + break; + wtotal += wcount; + if (wcount >= (ssize_t)wresid) + break; + } + if (wcount != (ssize_t)wresid) { + SLOG("%s: %s", to.p_path, strerror(errno)); + rval = 1; + } + /* Some systems don't unmap on close(2). */ + if (munmap(p, sp->st_size) < 0) { + SLOG("%s: %s", spath, strerror(errno)); + rval = 1; + } + } else { + if (buf == NULL) { + /* + * Note that buf and bufsize are static. If + * malloc() fails, it will fail at the start + * and not copy only some files. + */ + if (sysconf(_SC_PHYS_PAGES) > + PHYSPAGES_THRESHOLD) + bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); + else + bufsize = BUFSIZE_SMALL; + buf = malloc(bufsize); + if (buf == NULL) + ERROR("Not enough memory"); + + } + wtotal = 0; + while ((rcount = read(from_fd, buf, bufsize)) > 0) { + for (bufp = buf, wresid = rcount; ; + bufp += wcount, wresid -= wcount) { wcount = write(to_fd, bufp, wresid); if (wcount <= 0) break; @@ -655,58 +777,15 @@ static int ftw_copy_file(const struct FTW *entp, if (wcount != (ssize_t)wresid) { SLOG("%s: %s", to.p_path, strerror(errno)); rval = 1; - } - /* Some systems don't unmap on close(2). */ - if (munmap(p, sp->st_size) < 0) { - SLOG("%s: %s", spath, strerror(errno)); - rval = 1; - } - } else { - if (buf == NULL) { - /* - * Note that buf and bufsize are static. If - * malloc() fails, it will fail at the start - * and not copy only some files. - */ - if (sysconf(_SC_PHYS_PAGES) > - PHYSPAGES_THRESHOLD) - bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); - else - bufsize = BUFSIZE_SMALL; - buf = malloc(bufsize); - if (buf == NULL) - ERROR("Not enough memory"); - - } - wtotal = 0; - while ((rcount = read(from_fd, buf, bufsize)) > 0) { - for (bufp = buf, wresid = rcount; ; - bufp += wcount, wresid -= wcount) { - wcount = write(to_fd, bufp, wresid); - if (wcount <= 0) - break; - wtotal += wcount; - if (wcount >= (ssize_t)wresid) - break; - } - if (wcount != (ssize_t)wresid) { - SLOG("%s: %s", to.p_path, strerror(errno)); - rval = 1; - break; - } - } - if (rcount < 0) { - SLOG("%s: %s", spath, strerror(errno)); - rval = 1; + break; } } - } else { - if (link(spath, to.p_path)) { - SLOG("%s", to.p_path); + if (rcount < 0) { + SLOG("%s: %s", spath, strerror(errno)); rval = 1; } } - + /* * Don't remove the target even after an error. The target might * not be a regular file, or its attributes might be important, @@ -714,15 +793,13 @@ static int ftw_copy_file(const struct FTW *entp, * to remove it if we created it and its length is 0. */ - if (!lflag) { - if (pflag && setfile(sp, to_fd)) - rval = 1; - if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) - rval = 1; - if (close(to_fd)) { - SLOG("%s: %s", to.p_path, strerror(errno)); - rval = 1; - } + if (pflag && setfile(sp, to_fd)) + rval = 1; + if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) + rval = 1; + if (close(to_fd)) { + SLOG("%s: %s", to.p_path, strerror(errno)); + rval = 1; } (void)close(from_fd); @@ -766,10 +843,16 @@ static int setfile(const struct stat *fs, int fd) islink = !fdval && S_ISLNK(fs->st_mode); mode = fs->st_mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO); +#if defined(__FreeBSD__) + TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); +#else TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim); - if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { - SLOG("%sutimes: %s", islink ? "l" : "", to.p_path); +#endif + + if (utimes(to.p_path, tv)) { + SLOG("utimes: %s", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) :