#include <atalk/util.h>
#include <atalk/unix.h>
#include <atalk/volume.h>
-#include <atalk/volinfo.h>
#include <atalk/bstrlib.h>
#include <atalk/bstradd.h>
#include <atalk/queue.h>
static afpvol_t svolume, dvolume;
static cnid_t did, pdid;
static volatile sig_atomic_t alarmed;
-static char *adexecp;
static char *netatalk_dirs[] = {
".AppleDouble",
".AppleDB",
static int copy(const char *, const char *);
static int do_move(const char *, const char *);
-static int fastcopy(const char *, const char *, struct stat *);
static void preserve_fd_acls(int source_fd, int dest_fd, const char *source_path,
const char *dest_path);
/*
{
printf(
"Usage: ad mv [-f | -i | -n] [-v] source target\n"
- " ad mv [-f | -i | -n] [-v] source ... directory\n"
+ " ad mv [-f | -i | -n] [-v] source ... directory\n\n"
+ "Move files around within an AFP volume, updating the CNID\n"
+ "database as needed. If either:\n"
+ " - source or destination is not an AFP volume\n"
+ " - source volume != destinatio volume\n"
+ "the files are copied and removed from the source.\n\n"
+ "The following options are available:\n\n"
+ " -f Do not prompt for confirmation before overwriting the destination\n"
+ " path. (The -f option overrides any previous -i or -n options.)\n"
+ " -i Cause mv to write a prompt to standard error before moving a file\n"
+ " that would overwrite an existing file. If the response from the\n"
+ " standard input begins with the character `y' or `Y', the move is\n"
+ " attempted. (The -i option overrides any previous -f or -n\n"
+ " options.)\n"
+ " -n Do not overwrite an existing file. (The -n option overrides any\n"
+ " previous -f or -i options.)\n"
+ " -v Cause mv to be verbose, showing files after they are moved.\n"
);
exit(EXIT_FAILURE);
}
-int ad_mv(int argc, char *argv[])
+int ad_mv(int argc, char *argv[], AFPObj *obj)
{
size_t baselen, len;
int rval;
pdid = htonl(1);
did = htonl(2);
- adexecp = argv[0];
argc--;
argv++;
set_signal();
cnid_init();
- if (openvol(argv[argc - 1], &dvolume) != 0) {
- SLOG("Error opening CNID database for %s: ", argv[argc - 1]);
+ if (openvol(obj, argv[argc - 1], &dvolume) != 0) {
+ SLOG("Error opening CNID database for source \"%s\": ", argv[argc - 1]);
return 1;
}
if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
if (argc > 2)
usage_mv();
- if (openvol(argv[0], &svolume) != 0) {
- SLOG("Error opening CNID database for %s: ", argv[0]);
+ if (openvol(obj, argv[0], &svolume) != 0) {
+ SLOG("Error opening CNID database for destination \"%s\": ", argv[0]);
return 1;
}
rval = do_move(argv[0], argv[1]);
closevol(&svolume);
closevol(&dvolume);
+ return 1;
}
/* It's a directory, move each file into it. */
rval = 1;
} else {
memmove(endp, p, (size_t)len + 1);
- if (openvol(*argv, &svolume) != 0) {
- SLOG("Error opening CNID database for %s: ", argv[0]);
- rval = 1;
- goto exit;
- }
+ openvol(obj, *argv, &svolume);
+
if (do_move(*argv, path))
rval = 1;
closevol(&svolume);
* 1) source AFP volume != dest AFP volume
* 2) either source or dest isn't even an AFP volume
*/
- if (!svolume.volinfo.v_path
- || !dvolume.volinfo.v_path
- || strcmp(svolume.volinfo.v_path, dvolume.volinfo.v_path) != 0)
+ if (!svolume.vol->v_path
+ || !dvolume.vol->v_path
+ || strcmp(svolume.vol->v_path, dvolume.vol->v_path) != 0)
mustcopy = 1;
cnid_t cnid = 0;
switch (sb.st_mode & S_IFMT) {
case S_IFREG:
- if (dvolume.volume.vfs->vfs_renamefile(&dvolume.volume, -1, from, to) != 0) {
+ if (dvolume.vol->vfs->vfs_renamefile(dvolume.vol, -1, from, to) != 0) {
SLOG("Error moving adouble file for %s", from);
return -1;
}
return -1;
}
- char *newdir = strdup(to);
- cnid_t newdid;
- if ((newdid = cnid_for_path(&svolume, dirname(newdir), &pdid)) == CNID_INVALID) {
- SLOG("Couldn't resolve CNID for %s", to);
+ /* get CNID of new parent dir */
+ cnid_t newpdid, newdid;
+ if ((newdid = cnid_for_paths_parent(&dvolume, to, &newpdid)) == CNID_INVALID) {
+ SLOG("Couldn't resolve CNID for parent of %s", to);
+ return -1;
}
- free(newdir);
if (stat(to, &sb) != 0) {
SLOG("Cant stat %s: %s", to, strerror(errno));
return 1;
}
- char *name = strdup(to);
- if (cnid_update(dvolume.volume.v_cdb, cnid, &sb, newdid, basename(to), strlen(basename(to))) != 0) {
+
+ char *p = strdup(to);
+ char *name = basename(p);
+ if (cnid_update(dvolume.vol->v_cdb, cnid, &sb, newdid, name, strlen(name)) != 0) {
SLOG("Cant update CNID for: %s", to);
return 1;
}
- free(name);
+ free(p);
struct adouble ad;
- ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
- if (ad_open_metadata(to, S_ISDIR(sb.st_mode) ? ADFLAGS_DIR : 0, O_RDWR, &ad) != 0) {
+ ad_init(&ad, dvolume.vol);
+ if (ad_open(&ad, to, S_ISDIR(sb.st_mode) ? (ADFLAGS_DIR | ADFLAGS_HF | ADFLAGS_RDWR) : ADFLAGS_HF | ADFLAGS_RDWR) != 0) {
SLOG("Error opening adouble for: %s", to);
return 1;
}
ad_setid(&ad, sb.st_dev, sb.st_ino, cnid, newdid, dvolume.db_stamp);
ad_flush(&ad);
- ad_close_metadata(&ad);
+ ad_close(&ad, ADFLAGS_HF);
if (vflg)
printf("%s -> %s\n", from, to);
return (0);
}
+
+ if (mustcopy)
+ return copy(from, to);
- if (mustcopy) {
- /*
- * If rename fails because we're trying to cross devices, and
- * it's a regular file, do the copy internally; otherwise, use
- * cp and rm.
- */
- if (lstat(from, &sb)) {
- SLOG("%s: %s", from, strerror(errno));
- return (1);
- }
- return (S_ISREG(sb.st_mode) ?
- fastcopy(from, to, &sb) : copy(from, to));
- }
- return 1;
-}
-
-static int fastcopy(const char *from, const char *to, struct stat *sbp)
-{
- struct timeval tval[2];
- static u_int blen;
- static char *bp;
- mode_t oldmode;
- int nread, from_fd, to_fd;
-
- if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
- SLOG("%s: %s", from, strerror(errno));
- return (1);
- }
- if (blen < sbp->st_blksize) {
- if (bp != NULL)
- free(bp);
- if ((bp = malloc((size_t)sbp->st_blksize)) == NULL) {
- blen = 0;
- SLOG("malloc failed");
- return (1);
- }
- blen = sbp->st_blksize;
- }
- while ((to_fd = open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
- if (errno == EEXIST && unlink(to) == 0)
- continue;
- SLOG("%s: %s", to, strerror(errno));
- (void)close(from_fd);
- return (1);
- }
- while ((nread = read(from_fd, bp, (size_t)blen)) > 0)
- if (write(to_fd, bp, (size_t)nread) != nread) {
- SLOG("%s: %s", to, strerror(errno));
- goto err;
- }
- if (nread < 0) {
- SLOG("%s: %s", from, strerror(errno));
- err:
- if (unlink(to))
- SLOG("%s: remove", to, strerror(errno));
- (void)close(from_fd);
- (void)close(to_fd);
- return (1);
- }
-
- oldmode = sbp->st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID);
- if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
- SLOG("%s: set owner/group (was: %lu/%lu)", to,
- (u_long)sbp->st_uid, (u_long)sbp->st_gid, strerror(errno));
- if (oldmode & S_ISUID) {
- SLOG("%s: owner/group changed; clearing suid (mode was 0%03o)",
- to, oldmode);
- sbp->st_mode &= ~S_ISUID;
- }
- }
- if (fchmod(to_fd, sbp->st_mode))
- SLOG("%s: set mode (was: 0%03o): %s", to, oldmode, strerror(errno));
- /*
- * POSIX 1003.2c states that if _POSIX_ACL_EXTENDED is in effect
- * for dest_file, then its ACLs shall reflect the ACLs of the
- * source_file.
- */
- preserve_fd_acls(from_fd, to_fd, from, to);
- (void)close(from_fd);
-
- tval[0].tv_sec = sbp->st_atime;
- tval[1].tv_sec = sbp->st_mtime;
- tval[0].tv_usec = tval[1].tv_usec = 0;
- if (utimes(to, tval))
- SLOG("%s: set times: %s", to, strerror(errno));
-
- if (close(to_fd)) {
- SLOG("%s: %s", to, strerror(errno));
- return (1);
- }
-
- if (unlink(from)) {
- SLOG("%s: remove: %s", from, strerror(errno));
- return (1);
- }
- if (vflg)
- printf("%s -> %s\n", from, to);
- return 0;
+ /* If we get here it's an error */
+ return -1;
}
static int copy(const char *from, const char *to)
/* Copy source to destination. */
if (!(pid = fork())) {
- execl(adexecp, "cp", vflg ? "-Rpv" : "-Rp", "--", from, to, (char *)NULL);
+ execl(_PATH_AD, "ad", "cp", vflg ? "-Rpv" : "-Rp", from, to, (char *)NULL);
_exit(1);
}
while ((waitpid(pid, &status, 0)) == -1) {
if (errno == EINTR)
continue;
- SLOG("%s %s %s: waitpid: %s", adexecp, from, to, strerror(errno));
+ SLOG("%s cp -R %s %s: waitpid: %s", _PATH_AD, from, to, strerror(errno));
return (1);
}
if (!WIFEXITED(status)) {
- SLOG("%s %s %s: did not terminate normally", adexecp, from, to);
+ SLOG("%s cp -R %s %s: did not terminate normally", _PATH_AD, from, to);
return (1);
}
switch (WEXITSTATUS(status)) {
case 0:
break;
default:
- SLOG("%s cp %s %s: terminated with %d (non-zero) status",
- adexecp, from, to, WEXITSTATUS(status));
+ SLOG("%s cp -R %s %s: terminated with %d (non-zero) status",
+ _PATH_AD, from, to, WEXITSTATUS(status));
return (1);
}
/* Delete the source. */
if (!(pid = fork())) {
- execl(adexecp, "rm", "-Rf", "--", from, (char *)NULL);
+ execl(_PATH_AD, "ad", "rm", "-R", from, (char *)NULL);
_exit(1);
}
while ((waitpid(pid, &status, 0)) == -1) {
if (errno == EINTR)
continue;
- SLOG("%s rm %s: waitpid: %s", adexecp, from, strerror(errno));
+ SLOG("%s rm -R %s: waitpid: %s", _PATH_AD, from, strerror(errno));
return (1);
}
if (!WIFEXITED(status)) {
- SLOG("%s rm %s: did not terminate normally", adexecp, from);
+ SLOG("%s rm -R %s: did not terminate normally", _PATH_AD, from);
return (1);
}
switch (WEXITSTATUS(status)) {
case 0:
break;
default:
- SLOG("%s rm %s: terminated with %d (non-zero) status",
- adexecp, from, WEXITSTATUS(status));
+ SLOG("%s rm -R %s: terminated with %d (non-zero) status",
+ _PATH_AD, from, WEXITSTATUS(status));
return (1);
}
return 0;