version 1.14, 2019/02/17 16:34:04 |
version 1.15, 2019/02/18 21:34:54 |
|
|
} |
} |
|
|
/* |
/* |
|
* Handle a symbolic link. |
|
* If we encounter directories existing in the symbolic link's place, |
|
* then try to unlink the directory. |
|
* Otherwise, simply overwrite with the symbolic link by renaming. |
* Return <0 on failure 0 on success. |
* Return <0 on failure 0 on success. |
*/ |
*/ |
static int |
static int |
|
|
return 0; |
return 0; |
} |
} |
|
|
/* See if the symlink already exists. */ |
/* |
|
* See if the symlink already exists. |
|
* If it's a directory, then try to unlink the directory prior |
|
* to overwriting with a symbolic link. |
|
* If it's a non-directory, we just overwrite it. |
|
*/ |
|
|
assert(p->rootfd != -1); |
assert(p->rootfd != -1); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
if (rc != -1 && !S_ISLNK(st.st_mode)) { |
if (rc != -1 && !S_ISLNK(st.st_mode)) { |
if (S_ISDIR(st.st_mode)) { |
if (S_ISDIR(st.st_mode) && |
if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
WARN(sess, "%s", f->path); |
ERR(sess, "%s: unlinkat", f->path); |
return -1; |
return -1; |
} |
|
} |
} |
rc = -1; /* overwrite object with symlink */ |
rc = -1; |
} else if (rc == -1 && errno != ENOENT) { |
} else if (rc == -1 && errno != ENOENT) { |
WARN(sess, "%s: fstatat", f->path); |
ERR(sess, "%s: fstatat", f->path); |
return -1; |
return -1; |
} |
} |
|
|
|
|
if (rc != -1) { |
if (rc != -1) { |
b = symlinkat_read(sess, p->rootfd, f->path); |
b = symlinkat_read(sess, p->rootfd, f->path); |
if (b == NULL) { |
if (b == NULL) { |
ERRX1(sess, "%s: symlinkat_read", f->path); |
ERRX1(sess, "symlinkat_read"); |
return -1; |
return -1; |
} |
} |
if (strcmp(f->link, b)) { |
if (strcmp(f->link, b)) { |
|
|
b = NULL; |
b = NULL; |
} |
} |
|
|
|
/* |
|
* Create the temporary file as a symbolic link, then rename the |
|
* temporary file as the real one, overwriting anything there. |
|
*/ |
|
|
if (rc == -1 || updatelink) { |
if (rc == -1 || updatelink) { |
LOG3(sess, "%s: creating " |
LOG3(sess, "%s: creating " |
"symlink: %s", f->path, f->link); |
"symlink: %s", f->path, f->link); |
|
if (mktemplate(sess, &temp, |
if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { |
f->path, sess->opts->recursive) == -1) { |
ERR(sess, "asprintf"); |
ERRX1(sess, "mktemplate"); |
return -1; |
return -1; |
} |
} |
if (mkstemplinkat(f->link, p->rootfd, temp) == NULL) { |
if (mkstemplinkat(f->link, p->rootfd, temp) == NULL) { |
WARN(sess, "%s: symlinkat", temp); |
ERR(sess, "mkstemplinkat"); |
free(temp); |
free(temp); |
return -1; |
return -1; |
} |
} |
newlink = 1; |
newlink = 1; |
} |
} |
|
|
rsync_set_metadata_at(sess, newlink, p->rootfd, f, |
rsync_set_metadata_at(sess, newlink, |
newlink ? temp : f->path); |
p->rootfd, f, newlink ? temp : f->path); |
|
|
if (newlink) { |
if (newlink) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
|
|
} |
} |
|
|
/* |
/* |
|
* See pre_link(), but for devices. |
|
* FIXME: this is very similar to the other pre_xxx() functions. |
* Return <0 on failure 0 on success. |
* Return <0 on failure 0 on success. |
*/ |
*/ |
static int |
static int |
|
|
return 0; |
return 0; |
} |
} |
|
|
/* See if the dev already exists */ |
/* |
assert(p->rootfd != -1); |
* See if the dev already exists. |
|
* If a non-device exists in its place, we'll replace that. |
|
* If it replaces a directory, remove the directory first. |
|
*/ |
|
|
|
assert(p->rootfd != -1); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
|
|
if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) { |
if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) { |
if (S_ISDIR(st.st_mode)) { |
if (S_ISDIR(st.st_mode) && |
if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
WARN(sess, "%s", f->path); |
ERR(sess, "%s: unlinkat", f->path); |
return -1; |
return -1; |
} |
|
} |
} |
rc = -1; /* overwrite object with dev */ |
rc = -1; |
} else if (rc == -1 && errno != ENOENT) { |
} else if (rc == -1 && errno != ENOENT) { |
WARN(sess, "%s: fstatat", f->path); |
ERR(sess, "%s: fstatat", f->path); |
return -1; |
return -1; |
} |
} |
|
|
/* |
/* Make sure existing device is of the correct type. */ |
* If the device already exists make sure it is of the correct type. |
|
*/ |
|
|
|
if (rc != -1) { |
if (rc != -1) { |
if ((f->st.mode & (S_IFCHR|S_IFBLK)) != |
if ((f->st.mode & (S_IFCHR|S_IFBLK)) != |
(st.st_mode & (S_IFCHR|S_IFBLK)) || f->st.rdev != |
(st.st_mode & (S_IFCHR|S_IFBLK)) || |
st.st_rdev) { |
f->st.rdev != st.st_rdev) { |
LOG3(sess, "%s: updating dev", f->path); |
LOG3(sess, "%s: updating device", f->path); |
updatedev = 1; |
updatedev = 1; |
} |
} |
} |
} |
|
|
if (rc == -1 || updatedev) { |
if (rc == -1 || updatedev) { |
newdev = 1; |
newdev = 1; |
if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { |
if (mktemplate(sess, &temp, f->path, |
ERR(sess, "asprintf"); |
sess->opts->recursive) == -1) { |
|
ERRX1(sess, "mktemplate"); |
return -1; |
return -1; |
} |
} |
if (mkstempnodat(p->rootfd, temp, f->st.mode & |
if (mkstempnodat(p->rootfd, temp, |
(S_IFCHR|S_IFBLK), f->st.rdev) == NULL) { |
f->st.mode & (S_IFCHR|S_IFBLK), f->st.rdev) == NULL) { |
WARN(sess, "%s: mknodat", temp); |
ERR(sess, "mkstempnodat"); |
free(temp); |
free(temp); |
return -1; |
return -1; |
} |
} |
} |
} |
|
|
rsync_set_metadata_at(sess, newdev, p->rootfd, f, |
rsync_set_metadata_at(sess, newdev, |
newdev ? temp : f->path); |
p->rootfd, f, newdev ? temp : f->path); |
|
|
if (newdev) { |
if (newdev) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
|
|
} |
} |
free(temp); |
free(temp); |
} |
} |
|
|
log_file(sess, f); |
log_file(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
/* |
/* |
|
* See pre_link(), but for FIFOs. |
|
* FIXME: this is very similar to the other pre_xxx() functions. |
* Return <0 on failure 0 on success. |
* Return <0 on failure 0 on success. |
*/ |
*/ |
static int |
static int |
|
|
return 0; |
return 0; |
} |
} |
|
|
/* See if the fifo already exists */ |
/* |
assert(p->rootfd != -1); |
* See if the fifo already exists. |
|
* If it exists as a non-FIFO, unlink it (if a directory) then |
|
* mark it from replacement. |
|
*/ |
|
|
|
assert(p->rootfd != -1); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
|
|
if (rc != -1 && !S_ISFIFO(st.st_mode)) { |
if (rc != -1 && !S_ISFIFO(st.st_mode)) { |
if (S_ISDIR(st.st_mode)) { |
if (S_ISDIR(st.st_mode) && |
if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
WARN(sess, "%s", f->path); |
ERR(sess, "%s: unlinkat", f->path); |
return -1; |
return -1; |
} |
|
} |
} |
rc = -1; /* overwrite object with fifo */ |
rc = -1; |
} else if (rc == -1 && errno != ENOENT) { |
} else if (rc == -1 && errno != ENOENT) { |
WARN(sess, "%s: fstatat", f->path); |
ERR(sess, "%s: fstatat", f->path); |
return -1; |
return -1; |
} |
} |
|
|
if (rc == -1) { |
if (rc == -1) { |
newfifo = 1; |
newfifo = 1; |
if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { |
if (mktemplate(sess, &temp, f->path, |
ERR(sess, "asprintf"); |
sess->opts->recursive) == -1) { |
|
ERRX1(sess, "mktemplate"); |
return -1; |
return -1; |
} |
} |
if (mkstempfifoat(p->rootfd, temp) == NULL) { |
if (mkstempfifoat(p->rootfd, temp) == NULL) { |
WARN(sess, "%s: mkfifoat", temp); |
ERR(sess, "mkstempfifoat"); |
free(temp); |
free(temp); |
return -1; |
return -1; |
} |
} |
} |
} |
|
|
rsync_set_metadata_at(sess, newfifo, p->rootfd, f, |
rsync_set_metadata_at(sess, newfifo, |
newfifo ? temp : f->path); |
p->rootfd, f, newfifo ? temp : f->path); |
|
|
if (newfifo) { |
if (newfifo) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
|
|
} |
} |
free(temp); |
free(temp); |
} |
} |
|
|
log_file(sess, f); |
log_file(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
/* |
/* |
|
* See pre_link(), but for socket files. |
|
* FIXME: this is very similar to the other pre_xxx() functions. |
* Return <0 on failure 0 on success. |
* Return <0 on failure 0 on success. |
*/ |
*/ |
static int |
static int |
|
|
return 0; |
return 0; |
} |
} |
|
|
|
/* |
|
* See if the fifo already exists. |
|
* If it exists as a non-FIFO, unlink it (if a directory) then |
|
* mark it from replacement. |
|
*/ |
|
|
|
assert(-1 != p->rootfd); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
|
|
if (rc != -1 && !S_ISSOCK(st.st_mode)) { |
if (rc != -1 && !S_ISSOCK(st.st_mode)) { |
if (S_ISDIR(st.st_mode)) { |
if (S_ISDIR(st.st_mode) && |
if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { |
WARN(sess, "%s", f->path); |
ERR(sess, "%s: unlinkat", f->path); |
return -1; |
return -1; |
} |
|
} |
} |
rc = -1; /* overwrite object with sock */ |
rc = -1; |
} else if (rc == -1 && errno != ENOENT) { |
} else if (rc == -1 && errno != ENOENT) { |
WARN(sess, "%s: fstatat", f->path); |
ERR(sess, "%s: fstatat", f->path); |
return -1; |
return -1; |
} |
} |
|
|
if (rc == -1) { |
if (rc == -1) { |
newsock = 1; |
newsock = 1; |
|
if (mktemplate(sess, &temp, f->path, |
if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { |
sess->opts->recursive) == -1) { |
ERR(sess, "asprintf"); |
ERRX1(sess, "mktemplate"); |
return -1; |
return -1; |
} |
} |
|
|
if (mkstempsock(p->root, temp) == NULL) { |
if (mkstempsock(p->root, temp) == NULL) { |
WARN(sess, "%s: mksockat", temp); |
ERR(sess, "mkstempsock"); |
free(temp); |
free(temp); |
return -1; |
return -1; |
} |
} |
} |
} |
|
|
rsync_set_metadata_at(sess, newsock, p->rootfd, f, |
rsync_set_metadata_at(sess, newsock, |
newsock ? temp : f->path); |
p->rootfd, f, newsock ? temp : f->path); |
|
|
if (newsock) { |
if (newsock) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) { |
|
|
} |
} |
free(temp); |
free(temp); |
} |
} |
|
|
log_file(sess, f); |
log_file(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
|
|
assert(p->rootfd != -1); |
assert(p->rootfd != -1); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); |
|
|
if (rc == -1 && errno != ENOENT) { |
if (rc == -1 && errno != ENOENT) { |
WARN(sess, "%s: fstatat", f->path); |
ERR(sess, "%s: fstatat", f->path); |
return -1; |
return -1; |
} else if (rc != -1 && !S_ISDIR(st.st_mode)) { |
} else if (rc != -1 && !S_ISDIR(st.st_mode)) { |
WARNX(sess, "%s: not a directory", f->path); |
ERRX(sess, "%s: not a directory", f->path); |
return -1; |
return -1; |
} else if (rc != -1) { |
} else if (rc != -1) { |
/* |
/* |
|
|
|
|
LOG3(sess, "%s: creating directory", f->path); |
LOG3(sess, "%s: creating directory", f->path); |
if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) { |
if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) { |
WARN(sess, "%s: mkdirat", f->path); |
ERR(sess, "%s: mkdirat", f->path); |
return -1; |
return -1; |
} |
} |
|
|
|
|
/* Go back to the event loop, if necessary. */ |
/* Go back to the event loop, if necessary. */ |
|
|
u->state = (*fileinfd == -1) ? |
u->state = (*fileinfd == -1) ? |
UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL; |
UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL; |
if (u->state == UPLOAD_READ_LOCAL) |
if (u->state == UPLOAD_READ_LOCAL) |
return 1; |
return 1; |
} |
} |
|
|
mapsz = st.st_size; |
mapsz = st.st_size; |
map = mmap(NULL, mapsz, PROT_READ, MAP_SHARED, *fileinfd, 0); |
map = mmap(NULL, mapsz, PROT_READ, MAP_SHARED, *fileinfd, 0); |
if (map == MAP_FAILED) { |
if (map == MAP_FAILED) { |
WARN(sess, "%s: mmap", u->fl[u->idx].path); |
ERR(sess, "%s: mmap", u->fl[u->idx].path); |
close(*fileinfd); |
close(*fileinfd); |
*fileinfd = -1; |
*fileinfd = -1; |
return -1; |
return -1; |