]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/findlib/mkpath.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / findlib / mkpath.c
index 38308ea575d78f3b101855c3f55b659a66d3b729..e1e19be289e0ee2ae9257cbb37cfaddbdec8c672 100644 (file)
 /*
-   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.
-*/
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2018 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
 
+   This notice must be preserved when any source code is
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
+*/
 /*
  *  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$
+ * ***FIXME*** the mkpath code could be significantly optimized by
+ *   walking up the path chain from the bottom until it either gets
+ *   to the top or finds an existing directory then walk back down
+ *   creating the path components.  Currently, it always starts at
+ *   the top, which can be rather inefficient for long path names.
+ *
  */
 #include "bacula.h"
 #include "jcr.h"
 
+#define dbglvl 50
+
+/*
+ * For old systems that don't have lchown() or lchmod()
+ */
+#ifndef HAVE_LCHOWN
+#define lchown chown
+#endif
+#ifndef HAVE_LCHMOD
+#define lchmod chmod
+#endif
+
+/* Defined in attribs.c */
+void set_own_mod(ATTR *attr, char *path, uid_t owner, gid_t group, mode_t mode);
+
+typedef struct PrivateCurDir {
+   hlink link;
+   char fname[1];
+} CurDir;
+
+/* Initialize the path hash table */
+static bool path_list_init(JCR *jcr)
+{
+   CurDir *elt = NULL;
+   jcr->path_list = (htable *)malloc(sizeof(htable));
+
+   /* Hard to know in advance how many directories will
+    * be stored in this hash
+    */
+   jcr->path_list->init(elt, &elt->link, 10000);
+   return true;
+}
+
+/* Add a path to the hash when we create a directory
+ * with the replace=NEVER option
+ */
+bool path_list_add(JCR *jcr, uint32_t len, char *fname)
+{
+   bool ret = true;
+   CurDir *item;
+
+   if (!jcr->path_list) {
+      path_list_init(jcr);
+   }
+
+   /* we store CurDir, fname in the same chunk */
+   item = (CurDir *)jcr->path_list->hash_malloc(sizeof(CurDir)+len+1);
+
+   memset(item, 0, sizeof(CurDir));
+   memcpy(item->fname, fname, len+1);
+
+   jcr->path_list->insert(item->fname, item);
+
+   Dmsg1(dbglvl, "add fname=<%s>\n", fname);
+   return ret;
+}
+
+void free_path_list(JCR *jcr)
+{
+   if (jcr->path_list) {
+      jcr->path_list->destroy();
+      free(jcr->path_list);
+      jcr->path_list = NULL;
+   }
+}
+
+bool path_list_lookup(JCR *jcr, char *fname)
+{
+   bool found=false;
+   char bkp;
+
+   if (!jcr->path_list) {
+      return false;
+   }
+
+   /* Strip trailing / */
+   int len = strlen(fname);
+   if (len == 0) {
+      return false;
+   }
+   len--;
+   bkp = fname[len];
+   if (fname[len] == '/') {       /* strip any trailing slash */
+      fname[len] = 0;
+   }
+
+   CurDir *temp = (CurDir *)jcr->path_list->lookup(fname);
+   if (temp) {
+      found=true;
+   }
+
+   Dmsg2(dbglvl, "lookup <%s> %s\n", fname, found?"ok":"not ok");
+
+   fname[len] = bkp;            /* restore last / */
+   return found;
+}
+
 static bool makedir(JCR *jcr, char *path, mode_t mode, int *created)
 {
    struct stat statp;
@@ -44,7 +136,7 @@ static bool makedir(JCR *jcr, char *path, mode_t mode, int *created)
    if (mkdir(path, mode) != 0) {
       berrno be;
       *created = false;
-      if (stat(path, &statp) != 0) {
+      if (lstat(path, &statp) != 0) {
          Jmsg2(jcr, M_ERROR, 0, _("Cannot create directory %s: ERR=%s\n"),
               path, be.bstrerror());
          return false;
@@ -54,32 +146,31 @@ static bool makedir(JCR *jcr, char *path, mode_t mode, int *created)
       }
       return true;                 /* directory exists */
    }
-   *created = true;
-   return true;
-}
-
-static void set_own_mod(ATTR *attr, char *path, uid_t owner, gid_t group, mode_t mode)
-{
-   if (chown(path, owner, group) != 0 && attr->uid == 0
-#ifdef AFS
-        && errno != EPERM
-#endif
-   ) {
-      berrno be;
-      Jmsg2(attr->jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"),
-           path, be.bstrerror());
+#if 0
+   /* TODO: This code rely on statp that is not initialized, we need to do a stat() */
+   if (S_ISLNK(statp.st_mode)) {
+      /*
+       * Note, we created a directory, not a link, so if we find a
+       *  link, there is a security problem here.
+       */
+      Jmsg1(jcr, M_FATAL, 0, _("Security problem!! We created directory %s, but it is a link.\n"),
+         path);
+      return false;
    }
-   if (chmod(path, mode) != 0 && attr->uid == 0) {
-      berrno be;
-      Jmsg2(attr->jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"),
-           path, be.bstrerror());
+#endif
+   if (jcr->keep_path_list) {
+      /* When replace=NEVER, we keep track of all directories newly created */
+      path_list_add(jcr, strlen(path), path);
    }
+
+   *created = true;
+   return true;
 }
 
 /*
  * 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 
+ * parent_mode are the parent's modes if we need to create parent
  *    directories.
  *
  * owner and group are to set on any created dirs
@@ -190,6 +281,11 @@ bool makepath(ATTR *attr, const char *apath, mode_t mode, mode_t parent_mode,
 
    /* Now set the proper owner and modes */
 #if defined(HAVE_WIN32)
+
+   /* Don't propagate the hidden or encrypted attributes to parent directories */
+   parent_mode &= ~S_ISVTX;
+   parent_mode &= ~S_ISGID;
+
    if (path[1] == ':') {
       p = &path[3];
    } else {