diff options
Diffstat (limited to 'src/nssync.c')
-rw-r--r-- | src/nssync.c | 126 |
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 @@ -60,12 +60,72 @@ debug_printf(const char *fmt, ...) vfprintf(stderr, fmt, ap); fputc('\n', stderr); va_end(ap); } +/* 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) { int out_fd; struct stat st; int rc; @@ -82,15 +142,23 @@ copy_file(const char *file_name, FILE *infile, const char *dst_file) file_name, strerror(errno)); 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; + 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; fsize = st.st_size; for (bufsize = fsize; bufsize > 0 && (buf = malloc (bufsize)) == NULL; @@ -131,12 +199,52 @@ copy_file(const char *file_name, FILE *infile, const char *dst_file) if (rc) unlink(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) { const char *env[5]; struct wordsplit ws; @@ -324,21 +432,25 @@ main(int argc, char **argv) if (slave_status_file) check_slave_status(); 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) { int rc = system(reload_command); if (rc) { debug(1,("reload command returned %d", rc)); |