From: Kern Sibbald Date: Sun, 2 Sep 2007 18:58:40 +0000 (+0000) Subject: kes Integrate patch to README.vc8 from X-Git-Tag: Release-7.0.0~5762 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=d4260ebd1b6096a01c425fbea7a39b1beb85f536;p=bacula%2Fbacula kes Integrate patch to README.vc8 from Hederer Jean-Sébastien , had to manually edit it to get it into Unix patch format. kes Implement mkpath.c to replace old FSF makepath.c git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@5433 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index eadfb5770c..a26fc7f848 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -56,6 +56,16 @@ Professional Needs: - How to sync remote offices. - Exchange backup: http://www.microsoft.com/technet/itshowcase/content/exchbkup.mspx +- David's priorities + Copypools + Extract capability (#25) + Continued enhancement of bweb + Threshold triggered migration jobs (not currently in list, but will be + needed ASAP) + Client triggered backups + Complete rework of the scheduling system (not in list) + Performance and usage instrumentation (not in list) + See email of 21Aug2007 for details. Priority: - Implement SDErrors (must return from SD) diff --git a/bacula/src/findlib/Makefile.in b/bacula/src/findlib/Makefile.in index 89c6354c34..0258418ebe 100644 --- a/bacula/src/findlib/Makefile.in +++ b/bacula/src/findlib/Makefile.in @@ -23,10 +23,10 @@ dummy: # LIBSRCS = find.c match.c find_one.c attribs.c create_file.c \ - bfile.c drivetype.c enable_priv.c fstype.c makepath.c \ + bfile.c drivetype.c enable_priv.c fstype.c mkpath.c \ savecwd.c LIBOBJS = find.o match.o find_one.o attribs.o create_file.o \ - bfile.o drivetype.o enable_priv.o fstype.o makepath.o \ + bfile.o drivetype.o enable_priv.o fstype.o mkpath.o \ savecwd.o .SUFFIXES: .c .o diff --git a/bacula/src/findlib/create_file.c b/bacula/src/findlib/create_file.c index 12f7c487ba..739ad8744b 100644 --- a/bacula/src/findlib/create_file.c +++ b/bacula/src/findlib/create_file.c @@ -71,7 +71,7 @@ static int path_already_seen(JCR *jcr, char *path, int pnl); */ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) { - int new_mode, parent_mode, mode; + mode_t new_mode, parent_mode, mode; uid_t uid; gid_t gid; int pnl; @@ -191,7 +191,7 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) * 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) { + if (!makepath(jcr, attr->ofname, parent_mode, parent_mode, uid, gid, 1)) { Dmsg1(10, "Could not make path. %s\n", attr->ofname); attr->ofname[pnl] = savechr; /* restore full name */ return CF_ERROR; @@ -357,7 +357,7 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) case FT_DIRBEGIN: case FT_DIREND: 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) { + if (!makepath(jcr, attr->ofname, new_mode, parent_mode, uid, gid, 0)) { return CF_ERROR; } /* diff --git a/bacula/src/findlib/makepath.c b/bacula/src/findlib/makepath.c deleted file mode 100644 index 24321ced55..0000000000 --- a/bacula/src/findlib/makepath.c +++ /dev/null @@ -1,415 +0,0 @@ -/* makepath.c -- Ensure that a directory path exists. - - Copyright (C) 1990, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by David MacKenzie and Jim Meyering. */ -/* - * Modified by Kern Sibbald for use in Bacula, December 2000 - * - * Version $Id$ - */ - -#include "bacula.h" -#include "jcr.h" -#include "savecwd.h" - - -#if !defined(S_ISDIR) && defined(S_IFDIR) -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_IRWXUGO -# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) -#endif - - -#ifndef S_ISUID -# define S_ISUID 04000 -#endif -#ifndef S_ISGID -# define S_ISGID 02000 -#endif -#ifndef S_ISVTX -# define S_ISVTX 01000 -#endif -#ifndef S_IRUSR -# define S_IRUSR 0200 -#endif -#ifndef S_IWUSR -# define S_IWUSR 0200 -#endif -#ifndef S_IXUSR -# define S_IXUSR 0100 -#endif - -#ifndef S_IRWXU -# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) -#endif - -#define WX_USR (S_IWUSR | S_IXUSR) - -#define quote(path) path - -extern void strip_trailing_slashes(); - -/* Attempt to create directory DIR (aka DIRPATH) with the specified MODE. - If CREATED_DIR_P is non-NULL, set *CREATED_DIR_P to non-zero if this - function creates DIR and to zero otherwise. Give a diagnostic and - return non-zero if DIR cannot be created or cannot be determined to - exist already. Use DIRPATH in any diagnostic, not DIR. - Note that if DIR already exists, this function will return zero - (indicating success) and will set *CREATED_DIR_P to zero. */ - -static int -make_dir(JCR *jcr, const char *dir, const char *dirpath, mode_t mode, int *created_dir_p) -{ - int fail = 0; - int created_dir; - int save_errno; - - Dmsg2(300, "make_dir mode=%o dir=%s\n", mode, dir); - created_dir = (mkdir(dir, mode) == 0); - save_errno = errno; - - if (!created_dir) { - struct stat stats; - - /* The mkdir and stat calls below may appear to be reversed. - They are not. It is important to call mkdir first and then to - call stat (to distinguish the three cases) only if mkdir fails. - The alternative to this approach is to `stat' each directory, - then to call mkdir if it doesn't exist. But if some other process - were to create the directory between the stat & mkdir, the mkdir - would fail with EEXIST. */ - - if (stat(dir, &stats)) { - berrno be; - be.set_errno(save_errno); - Jmsg(jcr, M_ERROR, 0, _("Cannot create directory %s: ERR=%s\n"), - dirpath, be.bstrerror()); - fail = 1; - } else if (!S_ISDIR(stats.st_mode)) { - Jmsg(jcr, M_ERROR, 0, _("%s exists but is not a directory\n"), quote(dirpath)); - fail = 1; - } else { - /* DIR (aka DIRPATH) already exists and is a directory. */ - } - } - - if (created_dir_p) { - *created_dir_p = created_dir; - } - - return fail; -} - -/* return non-zero if path is absolute or zero if relative. */ -int -isAbsolute(const char *path) -{ -#if defined(HAVE_WIN32) - return path[1] == ':' || IsPathSeparator(*path); /* drivespec:/blah is absolute */ -#else - return IsPathSeparator(*path); -#endif -} - -/* Ensure that the directory ARGPATH exists. - Remove any trailing slashes from ARGPATH before calling this function. - - Create any leading directories that don't already exist, with - permissions PARENT_MODE. - - If the last element of ARGPATH does not exist, create it as - a new directory with permissions MODE. - - If OWNER and GROUP are non-negative, use them to set the UID and GID of - any created directories. - - If VERBOSE_FMT_STRING is nonzero, use it as a printf format - string for printing a message after successfully making a directory, - with the name of the directory that was just made as an argument. - - If PRESERVE_EXISTING is non-zero and ARGPATH is an existing directory, - then do not attempt to set its permissions and ownership. - - Return 0 if ARGPATH exists as a directory with the proper - ownership and permissions when done, otherwise 1. */ - -int -make_path( - JCR *jcr, - const char *argpath, - int mode, - int parent_mode, - uid_t owner, - gid_t group, - int preserve_existing, - char *verbose_fmt_string) -{ - struct stat stats; - int retval = 0; - - if (stat(argpath, &stats)) { - char *slash; - int tmp_mode; /* Initial perms for leading dirs. */ - int re_protect; /* Should leading dirs be unwritable? */ - struct ptr_list { - char *dirname_end; - struct ptr_list *next; - }; - struct ptr_list *p, *leading_dirs = NULL; - saveCWD cwd; - char *basename_dir; - char *dirpath; - - /* Temporarily relax umask in case it's overly restrictive. */ - mode_t oldmask = umask(0); - - /* Make a copy of ARGPATH that we can scribble NULs on. */ - dirpath = (char *)alloca(strlen(argpath) + 1); - strcpy (dirpath, argpath); - strip_trailing_slashes(dirpath); - - /* If leading directories shouldn't be writable or executable, - or should have set[ug]id or sticky bits set and we are setting - their owners, we need to fix their permissions after making them. */ - if (((parent_mode & WX_USR) != WX_USR) - || ((owner != (uid_t)-1 || group != (gid_t)-1) - && (parent_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0)) { - tmp_mode = S_IRWXU; - re_protect = 1; - } else { - tmp_mode = parent_mode; - re_protect = 0; - } - -#if defined(HAVE_WIN32) - /* chdir can fail if permissions are sufficiently restricted since I don't think - backup/restore security rights affect ChangeWorkingDirectory */ - - /* Validate drive letter */ - if (dirpath[1] == ':') { - char drive[4] = "X:\\"; - - drive[0] = dirpath[0]; - - UINT drive_type = GetDriveType(drive); - - if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) { - Jmsg(jcr, M_ERROR, 0, _("%c: is not a valid drive\n"), dirpath[0]); - return 1; - } - - if (dirpath[2] == '\0') { - return 0; - } - - slash = &dirpath[3]; - } else { - slash = dirpath; - } -#else - /* If we can record the current working directory, we may be able - to do the chdir optimization. */ - cwd.save(jcr); - - slash = dirpath; -#endif - - /* If we've saved the cwd and DIRPATH is an absolute pathname, - we must chdir to `/' in order to enable the chdir optimization. - So if chdir ("/") fails, turn off the optimization. */ - if (cwd.is_saved() && isAbsolute(dirpath) && (chdir("/") < 0)) { - cwd.release(); - } - - /* Skip over leading slashes. */ - while (IsPathSeparator(*slash)) - slash++; - - for ( ; ; ) { - int newly_created_dir; - int fail; - - /* slash points to the leftmost unprocessed component of dirpath. */ - basename_dir = slash; - slash = first_path_separator(slash); - if (slash == NULL) { - break; - } - - /* If we're *not* doing chdir before each mkdir, then we have to refer - to the target using the full (multi-component) directory name. */ - if (!cwd.is_saved()) { - basename_dir = dirpath; - } - - *slash = '\0'; - fail = make_dir(jcr, basename_dir, dirpath, tmp_mode, &newly_created_dir); - if (fail) { - umask(oldmask); - cwd.restore(jcr); - return 1; - } - - if (newly_created_dir) { - Dmsg0(300, "newly_created_dir\n"); - - if ((owner != (uid_t)-1 || group != (gid_t)-1) - && chown(basename_dir, owner, group) -#if defined(AFS) && defined (EPERM) - && errno != EPERM -#endif - ) { - /* Note, if we are restoring as NON-root, this may not be fatal */ - berrno be; - Jmsg(jcr, M_ERROR, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - } - Dmsg0(300, "Chown done.\n"); - - if (re_protect) { - struct ptr_list *pnew = (struct ptr_list *) - alloca(sizeof (struct ptr_list)); - pnew->dirname_end = slash; - pnew->next = leading_dirs; - leading_dirs = pnew; - Dmsg0(300, "re_protect\n"); - } - } - - /* If we were able to save the initial working directory, - then we can use chdir to change into each directory before - creating an entry in that directory. This avoids making - stat and mkdir process O(n^2) file name components. */ - if (cwd.is_saved() && chdir(basename_dir) < 0) { - berrno be; - Jmsg(jcr, M_ERROR, 0, _("Cannot chdir to directory, %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - umask(oldmask); - - cwd.restore(jcr); - return 1; - } - - *slash++ = '/'; - - /* Avoid unnecessary calls to `stat' when given - pathnames containing multiple adjacent slashes. */ - while (IsPathSeparator(*slash)) - slash++; - } /* end while (1) */ - - if (!cwd.is_saved()) { - basename_dir = dirpath; - } - - /* We're done making leading directories. - Create the final component of the path. */ - - Dmsg1(300, "Create final component. mode=%o\n", mode); - if (make_dir(jcr, basename_dir, dirpath, mode, NULL)) { - umask(oldmask); - cwd.restore(jcr); - return 1; - } - - /* Done creating directories. Restore original umask. */ - umask(oldmask); - - if (owner != (uid_t)-1 || group != (gid_t)-1) { - if (chown(basename_dir, owner, group) -#ifdef AFS - && errno != EPERM -#endif - ) - { - berrno be; - Jmsg(jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - } - } - - /* The above chown may have turned off some permission bits in MODE. - Another reason we may have to use chmod here is that mkdir(2) is - required to honor only the file permission bits. In particular, - it need not honor the `special' bits, so if MODE includes any - special bits, set them here. */ - if (mode & ~S_IRWXUGO) { - Dmsg1(300, "Final chmod mode=%o\n", mode); - } - if ((mode & ~S_IRWXUGO) && chmod(basename_dir, mode)) { - berrno be; - Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - } - - if (!cwd.restore(jcr)) { - return 1; - } - - /* If the mode for leading directories didn't include owner "wx" - privileges, we have to reset their protections to the correct - value. */ - for (p = leading_dirs; p != NULL; p = p->next) { - *(p->dirname_end) = '\0'; - Dmsg2(300, "Reset parent mode=%o dir=%s\n", parent_mode, dirpath); - if (chmod(dirpath, parent_mode)) { - berrno be; - Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - } - } - } else { - /* We get here if the entire path already exists. */ - - const char *dirpath = argpath; - - if (!S_ISDIR(stats.st_mode)) { - Jmsg(jcr, M_ERROR, 0, _("%s exists but is not a directory\n"), quote(dirpath)); - return 1; - } - - if (!preserve_existing) { - Dmsg0(300, "Do not preserve existing.\n"); - /* chown must precede chmod because on some systems, - chown clears the set[ug]id bits for non-superusers, - resulting in incorrect permissions. - On System V, users can give away files with chown and then not - be able to chmod them. So don't give files away. */ - - if ((owner != (uid_t)-1 || group != (gid_t)-1) - && chown(dirpath, owner, group) -#ifdef AFS - && errno != EPERM -#endif - ) { - berrno be; - Jmsg(jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - } - if (chmod(dirpath, mode)) { - berrno be; - Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), - quote(dirpath), be.bstrerror()); - } - Dmsg2(300, "pathexists chmod mode=%o dir=%s\n", mode, dirpath); - } - } - return retval; -} diff --git a/bacula/src/findlib/mkpath.c b/bacula/src/findlib/mkpath.c new file mode 100644 index 0000000000..ca2a0c113e --- /dev/null +++ b/bacula/src/findlib/mkpath.c @@ -0,0 +1,226 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2007-2007 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ + +/* + * Kern Sibbald, September MMVII + * + * This is tricky code, especially when writing from scratch. Fortunately, + * a non-copyrighted version of mkdir was available to consult. + * + * Version $Id$ + */ +#include "bacula.h" +#include "jcr.h" + +static bool makedir(JCR *jcr, char *path, mode_t mode, int *created) +{ + struct stat statp; + + if (mkdir(path, mode) != 0) { + berrno be; + *created = false; + if (stat(path, &statp) != 0) { + Jmsg(jcr, M_ERROR, 0, _("Cannot create directory %s: ERR=%s\n"), + path, be.bstrerror()); + return false; + } else if (!S_ISDIR(statp.st_mode)) { + Jmsg(jcr, M_ERROR, 0, _("%s exists but is not a directory.\n"), path); + return false; + } + return true; /* directory exists */ + } + *created = true; + return true; +} + +static void set_own_mod(JCR *jcr, char *path, uid_t owner, gid_t group, mode_t mode) +{ + if (chown(path, owner, group) != 0 +#ifdef AFS + && errno != EPERM +#endif + ) { + berrno be; + Jmsg(jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"), + path, be.bstrerror()); + } + if (chmod(path, mode) != 0) { + berrno be; + Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), + path, be.bstrerror()); + } +} + +/* + * mode is the mode bits to use in creating a new directory + * + * parent_mode are the parent's modes if we need to create parent + * directories. + * + * owner and group are to set on any created dirs + * + * keep_dir_modes if set means don't change mode bits if dir exists + */ +bool makepath(JCR *jcr, const char *apath, mode_t mode, mode_t parent_mode, + uid_t owner, gid_t group, int keep_dir_modes) +{ + struct stat statp; + mode_t omask, tmode; + char *path = (char *)apath; + char *p; + int len; + bool ok = false; + int created; + char new_dir[5000]; + int ndir = 0; + int i = 0; + int max_dirs = (int)sizeof(new_dir); + + if (stat(path, &statp) == 0) { /* Does dir exist? */ + if (!S_ISDIR(statp.st_mode)) { + Jmsg(jcr, M_ERROR, 0, _("%s exists but is not a directory.\n"), path); + return false; + } + /* Full path exists */ + if (keep_dir_modes) { + return true; + } + set_own_mod(jcr, path, owner, group, mode); + return true; + } + omask = umask(0); + umask(omask); + len = strlen(apath); + path = (char *)alloca(len+1); + bstrncpy(path, apath, len+1); + strip_trailing_slashes(path); + /* + * Now for one of the complexities. If we are not running as root, + * then if the parent_mode does not have wx user perms, or we are + * setting the userid or group, and the parent_mode has setuid, setgid, + * or sticky bits, we must create the dir with open permissions, then + * go back and patch all the dirs up with the correct perms. + * Solution, set everything to 0777, then go back and reset them at the + * end. + */ + tmode = 0777; + +#if defined(HAVE_WIN32) + /* Validate drive letter */ + if (path[1] == ':') { + char drive[4] = "X:\\"; + + drive[0] = path[0]; + + UINT drive_type = GetDriveType(drive); + + if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) { + Jmsg(jcr, M_ERROR, 0, _("%c: is not a valid drive.\n"), path[0]); + goto bail_out; + } + + if (path[2] == '\0') { /* attempt to create a drive */ + ok = true; + goto bail_out; /* OK, it is already there */ + } + + p = &path[3]; + } else { + p = path; + } +#else + p = path; +#endif + + /* Skip leading slash(es) */ + while (IsPathSeparator(*p)) { + p++; + } + while ((p = first_path_separator(p))) { + char save_p; + save_p = *p; + *p = 0; + if (!makedir(jcr, path, tmode, &created)) { + goto bail_out; + } + if (ndir < max_dirs) { + new_dir[ndir++] = created; + } + *p = save_p; + while (IsPathSeparator(*p)) { + p++; + } + } + /* Create final component */ + if (!makedir(jcr, path, tmode, &created)) { + goto bail_out; + } + if (ndir < max_dirs) { + new_dir[ndir++] = created; + } + if (ndir >= max_dirs) { + Jmsg(jcr, M_WARNING, 0, _("Too many subdirectories. Some permissions not reset.\n")); + } + + /* Now set the proper owner and modes */ +#if defined(HAVE_WIN32) + if (path[1] == ':') { + p = &path[3]; + } else { + p = path; + } +#else + p = path; +#endif + /* Skip leading slash(es) */ + while (IsPathSeparator(*p)) { + p++; + } + while ((p = first_path_separator(p))) { + char save_p; + save_p = *p; + *p = 0; + if (i < ndir && new_dir[i++] && !keep_dir_modes) { + set_own_mod(jcr, path, owner, group, parent_mode); + } + *p = save_p; + while (IsPathSeparator(*p)) { + p++; + } + } + + /* Set for final component */ + if (i < ndir && new_dir[i++]) { + set_own_mod(jcr, path, owner, group, mode); + } + + ok = true; +bail_out: + umask(omask); + return ok; +} diff --git a/bacula/src/findlib/protos.h b/bacula/src/findlib/protos.h index a7c5f04f2e..2f8e7fdc3a 100644 --- a/bacula/src/findlib/protos.h +++ b/bacula/src/findlib/protos.h @@ -72,9 +72,9 @@ int enable_backup_privileges(JCR *jcr, int ignore_errors); /* from makepath.c */ -int make_path(JCR *jcr, const char *argpath, int mode, - int parent_mode, uid_t owner, gid_t group, - int preserve_existing, char *verbose_fmt_string); +int makepath(JCR *jcr, const char *path, mode_t mode, + mode_t parent_mode, uid_t owner, gid_t group, + int keep_dir_modes); /* from fstype.c */ bool fstype(const char *fname, char *fs, int fslen);