summaryrefslogtreecommitdiffabout
path: root/src/nssync.c
Side-by-side diff
Diffstat (limited to 'src/nssync.c') (more/less context) (ignore whitespace changes)
-rw-r--r--src/nssync.c126
1 files changed, 119 insertions, 7 deletions
diff --git a/src/nssync.c b/src/nssync.c
index 9f8fb9d..75de83c 100644
--- a/src/nssync.c
+++ b/src/nssync.c
@@ -63,6 +63,66 @@ debug_printf(const char *fmt, ...)
}
+/* Create the directory DIR, eventually creating all intermediate directories
+ starting from DIR + BASELEN. */
+int
+create_hierarchy(char *dir, size_t baselen)
+{
+ int rc;
+ struct stat st;
+ char *p;
+
+ if (stat(dir, &st) == 0) {
+ if (!S_ISDIR(st.st_mode)) {
+ error(_("component %s is not a directory"), dir);
+ return 1;
+ }
+ return 0;
+ } else if (errno != ENOENT) {
+ error(_("cannot stat file %s: %s"), dir, strerror(errno));
+ return 1;
+ }
+
+ p = strrchr(dir, '/');
+ if (p) {
+ if (p - dir + 1 < baselen) {
+ error(_("base directory %s does not exist"), dir);
+ return 1;
+ }
+ *p = 0;
+ }
+
+ rc = create_hierarchy(dir, baselen);
+ if (rc == 0) {
+ if (p)
+ *p = '/';
+ if (mkdir(dir, 0744)) {
+ error(_("cannot create directory %s: %s"),
+ dir, strerror(errno));
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+static int
+trycreate(const char *file_name)
+{
+ int rc = 1;
+ char *dir_name = grecs_strdup(file_name);
+ char *p = strrchr(dir_name, '/');
+
+ if (p) {
+ size_t len = strlen(bind_working_dir);
+ if (strncmp(dir_name, bind_working_dir, len) == 0) {
+ *p = 0;
+ rc = create_hierarchy(dir_name, len);
+ }
+ }
+ free(dir_name);
+ return rc;
+}
+
int
copy_file(const char *file_name, FILE *infile, const char *dst_file)
{
@@ -85,9 +145,17 @@ copy_file(const char *file_name, FILE *infile, const char *dst_file)
out_fd = open(dst_file, O_WRONLY|O_TRUNC|O_CREAT, 0640);
if (out_fd == -1) {
- error("cannot create destination file %s: %s",
- dst_file, strerror(errno));
- return 1;
+ if (errno == ENOENT) {
+ if (trycreate(dst_file))
+ return 1;
+ out_fd = open(dst_file, O_WRONLY|O_TRUNC|O_CREAT,
+ 0640);
+ }
+ if (out_fd == -1) {
+ error("cannot create destination file %s: %s",
+ dst_file, strerror(errno));
+ return 1;
+ }
}
buf = NULL;
@@ -134,6 +202,46 @@ copy_file(const char *file_name, FILE *infile, const char *dst_file)
return rc;
}
+/* Move FILE to DST_FILE. If they reside on different devices, use copy_file
+ + unlink. */
+int
+move_file(const char *file, const char *dst_file)
+{
+ int rc = 0;
+
+ rc = rename(file, dst_file);
+ if (rc && errno == ENOENT) {
+ if (trycreate(dst_file))
+ return 1;
+ rc = rename(file, dst_file);
+ }
+ if (rc) {
+ if (errno == EXDEV) {
+ FILE *fp = fopen(file, "r");
+ if (!fp) {
+ error("cannot open %s for reading: %s",
+ file, strerror(errno));
+ return 1;
+ }
+ rc = copy_file (file, fp, dst_file);
+ fclose(fp);
+ if (rc) {
+ error(_("cannot copy %s to %s: %s"),
+ file, dst_file, strerror(errno));
+ rc = 1;
+ } else if (unlink(file)) {
+ error(_("cannot unlink %s: %s"),
+ file, strerror(errno));
+ }
+ } else {
+ error(_("cannot move %s to %s: %s"),
+ file, dst_file, strerror(errno));
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
int
compare(const char *oldfile, const char *newfile)
@@ -327,15 +435,19 @@ main(int argc, char **argv)
for (ep = synclist->head; ep; ep = ep->next)
synchronize(ep->data);
- if (error_count)
+ if (error_count) {
+ error("exiting due to errors");
exit(EX_UNAVAILABLE);
-
+ }
+
for (ep = synclist->head; ep; ep = ep->next)
flush_zone_list(ep->data);
- if (error_count)
+ if (error_count) {
+ error("exiting due to errors");
exit(EX_UNAVAILABLE);
-
+ }
+
if (changed_zones) {
debug(1,("about to run %s", reload_command));
if (!dry_run_mode) {

Return to:

Send suggestions and report system problems to the System administrator.