X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffindlib%2Fcreate_file.c;h=766120df91609dea4be2a6347c58609c9b6a9501;hb=a64e57850ac943b84184f43e712ccf18b498ca30;hp=8c503d14a775901c0f33fdf461281a50670da24c;hpb=7e3728443e60e985983472a93e73f75e3faff82c;p=bacula%2Fbacula diff --git a/bacula/src/findlib/create_file.c b/bacula/src/findlib/create_file.c index 8c503d14a7..766120df91 100644 --- a/bacula/src/findlib/create_file.c +++ b/bacula/src/findlib/create_file.c @@ -38,6 +38,9 @@ #define O_CTG 0 #endif +static int separate_path_and_file(JCR *jcr, char *fname, char *ofile); +static int path_already_seen(JCR *jcr, char *path, int pnl); + /* * Create the file, or the directory @@ -58,166 +61,211 @@ * files. * */ -int create_file(void *jcr, char *fname, char *ofile, char *lname, - int type, int stream, struct stat *statp, - char *attribsEx, int *ofd, int replace) +int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) { int new_mode, parent_mode, mode; uid_t uid; gid_t gid; - int stat = 0; - int fnl, pnl; - char *f, *p, savechr; + int pnl; + bool exists = false; + struct stat mstatp; - *ofd = -1; - new_mode = statp->st_mode; - Dmsg2(300, "newmode=%x file=%s\n", new_mode, ofile); + if (is_win32_stream(attr->data_stream)) { + set_win32_backup(bfd); + } else { + set_portable_backup(bfd); + } + + new_mode = attr->statp.st_mode; + Dmsg2(300, "newmode=%x file=%s\n", new_mode, attr->ofname); parent_mode = S_IWUSR | S_IXUSR | new_mode; - gid = statp->st_gid; - uid = statp->st_uid; + gid = attr->statp.st_gid; + uid = attr->statp.st_uid; Dmsg2(400, "Replace=%c %d\n", (char)replace, replace); - /* If not always replacing, do a stat and decide */ - if (replace != REPLACE_ALWAYS) { - struct stat mstatp; - if (lstat(ofile, &mstatp) == 0) { - switch (replace) { - case REPLACE_IFNEWER: - if (statp->st_mtime <= mstatp.st_mtime) { - Jmsg(jcr, M_SKIPPED, 0, _("File skipped. Not newer: %s\n"), ofile); - return CF_SKIP; - } - break; - case REPLACE_IFOLDER: - if (statp->st_mtime >= mstatp.st_mtime) { - Jmsg(jcr, M_SKIPPED, 0, _("File skipped. Not older: %s\n"), ofile); - return CF_SKIP; - } - break; - case REPLACE_NEVER: - Jmsg(jcr, M_SKIPPED, 0, _("File skipped. Already exists: %s\n"), ofile); + if (lstat(attr->ofname, &mstatp) == 0) { + exists = true; + switch (replace) { + case REPLACE_IFNEWER: + if (attr->statp.st_mtime <= mstatp.st_mtime) { + Jmsg(jcr, M_SKIPPED, 0, _("File skipped. Not newer: %s\n"), attr->ofname); return CF_SKIP; } + break; + + case REPLACE_IFOLDER: + if (attr->statp.st_mtime >= mstatp.st_mtime) { + Jmsg(jcr, M_SKIPPED, 0, _("File skipped. Not older: %s\n"), attr->ofname); + return CF_SKIP; + } + break; + + case REPLACE_NEVER: + Jmsg(jcr, M_SKIPPED, 0, _("File skipped. Already exists: %s\n"), attr->ofname); + return CF_SKIP; + + case REPLACE_ALWAYS: + break; } } - switch (type) { + switch (attr->type) { case FT_LNKSAVED: /* Hard linked, file already saved */ - Dmsg2(130, "Hard link %s => %s\n", ofile, lname); - if (link(lname, ofile) != 0) { - Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s ==> %s: ERR=%s\n"), - ofile, lname, strerror(errno)); - return CF_ERROR; - } - break; + case FT_LNK: + case FT_RAW: + case FT_FIFO: + case FT_SPEC: case FT_REGE: /* empty file */ case FT_REG: /* regular file */ - /* Separate pathname and filename */ - for (p=f=ofile; *p; p++) { - if (*p == '/') { - f = p; /* possible filename */ + if (exists) { + /* Get rid of old copy */ + if (unlink(attr->ofname) == -1) { + Jmsg(jcr, M_ERROR, 0, _("File %s already exists and could not be replaced. ERR=%s.\n"), + attr->ofname, strerror(errno)); + /* Continue despite error */ } } - if (*f == '/') { - f++; - } - - fnl = p - f; - if (fnl == 0) { - /* The filename length must not be zero here because we - * are dealing with a file (i.e. FT_REGE or FT_REG). - */ - Jmsg1(jcr, M_ERROR, 0, _("Zero length filename: %s\n"), fname); + /* + * Here we do some preliminary work for all the above + * types to create the path to the file if it does + * not already exist. Below, we will split to + * do the file type specific work + */ + pnl = separate_path_and_file(jcr, attr->fname, attr->ofname); + if (pnl < 0) { return CF_ERROR; } - pnl = f - ofile - 1; - /* * If path length is <= 0 we are making a file in the root * directory. Assume that the directory already exists. */ if (pnl > 0) { - savechr = ofile[pnl]; - ofile[pnl] = 0; /* terminate path */ - - Dmsg1(50, "Make path %s\n", ofile); - /* - * If we need to make the directory, ensure that it is with - * execute bit set (i.e. parent_mode), and preserve what already - * exists. Normally, this should do nothing. - */ - stat = !make_path(jcr, ofile, parent_mode, parent_mode, uid, gid, 1, NULL); - if (stat == 0) { - Dmsg1(0, "Could not make path. %s\n", ofile); - Jmsg1(jcr, M_ERROR, 0, _("Could not make path. %s\n"), ofile); - return CF_ERROR; + char savechr; + savechr = attr->ofname[pnl]; + attr->ofname[pnl] = 0; /* terminate path */ + + if (!path_already_seen(jcr, attr->ofname, pnl)) { + Dmsg1(50, "Make path %s\n", attr->ofname); + /* + * If we need to make the directory, ensure that it is with + * execute bit set (i.e. parent_mode), and preserve what already + * exists. Normally, this should do nothing. + */ + if (make_path(jcr, attr->ofname, parent_mode, parent_mode, uid, gid, 1, NULL) != 0) { + Dmsg1(10, "Could not make path. %s\n", attr->ofname); + attr->ofname[pnl] = savechr; /* restore full name */ + return CF_ERROR; + } } - - ofile[pnl] = savechr; /* restore full name */ + attr->ofname[pnl] = savechr; /* restore full name */ } - Dmsg1(100, "Create file %s\n", ofile); - mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /* O_NOFOLLOW; */ - if (IS_CTG(statp->st_mode)) { - mode |= O_CTG; /* set contiguous bit if needed */ - } - Dmsg1(50, "Create file: %s\n", ofile); - if ((*ofd = open(ofile, mode, S_IRUSR | S_IWUSR)) < 0) { - Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), ofile, strerror(errno)); - return CF_ERROR; - } - return CF_EXTRACT; - case FT_LNK: - Dmsg2(130, "FT_LNK should restore: %s -> %s\n", ofile, lname); - if (symlink(lname, ofile) != 0 && errno != EEXIST) { - Jmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"), - ofile, lname, strerror(errno)); - return CF_ERROR; - } - return CF_CREATED; - case FT_DIR: - Dmsg2(300, "Make dir mode=%o dir=%s\n", new_mode, ofile); - if (make_path(jcr, ofile, new_mode, parent_mode, uid, gid, 0, NULL) != 0) { - Jmsg1(jcr, M_ERROR, 0, _("Could not make directory: %s\n"), ofile); - return CF_ERROR; - } - return CF_CREATED; - case FT_RAW: - case FT_FIFO: - case FT_SPEC: - if (S_ISFIFO(statp->st_mode)) { - Dmsg1(200, "Restore fifo: %s\n", ofile); - if (mkfifo(ofile, statp->st_mode) != 0 && errno != EEXIST) { - Jmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"), ofile, strerror(errno)); + /* Now we do the specific work for each file type */ + switch(attr->type) { + case FT_REGE: + case FT_REG: + Dmsg1(100, "Create file %s\n", attr->ofname); + mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /* O_NOFOLLOW; */ + if (IS_CTG(attr->statp.st_mode)) { + mode |= O_CTG; /* set contiguous bit if needed */ + } + Dmsg1(50, "Create file: %s\n", attr->ofname); + if (is_bopen(bfd)) { + Jmsg1(jcr, M_ERROR, 0, "bpkt already open fid=%d\n", bfd->fid); + } + if ((bopen(bfd, attr->ofname, mode, S_IRUSR | S_IWUSR)) < 0) { + Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), + attr->ofname, berror(bfd)); + return CF_ERROR; + } + return CF_EXTRACT; + + case FT_RAW: /* Bacula raw device e.g. /dev/sda1 */ + case FT_FIFO: /* Bacula fifo to save data */ + case FT_SPEC: + if (S_ISFIFO(attr->statp.st_mode)) { + Dmsg1(200, "Restore fifo: %s\n", attr->ofname); + if (mkfifo(attr->ofname, attr->statp.st_mode) != 0 && errno != EEXIST) { + Jmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"), + attr->ofname, strerror(errno)); + return CF_ERROR; + } + } else { + Dmsg1(200, "Restore node: %s\n", attr->ofname); + if (mknod(attr->ofname, attr->statp.st_mode, attr->statp.st_rdev) != 0 && errno != EEXIST) { + Jmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"), + attr->ofname, strerror(errno)); + return CF_ERROR; + } + } + if (attr->type == FT_RAW || attr->type == FT_FIFO) { + btimer_id tid; + Dmsg1(200, "FT_RAW|FT_FIFO %s\n", attr->ofname); + mode = O_WRONLY | O_BINARY; + /* Timeout open() in 60 seconds */ + if (attr->type == FT_FIFO) { + tid = start_thread_timer(pthread_self(), 60); + } else { + tid = NULL; + } + if (is_bopen(bfd)) { + Jmsg1(jcr, M_ERROR, 0, "bpkt already open fid=%d\n", bfd->fid); + } + if ((bopen(bfd, attr->ofname, mode, 0)) < 0) { + Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), + attr->ofname, berror(bfd)); + stop_thread_timer(tid); + return CF_ERROR; + } + stop_thread_timer(tid); + return CF_EXTRACT; + } + Dmsg1(200, "FT_SPEC %s\n", attr->ofname); + return CF_CREATED; + + case FT_LNK: + Dmsg2(130, "FT_LNK should restore: %s -> %s\n", attr->ofname, attr->olname); + if (symlink(attr->olname, attr->ofname) != 0 && errno != EEXIST) { + Jmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"), + attr->ofname, attr->olname, strerror(errno)); return CF_ERROR; } - } else { - Dmsg1(200, "Restore node: %s\n", ofile); - if (mknod(ofile, statp->st_mode, statp->st_rdev) != 0 && errno != EEXIST) { - Jmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"), ofile, strerror(errno)); + return CF_CREATED; + + case FT_LNKSAVED: /* Hard linked, file already saved */ + Dmsg2(130, "Hard link %s => %s\n", attr->ofname, attr->olname); + if (link(attr->olname, attr->ofname) != 0) { + Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s -> %s: ERR=%s\n"), + attr->ofname, attr->olname, strerror(errno)); return CF_ERROR; } - } - if (type == FT_RAW || type == FT_FIFO) { - btimer_id tid; - Dmsg1(200, "FT_RAW|FT_FIFO %s\n", ofile); - mode = O_WRONLY | O_BINARY; - /* Timeout open() in 60 seconds */ - if (type == FT_FIFO) { - tid = start_thread_timer(pthread_self(), 60); - } else { - tid = NULL; + return CF_CREATED; + + } /* End inner switch */ + + case FT_DIR: + Dmsg2(200, "Make dir mode=%o dir=%s\n", new_mode, attr->ofname); + if (make_path(jcr, attr->ofname, new_mode, parent_mode, uid, gid, 0, NULL) != 0) { + return CF_ERROR; + } + /* + * If we are using the Win32 Backup API, we open the + * directory so that the security info will be read + * and saved. + */ + if (!is_portable_backup(bfd)) { + if (is_bopen(bfd)) { + Jmsg1(jcr, M_ERROR, 0, "bpkt already open fid=%d\n", bfd->fid); } - if ((*ofd = open(ofile, mode)) < 0) { - Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), ofile, strerror(errno)); - stop_thread_timer(tid); + if ((bopen(bfd, attr->ofname, O_WRONLY|O_BINARY, 0)) < 0) { + Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), + attr->ofname, berror(bfd)); return CF_ERROR; } - stop_thread_timer(tid); return CF_EXTRACT; + } else { + return CF_CREATED; } - Dmsg1(200, "FT_SPEC %s\n", ofile); - return CF_CREATED; /* The following should not occur */ case FT_NOACCESS: @@ -229,9 +277,60 @@ int create_file(void *jcr, char *fname, char *ofile, char *lname, case FT_NORECURSE: case FT_NOFSCHG: case FT_NOOPEN: - Jmsg2(jcr, M_ERROR, 0, _("Original file %s not saved. Stat=%d\n"), fname, type); + Jmsg2(jcr, M_ERROR, 0, _("Original file %s not saved: type=%d\n"), attr->fname, attr->type); + break; default: - Jmsg2(jcr, M_ERROR, 0, _("Unknown file type %d; not restored: %s\n"), type, fname); + Jmsg2(jcr, M_ERROR, 0, _("Unknown file type %d; not restored: %s\n"), attr->type, attr->fname); + break; } return CF_ERROR; } + +/* + * Returns: > 0 index into path where last path char is. + * 0 no path + * -1 filename is zero length + */ +static int separate_path_and_file(JCR *jcr, char *fname, char *ofile) +{ + char *f, *p; + int fnl, pnl; + + /* Separate pathname and filename */ + for (p=f=ofile; *p; p++) { + if (*p == '/') { + f = p; /* possible filename */ + } + } + if (*f == '/') { + f++; + } + + fnl = p - f; + if (fnl == 0) { + /* The filename length must not be zero here because we + * are dealing with a file (i.e. FT_REGE or FT_REG). + */ + Jmsg1(jcr, M_ERROR, 0, _("Zero length filename: %s\n"), fname); + return -1; + } + pnl = f - ofile - 1; + return pnl; +} + +/* + * Primitive caching of path to prevent recreating a pathname + * each time as long as we remain in the same directory. + */ +static int path_already_seen(JCR *jcr, char *path, int pnl) +{ + if (!jcr->cached_path) { + jcr->cached_path = get_pool_memory(PM_FNAME); + } + if (jcr->cached_pnl == pnl && strcmp(path, jcr->cached_path) == 0) { + return 1; + } + pm_strcpy(&jcr->cached_path, path); + jcr->cached_pnl = pnl; + return 0; +}