]> git.sur5r.net Git - bacula/bacula/commitdiff
Mult Vols + fix restore hard links + file permissions
authorKern Sibbald <kern@sibbald.com>
Sat, 1 Feb 2003 18:16:08 +0000 (18:16 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 1 Feb 2003 18:16:08 +0000 (18:16 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@331 91ce42f0-d328-0410-95d8-f526ca767f89

28 files changed:
bacula/kernstodo
bacula/src/cats/make_sqlite_tables.in
bacula/src/dird/ua_restore.c
bacula/src/dird/verify.c
bacula/src/filed/backup.c
bacula/src/filed/restore.c
bacula/src/filed/verify.c
bacula/src/findlib/attribs.c
bacula/src/findlib/find.h
bacula/src/findlib/find_one.c
bacula/src/findlib/protos.h
bacula/src/lib/.cvsignore
bacula/src/lib/Makefile.in
bacula/src/lib/bnet_pkt.c
bacula/src/lib/daemon.c
bacula/src/stored/acquire.c
bacula/src/stored/append.c
bacula/src/stored/bcopy.c
bacula/src/stored/bextract.c
bacula/src/stored/bls.c
bacula/src/stored/bscan.c
bacula/src/stored/btape.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/protos.h
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h
bacula/src/version.h

index 1257c5fb5eab638db94a8d9f6ba1bf00dc0454ad..07be04fd789365520d0dab1e0213df5b0ceae736 100644 (file)
@@ -15,6 +15,13 @@ Testing to do: (painful)
 - blocksize recognition code.
 
 For 1.30 release:
+- Fix restore of hard linked file.
+- Implement FileOptions (see end of this document)
+- Implement Bacula plugins -- design API
+- Make bcopy read through bad tape records.
+- Fix read_record to handle multiple sessions.
+- Program files (i.e. execute a program to read/write files).
+  Pass read date of last backup, size of file last time.
 - Add Signature type to File DB record.
 - CD into subdirectory when open()ing files for backup to
   speed up things.  Test with testfind().
@@ -32,9 +39,6 @@ For 1.30 release:
 - Implement finer multiprocessing options.
 - Solaris -I on tar for include list
 - Enable avoid backing up archive device (findlib/find_one.c:128)
-- Implement FileOptions (see end of this document)
-- Implement Bacula plugins -- design API
-- Make bcopy read through bad tape records.
 - Need a verbose mode in restore, perhaps to bsr.
 - bscan without -v is too quiet -- perhaps show jobs.
 - Add code to reject whole blocks if not wanted on restore.
@@ -48,9 +52,6 @@ For 1.30 release:
   records -- one per Job, maybe a JCR or some other structure with
   a block and a record.
 - Figure out how to do a bare metal Windows restore
-- Fix read_record to handle multiple sessions.
-- Program files (i.e. execute a program to read/write files).
-  Pass read date of last backup, size of file last time.
 - Put system type returned by FD into catalog.
 - Possibly add email to Watchdog if drive is unmounted too
   long and a job is waiting on the drive.
@@ -827,4 +828,5 @@ Done: (see kernsdone for more)
 ====== 1.30 =======
 - Implement SHA1
 - Get correct error status from run_program or open_bpipe().    
-
+- Restrict permissions on File Volumes (now 0640).                   
+- Umasked 022 daemons
index d9516deda4b66c7db191dff31ed6f6c1815c2c60..55e5993366adde62f76b9aa0d208c66f1a5e3071 100644 (file)
@@ -31,7 +31,7 @@ CREATE TABLE File (
    FilenameId INTEGER REFERENCES Filename NOT NULL,
    MarkId INTEGER UNSIGNED DEFAULT 0,
    LStat VARCHAR(255) NOT NULL,
-   MD5 VARCHAR(25) NOT NULL,
+   MD5 VARCHAR(255) NOT NULL,
    PRIMARY KEY(FileId) 
    );
 
index c808dcd6bd64cc1f6932695a04b718c7e7ffc04b..7ab4a8848c13b32add952d6b89ade2f9f6b4774c 100644 (file)
@@ -906,14 +906,41 @@ static int insert_tree_handler(void *ctx, int num_fields, char **row)
  *  down the tree setting all children if the 
  *  node is a directory.
  */
-static void set_extract(TREE_NODE *node, int value)
+static void set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, int value)
 {
    TREE_NODE *n;
+   FILE_DBR fdbr;
+   struct stat statp;
 
    node->extract = value;
+   /* For a non-file (i.e. directory), we see all the children */
    if (node->type != TN_FILE) {
       for (n=node->child; n; n=n->sibling) {
-        set_extract(n, value);
+        set_extract(ua, n, tree, value);
+      }
+   } else if (value) {
+      char cwd[2000];
+      /* Ordinary file, we get the full path, look up the
+       * attributes, decode them, and if we are hard linked to
+       * a file that was saved, we must load that file too.
+       */
+      tree_getpath(node, cwd, sizeof(cwd));
+      fdbr.FileId = 0;
+      fdbr.JobId = node->JobId;
+      if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) {
+        uint32_t LinkFI;
+        decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
+        /* If we point to a hard linked file, traverse the tree to
+         * find that file, and mark it for restoration as well.
+         */
+        if (LinkFI) {
+           for (n=first_tree_node(tree->root); n; n=next_tree_node(n)) {
+              if (n->FileIndex == LinkFI) {
+                 n->extract = 1;
+                 break;
+              }
+           }
+        }
       }
    }
 }
@@ -929,7 +956,7 @@ static int markcmd(UAContext *ua, TREE_CTX *tree)
    }
    for (node = tree->node->child; node; node=node->sibling) {
       if (fnmatch(ua->argk[1], node->fname, 0) == 0) {
-        set_extract(node, 1);
+        set_extract(ua, node, tree, 1);
       }
    }
    return 1;
@@ -993,14 +1020,15 @@ static int lscmd(UAContext *ua, TREE_CTX *tree)
 extern char *getuser(uid_t uid);
 extern char *getgroup(gid_t gid);
 
-static void ls_output(char *buf, char *fname, struct stat *statp)
+/*
+ * This is actually the long form used for "dir"
+ */
+static void ls_output(char *buf, char *fname, int extract, struct stat *statp)
 {
    char *p, *f;
    char ec1[30];
    int n;
 
-// Dmsg2(000, "%s mode=0%o\n", fname, statp->st_mode);
-
    p = encode_mode(statp->st_mode, buf);
    n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
    p += n;
@@ -1010,7 +1038,11 @@ static void ls_output(char *buf, char *fname, struct stat *statp)
    p += n;
    p = encode_time(statp->st_ctime, p);
    *p++ = ' ';
-   *p++ = ' ';
+   if (extract) {
+      *p++ = '*';
+   } else {
+      *p++ = ' ';
+   }
    for (f=fname; *f; )
       *p++ = *f++;
    *p = 0;
@@ -1037,8 +1069,9 @@ static int dircmd(UAContext *ua, TREE_CTX *tree)
         fdbr.FileId = 0;
         fdbr.JobId = node->JobId;
         if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) {
-           decode_stat(fdbr.LStat, &statp); /* decode stat pkt */
-           ls_output(buf, cwd, &statp);
+           uint32_t LinkFI;
+           decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
+           ls_output(buf, cwd, node->extract, &statp);
             bsendmsg(ua, "%s\n", buf);
         } else {
            /* Something went wrong getting attributes -- print name */
@@ -1118,7 +1151,7 @@ static int unmarkcmd(UAContext *ua, TREE_CTX *tree)
    }
    for (node = tree->node->child; node; node=node->sibling) {
       if (fnmatch(ua->argk[1], node->fname, 0) == 0) {
-        set_extract(node, 0);
+        set_extract(ua, node, tree, 0);
       }
    }
    return 1;
index cc62515d0e5500663ab70e67cc962d7f9b943ad6..f365a2796de98e7b6e36f5a6ef9dbad2012f7042 100644 (file)
@@ -432,10 +432,11 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
        * Got attributes stream, decode it
        */
       if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_WIN32_ATTRIBUTES) {
+        uint32_t LinkFIf, LinkFIc;
          Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
         jcr->JobFiles++;
         jcr->FileIndex = file_index;    /* remember attribute file_index */
-        decode_stat(attr, &statf);  /* decode file stat packet */
+        decode_stat(attr, &statf, &LinkFIf);  /* decode file stat packet */
         do_SIG = NO_SIG;
         jcr->fn_printed = FALSE;
         strcpy(jcr->fname, fname);  /* move filename into JCR */
@@ -462,7 +463,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
 
          Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname, 
            file_index, Opts_SIG);
-        decode_stat(fdbr.LStat, &statc); /* decode catalog stat */
+        decode_stat(fdbr.LStat, &statc, &LinkFIc); /* decode catalog stat */
         /*
          * Loop over options supplied by user and verify the
          * fields he requests.
index 75a5da3e0222f69b299a33267bcba9a31608010c..62719ef0613cbd4b9b08291c5155ae1a57b48dba 100644 (file)
@@ -196,12 +196,13 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr)
    }
 
    Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
-   encode_stat(attribs, &ff_pkt->statp);
+   encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI);
    stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
    Dmsg3(200, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
      
    P(jcr->mutex);
    jcr->JobFiles++;                   /* increment number of files sent */
+   ff_pkt->FileIndex = jcr->JobFiles;  /* return FileIndex */
    pm_strcpy(&jcr->last_fname, ff_pkt->fname);
    V(jcr->mutex);
     
index 7447678834d8df0dc60f843f53b1710d6d9feb1d..bc946757a22b101ecacba59f73468aa020e7fc18 100644 (file)
@@ -120,6 +120,7 @@ void do_restore(JCR *jcr)
       /* File Attributes stream */
       if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_WIN32_ATTRIBUTES) {
         char *ap, *lp, *fp, *apex;
+        uint32_t LinkFI;
 
          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
         /* If extracting, it was from previous stream, so
@@ -207,7 +208,7 @@ void do_restore(JCR *jcr)
 
          Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", fname, ap, attribsEx);
 
-        decode_stat(ap, &statp);
+        decode_stat(ap, &statp, &LinkFI);
         /*
          * Prepend the where directory so that the
          * files are put where the user wants.
index 20214f086d088407498ec8b5c107d0a52d3f9073..3bff5a1d51f80c7685ec71f47db9c0fa83b7b2fc 100644 (file)
@@ -149,7 +149,7 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt)
       fid = -1;
    }
 
-   encode_stat(attribs, &ff_pkt->statp);
+   encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI);
      
    P(jcr->mutex);
    jcr->JobFiles++;                 /* increment number of files sent */
index 8ef3d7b359d175f0fc9e3e995d98e3880af89efe..7aee3723e67c70fe5093aa56f14d1e5ca1c00f7b 100755 (executable)
@@ -54,7 +54,7 @@ void win_error(void *jcr, char *prefix, POOLMEM *ofile);
 
 
 /* Encode a stat structure into a base64 character string */
-void encode_stat(char *buf, struct stat *statp)
+void encode_stat(char *buf, struct stat *statp, uint32_t LinkFI)
 {
    char *p = buf;
    /*
@@ -89,6 +89,8 @@ void encode_stat(char *buf, struct stat *statp)
    p += to_base64((int64_t)statp->st_mtime, p);
    *p++ = ' ';
    p += to_base64((int64_t)statp->st_ctime, p);
+   *p++ = ' ';
+   p += to_base64((int64_t)LinkFI, p);
    *p = 0;
    return;
 }
@@ -97,7 +99,7 @@ void encode_stat(char *buf, struct stat *statp)
 
 /* Decode a stat packet from base64 characters */
 void
-decode_stat(char *buf, struct stat *statp)
+decode_stat(char *buf, struct stat *statp, uint32_t *LinkFI) 
 {
    char *p = buf;
    int64_t val;
@@ -140,6 +142,14 @@ decode_stat(char *buf, struct stat *statp)
    p++;
    p += from_base64(&val, p);
    statp->st_ctime = val;
+   /* Optional FileIndex of hard linked file data */
+   if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
+      p++;
+      p += from_base64(&val, p);
+      *LinkFI = (uint32_t)val;
+  } else {
+      *LinkFI = 0;
+  }
 }
 
 /*
index 00c17cb49b7a048d0ea95c689787f3e6f9c9265a..4318f9ed24bed266858f49ca149832e05991bd62 100755 (executable)
@@ -130,6 +130,9 @@ typedef struct ff {
    char *link;                        /* link if file linked */
    POOLMEM *sys_fname;                /* system filename */
    struct stat statp;                 /* stat packet */
+   uint32_t FileIndex;                /* FileIndex of this file */
+   uint32_t LinkFI;                   /* FileIndex of main hard linked file */
+   struct f_link *linked;             /* Set if we are hard linked */
    int type;                          /* FT_ type from above */
    int fid;                           /* file id if opened */
    int flags;                         /* control flags */
index 8bd209fb45fcdcc5f68f5289328e39a3d28bb612..39a58ccff104951d696fe11f51e3f8a3ef980e02 100755 (executable)
@@ -38,14 +38,19 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
 
 
 /*
- * Structure for keeping track of hard linked files
+ * Structure for keeping track of hard linked files, we   
+ *   keep an entry for each hardlinked file that we save,
+ *   which is the first one found. For all the other files that
+ *   are linked to this one, we save only the directory
+ *   entry so we can link it.
  */
 struct f_link {
     struct f_link *next;
-    dev_t dev;
-    ino_t ino;
+    dev_t dev;                       /* device */
+    ino_t ino;                       /* inode with device is unique */
     short linkcount;
-    char name[1];
+    uint32_t FileIndex;              /* Bacula FileIndex of this file */
+    char name[1];                    /* The name */
 };
 
 
@@ -124,7 +129,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt),
        return handle_file(ff_pkt, pkt);
    }
 #endif
-
+   ff_pkt->LinkFI = 0;
    /* 
     * Handle hard linked files
     *
@@ -141,173 +146,212 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt),
 
        struct f_link *lp;
 
-       /* Search link list of hard linked files */
-       for (lp = ff_pkt->linklist; lp; lp = lp->next)
-         if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) {
-             ff_pkt->link = lp->name;
-             ff_pkt->type = FT_LNKSAVED;       /* Handle link, file already saved */
-             return handle_file(ff_pkt, pkt);
-         }
-
-       /* File not previously dumped. Chain it into our list. */
-       lp = (struct f_link *)bmalloc(sizeof(struct f_link) + strlen(fname) +1);
-       lp->ino = ff_pkt->statp.st_ino;
-       lp->dev = ff_pkt->statp.st_dev;
-       strcpy(lp->name, fname);
-       lp->next = ff_pkt->linklist;
-       ff_pkt->linklist = lp;
+      /* Search link list of hard linked files */
+      for (lp = ff_pkt->linklist; lp; lp = lp->next)
+        if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) {
+            ff_pkt->link = lp->name;
+            ff_pkt->type = FT_LNKSAVED;       /* Handle link, file already saved */
+            ff_pkt->LinkFI = lp->FileIndex;
+            return handle_file(ff_pkt, pkt);
+        }
+
+      /* File not previously dumped. Chain it into our list. */
+      lp = (struct f_link *)bmalloc(sizeof(struct f_link) + strlen(fname) +1);
+      lp->ino = ff_pkt->statp.st_ino;
+      lp->dev = ff_pkt->statp.st_dev;
+      strcpy(lp->name, fname);
+      lp->next = ff_pkt->linklist;
+      ff_pkt->linklist = lp;
+      ff_pkt->linked = lp;           /* mark saved link */
+   } else {
+      ff_pkt->linked = NULL;
    }
 
    /* This is not a link to a previously dumped file, so dump it.  */
    if (S_ISREG(ff_pkt->statp.st_mode)) {
-       off_t sizeleft;
-
-       sizeleft = ff_pkt->statp.st_size;
-
-       /* Don't bother opening empty, world readable files.  Also do not open
-         files when archive is meant for /dev/null.  */
-       if (ff_pkt->null_output_device || (sizeleft == 0
-              && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
-         ff_pkt->type = FT_REGE;
-       } else {
-         ff_pkt->type = FT_REG;
-       }
-       return handle_file(ff_pkt, pkt);
+      off_t sizeleft;
+
+      sizeleft = ff_pkt->statp.st_size;
+
+      /* Don't bother opening empty, world readable files.  Also do not open
+        files when archive is meant for /dev/null.  */
+      if (ff_pkt->null_output_device || (sizeleft == 0
+             && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
+        ff_pkt->type = FT_REGE;
+      } else {
+        ff_pkt->type = FT_REG;
+      }
+      rtn_stat = handle_file(ff_pkt, pkt);
+      if (ff_pkt->linked) {
+        ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+      }
+      return rtn_stat;
+
 
    } else if (S_ISLNK(ff_pkt->statp.st_mode)) {
-       int size;
-       char *buffer = (char *)alloca(path_max + name_max + 2);
-
-       size = readlink(fname, buffer, path_max + name_max + 1);
-       if (size < 0) {
-          /* Could not follow link */                             
-          ff_pkt->type = FT_NOFOLLOW;
-          ff_pkt->ff_errno = errno;
-          return handle_file(ff_pkt, pkt);
-       }
-       buffer[size] = 0;
-       ff_pkt->link = buffer;
-       ff_pkt->type = FT_LNK;          /* got a real link */
-       return handle_file(ff_pkt, pkt);
+      int size;
+      char *buffer = (char *)alloca(path_max + name_max + 2);
+
+      size = readlink(fname, buffer, path_max + name_max + 1);
+      if (size < 0) {
+        /* Could not follow link */                             
+        ff_pkt->type = FT_NOFOLLOW;
+        ff_pkt->ff_errno = errno;
+        rtn_stat = handle_file(ff_pkt, pkt);
+        if (ff_pkt->linked) {
+           ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+        }
+        return rtn_stat;
+      }
+      buffer[size] = 0;
+      ff_pkt->link = buffer;
+      ff_pkt->type = FT_LNK;          /* got a real link */
+      rtn_stat = handle_file(ff_pkt, pkt);
+      if (ff_pkt->linked) {
+        ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+      }
+      return rtn_stat;
 
    } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
-       DIR *directory;
-       struct dirent *entry, *result;
-       char *link;
-       int link_len;
-       int len;
-       int status;
-       dev_t our_device = ff_pkt->statp.st_dev;
-
-       if (access(fname, R_OK) == -1 && geteuid() != 0) {
-          /* Could not access() directory */
-          ff_pkt->type = FT_NOACCESS;
-          ff_pkt->ff_errno = errno;
-          return handle_file(ff_pkt, pkt);
-       }
-
-       /* Build a canonical directory name with a trailing slash. */
-       len = strlen(fname);
-       link_len = len + 200;
-       link = (char *)bmalloc(link_len + 2);
-       bstrncpy(link, fname, link_len);
-       /* Strip all trailing slashes */
-       while (len >= 1 && link[len - 1] == '/')
-        len--;
-       link[len++] = '/';             /* add back one */
-       link[len] = 0;
-
-       ff_pkt->link = link;
-       if (ff_pkt->incremental &&
-          (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
-           ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
-         /* Incremental option, directory entry not changed */
-         ff_pkt->type = FT_DIRNOCHG;
-       } else {
-         ff_pkt->type = FT_DIR;
-       }
-       handle_file(ff_pkt, pkt);       /* handle directory entry */
-
-       ff_pkt->link = ff_pkt->fname;     /* reset "link" */
-
-       /* 
-       * Do not decend into subdirectories (recurse) if the
-       * user has turned it off for this directory.
-       */
-       if (ff_pkt->flags & FO_NO_RECURSION) {
-         free(link);
-         /* No recursion into this directory */
-         ff_pkt->type = FT_NORECURSE;
-         return handle_file(ff_pkt, pkt);
-       }
-
-       /* 
-       * See if we are crossing file systems, and
-       * avoid doing so if the user only wants to dump one file system.
-       */
-       if (!top_level && !(ff_pkt->flags & FO_MULTIFS) &&
-           parent_device != ff_pkt->statp.st_dev) {
-         free(link);
-         /* returning here means we do not handle this directory */
-         ff_pkt->type = FT_NOFSCHG;
-         return handle_file(ff_pkt, pkt);
-       }
-       /* 
-       * Now process the files in this directory.
-       */
-       errno = 0;
-       if ((directory = opendir(fname)) == NULL) {
-         free(link);
-         ff_pkt->type = FT_NOOPEN;
-         ff_pkt->ff_errno = errno;
-         return handle_file(ff_pkt, pkt);
-       }
-
-       /*
-       * This would possibly run faster if we chdir to the directory
-       * before traversing it.
-       */
-       rtn_stat = 1;
-       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
-       for ( ; !job_cancelled(jcr); ) {
-          char *p, *q;
-          int i;
-
-          status  = readdir_r(directory, entry, &result);
-           Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result,
-             entry->d_name);
-          if (status != 0 || result == NULL) {
-             break;
-          }
-          ASSERT(name_max+1 > sizeof(struct dirent) + (int)NAMELEN(entry));
-          p = entry->d_name;
-           /* Skip `.', `..', and excluded file names.  */
-           if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
-               (p[1] == '.' && p[2] == '\0')))) {
-             continue;
-          }
-
-          if ((int)NAMELEN(entry) + len >= link_len) {
-              link_len = len + NAMELEN(entry) + 1;
-              link = (char *)brealloc(link, link_len + 1);
-          }
-          q = link + len;
-          for (i=0; i < (int)NAMELEN(entry); i++) {
-             *q++ = *p++;
-          }
-          *q = 0;
-          if (!file_is_excluded(ff_pkt, link)) {
-             rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0);
-          }
-       }
-       closedir(directory);
-       free(link);
-       free(entry);
-
-       if (ff_pkt->atime_preserve) {
-         utime(fname, &restore_times);
-       }
-       return rtn_stat;
+      DIR *directory;
+      struct dirent *entry, *result;
+      char *link;
+      int link_len;
+      int len;
+      int status;
+      dev_t our_device = ff_pkt->statp.st_dev;
+
+      if (access(fname, R_OK) == -1 && geteuid() != 0) {
+        /* Could not access() directory */
+        ff_pkt->type = FT_NOACCESS;
+        ff_pkt->ff_errno = errno;
+        rtn_stat = handle_file(ff_pkt, pkt);
+        if (ff_pkt->linked) {
+           ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+        }
+        return rtn_stat;
+      }
+
+      /* Build a canonical directory name with a trailing slash. */
+      len = strlen(fname);
+      link_len = len + 200;
+      link = (char *)bmalloc(link_len + 2);
+      bstrncpy(link, fname, link_len);
+      /* Strip all trailing slashes */
+      while (len >= 1 && link[len - 1] == '/')
+       len--;
+      link[len++] = '/';             /* add back one */
+      link[len] = 0;
+
+      ff_pkt->link = link;
+      if (ff_pkt->incremental &&
+         (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
+          ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
+        /* Incremental option, directory entry not changed */
+        ff_pkt->type = FT_DIRNOCHG;
+      } else {
+        ff_pkt->type = FT_DIR;
+      }
+      handle_file(ff_pkt, pkt);       /* handle directory entry */
+      if (ff_pkt->linked) {
+        ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+      }
+
+      ff_pkt->link = ff_pkt->fname;     /* reset "link" */
+
+      /* 
+       * Do not decend into subdirectories (recurse) if the
+       * user has turned it off for this directory.
+       */
+      if (ff_pkt->flags & FO_NO_RECURSION) {
+        free(link);
+        /* No recursion into this directory */
+        ff_pkt->type = FT_NORECURSE;
+        rtn_stat = handle_file(ff_pkt, pkt);
+        if (ff_pkt->linked) {
+           ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+        }
+        return rtn_stat;
+      }
+
+      /* 
+       * See if we are crossing file systems, and
+       * avoid doing so if the user only wants to dump one file system.
+       */
+      if (!top_level && !(ff_pkt->flags & FO_MULTIFS) &&
+          parent_device != ff_pkt->statp.st_dev) {
+        free(link);
+        /* returning here means we do not handle this directory */
+        ff_pkt->type = FT_NOFSCHG;
+        rtn_stat = handle_file(ff_pkt, pkt);
+        if (ff_pkt->linked) {
+           ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+        }
+        return rtn_stat;
+      }
+      /* 
+       * Now process the files in this directory.
+       */
+      errno = 0;
+      if ((directory = opendir(fname)) == NULL) {
+        free(link);
+        ff_pkt->type = FT_NOOPEN;
+        ff_pkt->ff_errno = errno;
+        rtn_stat = handle_file(ff_pkt, pkt);
+        if (ff_pkt->linked) {
+           ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+        }
+        return rtn_stat;
+      }
+
+      /*
+       * This would possibly run faster if we chdir to the directory
+       * before traversing it.
+       */
+      rtn_stat = 1;
+      entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
+      for ( ; !job_cancelled(jcr); ) {
+        char *p, *q;
+        int i;
+
+        status  = readdir_r(directory, entry, &result);
+         Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result,
+           entry->d_name);
+        if (status != 0 || result == NULL) {
+           break;
+        }
+        ASSERT(name_max+1 > sizeof(struct dirent) + (int)NAMELEN(entry));
+        p = entry->d_name;
+         /* Skip `.', `..', and excluded file names.  */
+         if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
+             (p[1] == '.' && p[2] == '\0')))) {
+           continue;
+        }
+
+        if ((int)NAMELEN(entry) + len >= link_len) {
+            link_len = len + NAMELEN(entry) + 1;
+            link = (char *)brealloc(link, link_len + 1);
+        }
+        q = link + len;
+        for (i=0; i < (int)NAMELEN(entry); i++) {
+           *q++ = *p++;
+        }
+        *q = 0;
+        if (!file_is_excluded(ff_pkt, link)) {
+           rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0);
+           if (ff_pkt->linked) {
+              ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+           }
+        }
+      }
+      closedir(directory);
+      free(link);
+      free(entry);
+
+      if (ff_pkt->atime_preserve) {
+        utime(fname, &restore_times);
+      }
+      return rtn_stat;
    } /* end check for directory */
 
    /*
@@ -324,7 +368,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt),
       /* The only remaining types are special (character, ...) files */
       ff_pkt->type = FT_SPEC;
    }
-   return handle_file(ff_pkt, pkt);
+   rtn_stat = handle_file(ff_pkt, pkt);
+   if (ff_pkt->linked) {
+      ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+   }
+   return rtn_stat;
 }
 
 int term_find_one(FF_PKT *ff)
index 3c2c8763623f48e21721eafd2ced921b9ddca05d..770f97ea4b343f24c54d78e2f2745eb0871e64ba 100644 (file)
  */
 
 /* from attribs.c */
-void      encode_stat            (char *buf, struct stat *statp);
-void      decode_stat            (char *buf, struct stat *statp);
-int       encode_attribsEx       (void *jcr, char *attribsEx, FF_PKT *ff_pkt);
+void     encode_stat            (char *buf, struct stat *statp, uint32_t LinkFI);
+void     decode_stat            (char *buf, struct stat *statp, uint32_t *LinkFI);
+int      encode_attribsEx       (void *jcr, char *attribsEx, FF_PKT *ff_pkt);
 int set_attributes(void *jcr, char *fname, char *ofile, char *lname,
-                   int type, int stream, struct stat *statp, 
-                   char *attribsEx, int *ofd);
+                  int type, int stream, struct stat *statp, 
+                  char *attribsEx, int *ofd);
 
 /* from create_file.c */
 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 type, int stream, struct stat *statp, 
+               char *attribsEx, int *ofd, int replace);
 
 /* From find.c */
 FF_PKT *init_find_files();
@@ -50,15 +50,15 @@ void add_fname_to_exclude_list(FF_PKT *ff, char *fname);
 int file_is_excluded(FF_PKT *ff, char *file);
 int file_is_included(FF_PKT *ff, char *file);
 struct s_included_file *get_next_included_file(FF_PKT *ff, 
-                           struct s_included_file *inc);
+                          struct s_included_file *inc);
 
 /* From find_one.c */
 int find_one_file(JCR *jcr, FF_PKT *ff, int handle_file(FF_PKT *ff_pkt, void *hpkt), 
-               void *pkt, char *p, dev_t parent_device, int top_level);
+              void *pkt, char *p, dev_t parent_device, int top_level);
 int term_find_one(FF_PKT *ff);
 
 
 /* from makepath.c */
 int make_path(void *jcr, const char *argpath, int mode,
-           int parent_mode, uid_t owner, gid_t group,
-           int preserve_existing, char *verbose_fmt_string);
+          int parent_mode, uid_t owner, gid_t group,
+          int preserve_existing, char *verbose_fmt_string);
index afa729ee8518451dfaf83402a70322b9997dc050..b2d6cfa59fd3e9ed1017fdf8442586e6d73d01cb 100644 (file)
@@ -4,3 +4,5 @@ btraceback
 btraceback.gdb
 startit
 stopit
+sha1sum
+md5sum
index 58a4aec748df10c315fe75bc4e53a2f683c2aba1..bd866d1be2744c94befda127a0e5b1105328a880 100644 (file)
@@ -94,12 +94,27 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
        cd $(topdir) \
          && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
 
-rwlock_test:  rwlock.o
+rwlock_test:
        rm -f rwlock.o
        $(CXX) -DTEST_RWLOCK $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE)  $(CFLAGS) rwlock.c
        $(CXX) $(LDFLAGS) -L. -o $@ rwlock.o $(LIBS) $(DLIB) -lbac -lm
        rm -f rwlock.o
        $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) rwlock.c
+
+md5sum:
+       rm -f md5.o
+       $(CXX) -DMD5_SUM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE)  $(CFLAGS) md5.c
+       $(CXX) $(LDFLAGS) -L. -o $@ md5.o $(LIBS) $(DLIB) -lbac -lm
+       rm -f md5.o
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) md5.c
+
+
+sha1sum:
+       rm -f sha1.o
+       $(CXX) -DSHA1_SUM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE)  $(CFLAGS) sha1.c
+       $(CXX) $(LDFLAGS) -L. -o $@ sha1.o $(LIBS) $(DLIB) -lbac -lm
+       rm -f sha1.o
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) md5.c
         
 install:
 
@@ -107,7 +122,7 @@ uninstall:
 
 clean:
        $(RMF) *.a core a.out *.o *.bak *.tex *.pdf *~ *.intpro *.extpro 1 2 3
-       $(RMF) rwlock_test md5 sha1
+       $(RMF) rwlock_test md5sum sha1sum
 
 realclean: clean
        $(RMF) tags
index fb5ae14d87b82afd0bf6e68ae9cd08988bbf34a3..fe4acf92a5e51322ab61296347533eb7ef78c2ce 100644 (file)
@@ -7,7 +7,7 @@
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+   Copyright (C) 2002-2003 Kern Sibbald and John Walker
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
  * Returns -2 on error
  */
 int32_t 
-bnet_recv_pkt(BSOCK *bsock, BPKT *pkt)
+bnet_recv_pkt(BSOCK *bsock, BPKT *pkt, int *version)
 {
+   unser_declare;
+   short lversion;
+   int type;
+
+   unser_begin(bsock->msg, 0);
+   unser_uint16(lversion);
+   *version = (int)lversion;
+
+   
+   for ( ; pkt->type != BP_EOF; pkt++) {
+      if (pkt->id) {
+        ser_int8(BP_ID);
+        ser_string((char *)pkt->id);
+      }
+      ser_int8(pkt->type);
+      switch (pkt->type) {
+      case BP_CHAR:
+        ser_int8(*(int8_t *)pkt->value);
+        break;
+      case BP_INT32:
+        ser_int32(*(int32_t *)pkt->value);
+        break;
+      case BP_UINT32:
+        break;
+        ser_unit32(*(uint32_t *)pkt->value);
+        break;
+      case BP_INT64:
+        ser_int64(*(int64_t *)pkt->value);
+        break;
+      case BP_BTIME:
+      case BP_UTIME:
+      case BP_UINT64:
+        ser_uint64(*(uint64_t *)pkt->value);
+        break;
+      case BP_POOL:
+      case BP_STRING:
+      case BP_NAME:
+        ser_string((char *)pkt->value);
+        break;
+      case BP_BYTES:
+        ser_uint32(*(uint32_t *)pkt->len);
+        ser_bytes((char *)pkt->value, pkt->len);
+        break;
+      default:
+         Emsg1(M_ABORT, 0, _("Unknown BPKT type: %d\n"), pkt->type);
+      }
+   }
+   unser_end(bsock->msg, 0);
+   
 }
 
 /*
@@ -52,37 +101,50 @@ bnet_recv_pkt(BSOCK *bsock, BPKT *pkt)
  *         1 on success
  */
 int
-bnet_send_pkt(BSOCK *bsock, BPKT *pkt)
+bnet_send_pkt(BSOCK *bsock, BPKT *pkt, int version)
 {
    ser_declare;
 
    ser_begin(bsock->msg, 0);
+   ser_uint16(version);
 
-   while (pkt->type != BP_EOF) {
+   for ( ; pkt->type != BP_EOF; pkt++) {
+      if (pkt->id) {
+        ser_int8(BP_ID);
+        ser_string((char *)pkt->id);
+      }
       ser_int8(pkt->type);
       switch (pkt->type) {
       case BP_CHAR:
-        ser_int8(*((int8_t)pkt->value)));
+        ser_int8(*(int8_t *)pkt->value);
         break;
       case BP_INT32:
-        ser_int32(*(int32_t)pkt->value)));
+        ser_int32(*(int32_t *)pkt->value);
         break;
       case BP_UINT32:
         break;
+        ser_unit32(*(uint32_t *)pkt->value);
+        break;
       case BP_INT64:
+        ser_int64(*(int64_t *)pkt->value);
         break;
-      case BP_STRING:
+      case BP_BTIME:
+      case BP_UTIME:
+      case BP_UINT64:
+        ser_uint64(*(uint64_t *)pkt->value);
         break;
+      case BP_POOL:
+      case BP_STRING:
       case BP_NAME:
+        ser_string((char *)pkt->value);
         break;
       case BP_BYTES:
-        break;
-      case BP_FLOAT32:
-        break;
-      case BP_FLOAT64:
+        ser_uint32(*(uint32_t *)pkt->len);
+        ser_bytes((char *)pkt->value, pkt->len);
         break;
       default:
          Emsg1(M_ABORT, 0, _("Unknown BPKT type: %d\n"), pkt->type);
       }
-
+   }
+   ser_end(bsock->msg, 0);
 }
index 6613b7f6aa82eb35671cdbeed140838c147b0a22..01e11bb694101b2716754a68f5db789f1accb1d1 100644 (file)
@@ -42,6 +42,7 @@ daemon_start()
 #ifndef HAVE_CYGWIN
    int i;
    int cpid;
+   mode_t oldmask;
    /*
     *  Become a daemon.
     */
@@ -76,8 +77,13 @@ daemon_start()
    chdir("/");
 #endif
 
-   /* clear any inherited umask */ 
-   umask(0);
+   /* 
+    * Avoid creating files 666 but don't override any
+    * more restrictive mask set by the user.
+    */
+   oldmask = umask(022);
+   oldmask |= 022;
+   umask(oldmask);
 
    Dmsg0(200, "Exit daemon_start\n");
 #endif /* HAVE_CYGWIN */
index 215e2b2fb3df5ebdd25967dedbbc9e86b1b3fec4..99a6f33333bce08898177e03ae7807c8ae714d60 100644 (file)
@@ -28,6 +28,7 @@
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /********************************************************************* 
  * Acquire device for reading. We permit (for the moment)
@@ -143,20 +144,20 @@ get_out:
  * Acquire device for writing. We permit multiple writers.
  *  If this is the first one, we read the label.
  *
- *  Returns: 0 if failed for any reason
- *          1 if successful
+ *  Returns: NULL if failed for any reason
+ *          dev if successful (may change if new dev opened)
  */
-int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 {
    int release = 0;
    int do_mount = 0;
-   int stat = 0;
+   DEVICE *rtn_dev = NULL;
 
    lock_device(dev);
    block_device(dev, BST_DOING_ACQUIRE);
    unlock_device(dev);
    Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
-
+            
 
    if (dev->state & ST_APPEND) {
       /* 
@@ -173,14 +174,31 @@ int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
          !(dir_find_next_appendable_volume(jcr) &&
            strcmp(dev->VolHdr.VolName, jcr->VolumeName) == 0)) { /* wrong tape mounted */
         if (dev->num_writers != 0) {
-           /*
-            * ***FIXME*** add multiple writers here if permitted   
-            *  find end of dev chain 
-            *   dev->next = init_dev(NULL, dev->device);
-            *   ...
-            */
-            Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
-           goto get_out;
+           DEVICE *d = ((DEVRES *)dev->device)->dev;
+           uint32_t open_vols = 0;
+           for ( ; d; d=d->next) {
+              open_vols++;
+           }
+           if (dev->state & ST_FILE && dev->max_open_vols > open_vols) {
+              P(mutex);              /* lock all devices */
+              d = init_dev(NULL, (DEVRES *)dev->device); /* init new device */
+              d->prev = dev;                   /* chain in new device */
+              d->next = dev->next;
+              dev->next = d;
+              /* Release old device */
+              P(dev->mutex); 
+              unblock_device(dev);
+              V(dev->mutex);
+              /* Make new device current device and lock it */
+              dev = d;
+              lock_device(dev);
+              block_device(dev, BST_DOING_ACQUIRE);
+              unlock_device(dev);
+              V(mutex);
+           } else {
+               Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
+              goto get_out;
+           }
         }
         /* Wrong tape mounted, release it, then fall through to get correct one */
         release = 1;
@@ -213,13 +231,13 @@ int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       jcr->NumVolumes = 1;
    }
    attach_jcr_to_device(dev, jcr);    /* attach jcr to device */
-   stat = 1;                         /* good return */
+   rtn_dev = dev;                    /* return device */
 
 get_out:
    P(dev->mutex); 
    unblock_device(dev);
    V(dev->mutex);
-   return stat;
+   return rtn_dev;
 }
 
 /*
@@ -281,6 +299,14 @@ int release_device(JCR *jcr, DEVICE *dev)
            dev_name(dev), NPRT(jcr->VolumeName));
    }
    detach_jcr_from_device(dev, jcr);
-   unlock_device(dev);
+   if (dev->prev && !(dev->state & ST_READ) && dev->num_writers == 0) {
+      P(mutex);
+      unlock_device(dev);
+      dev->prev->next = dev->next;    /* dechain */
+      term_dev(dev);
+      V(mutex);
+   } else {
+      unlock_device(dev);
+   }
    return 1;
 }
index c3ea57e56081648a6f7f0bae4b2ecb29e860bb17..307b1becaebcc2a468e09c5bf2b02194c877599f 100644 (file)
@@ -73,7 +73,7 @@ int do_append_data(JCR *jcr)
     *  subroutine.
     */
    Dmsg0(100, "just before acquire_device\n");
-   if (!acquire_device_for_append(jcr, dev, block)) {
+   if (!(dev=acquire_device_for_append(jcr, dev, block))) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
       free_block(block);
       return 0;
index 9da6927c026b6d25ca800a5761a314125630b996..5dded6d184262e3d13530e6c54934780ad898e84 100644 (file)
@@ -144,7 +144,7 @@ int main (int argc, char *argv[])
       exit(1);
    }
    unlock_device(out_dev);
-   if (!acquire_device_for_append(out_jcr, out_dev, out_block)) {
+   if (!(out_dev=acquire_device_for_append(out_jcr, out_dev, out_block))) {
       free_block(out_block);
       free_jcr(in_jcr);
       exit(1);
index be9b1fa5ad8c959abab2f4f49f89bd1bd3145270..10c6300cca2aeb893d92f74007ae754ff447efde 100644 (file)
@@ -321,8 +321,9 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
 
         
       if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) {
+        uint32_t LinkFI;
 
-        decode_stat(ap, &statp);
+        decode_stat(ap, &statp, &LinkFI);
         /*
          * Prepend the where directory so that the
          * files are put where the user wants.
index dedf4fb5cd97b97008057f6fa6082f21b6839b89..3d00ea70c14cf28710873c4fbd0215aa926eb99d 100644 (file)
@@ -322,6 +322,8 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
    /* File Attributes stream */
    if (rec->Stream == STREAM_UNIX_ATTRIBUTES || rec->Stream == STREAM_WIN32_ATTRIBUTES) {
       char *ap, *fp;
+      uint32_t LinkFI;
+
       sscanf(rec->data, "%ld %d", &record_file_index, &type);
       if (record_file_index != rec->FileIndex) {
          Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
@@ -340,7 +342,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       }
       *fp = *ap++;                /* terminate filename & point to attribs */
 
-      decode_stat(ap, &statp);
+      decode_stat(ap, &statp, &LinkFI);
       /* Skip to link name */  
       while (*ap++ != 0)
         ;
index ebc4977aca36e85ccb370ceda7f6542c2abd6a12..9ccdc3fab9c40277ccf6209ee7ff0c7178a8a68a 100644 (file)
@@ -537,7 +537,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       }
       strcat(lname, lp);        /* "save" link name */
       if (verbose > 1) {
-        decode_stat(ap, &statp);
+        uint32_t LinkFI;
+        decode_stat(ap, &statp, &LinkFI);
         print_ls_output(fname, lname, type, &statp);   
       }
       mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
index 1b80ff02a9aef1ddb36a723a5fb4d721a1c92fca..94780827b91976d67dc8d3c5b68db4d4c7258437 100644 (file)
@@ -1043,7 +1043,7 @@ This may take a long time. I.e. hours! ...\n\n");
     *  subroutine.
     */
    Dmsg0(100, "just before acquire_device\n");
-   if (!acquire_device_for_append(jcr, dev, block)) {
+   if (!(dev=acquire_device_for_append(jcr, dev, block))) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
       free_block(block);
       return;
index 24572066b43e51cfe928e4cd645bae31900ed492..e19032544d6251c6092e8edbf9a52f437bbdeef8 100644 (file)
@@ -153,6 +153,7 @@ init_dev(DEVICE *dev, DEVRES *device)
    dev->volume_capacity = device->volume_capacity;
    dev->max_rewind_wait = device->max_rewind_wait;
    dev->max_open_wait = device->max_open_wait;
+   dev->max_open_vols = device->max_open_vols;
    dev->device = device;
 
    if (tape) {
@@ -305,7 +306,8 @@ open_dev(DEVICE *dev, char *VolName, int mode)
       } else {
          Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); 
       }
-      if ((dev->fd = open(archive_name, dev->mode, MODE_RW)) < 0) {
+      /* If creating file, give 0640 permissions */
+      if ((dev->fd = open(archive_name, dev->mode, 0640)) < 0) {
         dev->dev_errno = errno;
          Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name, strerror(dev->dev_errno));
         Emsg0(M_FATAL, 0, dev->errmsg);
index 7f91545a706bf9267d376ec0a5cbd99b36a9feff..d2fd63c935af445667a13f37f42b4d0a3f94761d 100644 (file)
@@ -31,9 +31,9 @@
 
 /* #define NEW_LOCK 1 */
 
-#define new_lock_device(dev)            _new_lock_device(__FILE__, __LINE__, (dev)) 
+#define new_lock_device(dev)             _new_lock_device(__FILE__, __LINE__, (dev)) 
 #define new_lock_device_state(dev,state) _new_lock_device(__FILE__, __LINE__, (dev), (state))
-#define new_unlock_device(dev)          _new_unlock_device(__FILE__, __LINE__, (dev))
+#define new_unlock_device(dev)           _new_unlock_device(__FILE__, __LINE__, (dev))
 
 #define lock_device(d) _lock_device(__FILE__, __LINE__, (d))
 #define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d))
 #define READ_WRITE 0
 #define READ_ONLY  1
 #define OPEN_READ_WRITE 0
-#define OPEN_READ_ONLY 1
+#define OPEN_READ_ONLY  1
 #define OPEN_WRITE_ONLY 2
 
 /* Generic status bits returned from status_dev() */
-#define MT_TAPE      (1<<0)               /* is tape device */
-#define MT_EOF      (1<<1)                /* just read EOF */
-#define MT_BOT      (1<<2)                /* at beginning of tape */
-#define MT_EOT      (1<<3)                /* end of tape reached */
-#define MT_SM       (1<<4)                /* DDS setmark */
-#define MT_EOD      (1<<5)                /* DDS at end of data */
-#define MT_WR_PROT   (1<<6)               /* tape write protected */
-#define MT_ONLINE    (1<<7)               /* tape online */
-#define MT_DR_OPEN   (1<<8)               /* tape door open */
-#define MT_IM_REP_EN (1<<9)               /* immediate report enabled */
+#define MT_TAPE      (1<<0)                /* is tape device */
+#define MT_EOF       (1<<1)                /* just read EOF */
+#define MT_BOT       (1<<2)                /* at beginning of tape */
+#define MT_EOT       (1<<3)                /* end of tape reached */
+#define MT_SM        (1<<4)                /* DDS setmark */
+#define MT_EOD       (1<<5)                /* DDS at end of data */
+#define MT_WR_PROT   (1<<6)                /* tape write protected */
+#define MT_ONLINE    (1<<7)                /* tape online */
+#define MT_DR_OPEN   (1<<8)                /* tape door open */
+#define MT_IM_REP_EN (1<<9)                /* immediate report enabled */
 
 
 /* Test capabilities */
 #define dev_cap(dev, cap) ((dev)->capabilities & (cap))
 
 /* Bits for device capabilities */
-#define CAP_EOF           0x0001     /* has MTWEOF */
-#define CAP_BSR           0x0002     /* has MTBSR */
-#define CAP_BSF           0x0004     /* has MTBSF */
-#define CAP_FSR           0x0008     /* has MTFSR */
-#define CAP_FSF           0x0010     /* has MTFSF */
-#define CAP_EOM           0x0020     /* has MTEOM */
-#define CAP_REM           0x0040     /* is removable media */
-#define CAP_RACCESS       0x0080     /* is random access device */
-#define CAP_AUTOMOUNT     0x0100     /* Read device at start to see what is there */
-#define CAP_LABEL         0x0200     /* Label blank tapes */
-#define CAP_ANONVOLS      0x0400     /* Mount without knowing volume name */
-#define CAP_ALWAYSOPEN    0x0800     /* always keep device open */
+#define CAP_EOF            0x0001     /* has MTWEOF */
+#define CAP_BSR            0x0002     /* has MTBSR */
+#define CAP_BSF            0x0004     /* has MTBSF */
+#define CAP_FSR            0x0008     /* has MTFSR */
+#define CAP_FSF            0x0010     /* has MTFSF */
+#define CAP_EOM            0x0020     /* has MTEOM */
+#define CAP_REM            0x0040     /* is removable media */
+#define CAP_RACCESS        0x0080     /* is random access device */
+#define CAP_AUTOMOUNT      0x0100     /* Read device at start to see what is there */
+#define CAP_LABEL          0x0200     /* Label blank tapes */
+#define CAP_ANONVOLS       0x0400     /* Mount without knowing volume name */
+#define CAP_ALWAYSOPEN     0x0800     /* always keep device open */
 #define CAP_AUTOCHANGER    0x1000     /* AutoChanger */
 #define CAP_OFFLINEUNMOUNT 0x2000     /* Offline before unmount */
-#define CAP_STREAM        0x4000     /* Stream device */
+#define CAP_STREAM         0x4000     /* Stream device */
 
 /* Test state */
 #define dev_state(dev, state) ((dev)->state & (state))
 
 /* Device state bits */
-#define ST_OPENED    0x0001          /* set when device opened */
-#define ST_TAPE      0x0002          /* is a tape device */  
-#define ST_FILE      0x0004          /* is a file device */
-#define ST_FIFO      0x0008          /* is a fifo device */
-#define ST_PROG      0x0010          /* is a program device */
-#define ST_LABEL     0x0020          /* label found */
+#define ST_OPENED    0x0001           /* set when device opened */
+#define ST_TAPE      0x0002           /* is a tape device */  
+#define ST_FILE      0x0004           /* is a file device */
+#define ST_FIFO      0x0008           /* is a fifo device */
+#define ST_PROG      0x0010           /* is a program device */
+#define ST_LABEL     0x0020           /* label found */
 #define ST_MALLOC    0x0040           /* dev packet malloc'ed in init_dev() */
-#define ST_APPEND    0x0080          /* ready for Bacula append */
-#define ST_READ      0x0100          /* ready for Bacula read */
-#define ST_EOT      0x0200           /* at end of tape */
-#define ST_WEOT      0x0400          /* Got EOT on write */
-#define ST_EOF      0x0800           /* Read EOF i.e. zero bytes */
-#define ST_NEXTVOL   0x1000          /* Start writing on next volume */
-#define ST_SHORT     0x2000          /* Short block read */
+#define ST_APPEND    0x0080           /* ready for Bacula append */
+#define ST_READ      0x0100           /* ready for Bacula read */
+#define ST_EOT       0x0200           /* at end of tape */
+#define ST_WEOT      0x0400           /* Got EOT on write */
+#define ST_EOF       0x0800           /* Read EOF i.e. zero bytes */
+#define ST_NEXTVOL   0x1000           /* Start writing on next volume */
+#define ST_SHORT     0x2000           /* Short block read */
 
 /* dev_blocked states (mutually exclusive) */
 #define BST_NOT_BLOCKED       0       /* not blocked */
-#define BST_UNMOUNTED        1       /* User unmounted device */
+#define BST_UNMOUNTED         1       /* User unmounted device */
 #define BST_WAITING_FOR_SYSOP 2       /* Waiting for operator to mount tape */
 #define BST_DOING_ACQUIRE     3       /* Opening/validating/moving tape */
 #define BST_WRITING_LABEL     4       /* Labeling a tape */  
 /* Volume Catalog Information structure definition */
 typedef struct s_volume_catalog_info {
    /* Media info for the current Volume */
-   uint32_t VolCatJobs;              /* number of jobs on this Volume */
-   uint32_t VolCatFiles;             /* Number of files */
-   uint32_t VolCatBlocks;            /* Number of blocks */
-   uint64_t VolCatBytes;             /* Number of bytes written */
-   uint32_t VolCatMounts;            /* Number of mounts this volume */
-   uint32_t VolCatErrors;            /* Number of errors this volume */
-   uint32_t VolCatWrites;            /* Number of writes this volume */
-   uint32_t VolCatReads;             /* Number of reads this volume */
-   uint32_t VolCatRecycles;          /* Number of recycles this volume */
-   int32_t  Slot;                    /* Slot in changer */
-   uint32_t VolCatMaxJobs;           /* Maximum Jobs to write to volume */
-   uint32_t VolCatMaxFiles;          /* Maximum files to write to volume */
-   uint64_t VolCatMaxBytes;          /* Max bytes to write to volume */
+   uint32_t VolCatJobs;               /* number of jobs on this Volume */
+   uint32_t VolCatFiles;              /* Number of files */
+   uint32_t VolCatBlocks;             /* Number of blocks */
+   uint64_t VolCatBytes;              /* Number of bytes written */
+   uint32_t VolCatMounts;             /* Number of mounts this volume */
+   uint32_t VolCatErrors;             /* Number of errors this volume */
+   uint32_t VolCatWrites;             /* Number of writes this volume */
+   uint32_t VolCatReads;              /* Number of reads this volume */
+   uint32_t VolCatRecycles;           /* Number of recycles this volume */
+   int32_t  Slot;                     /* Slot in changer */
+   uint32_t VolCatMaxJobs;            /* Maximum Jobs to write to volume */
+   uint32_t VolCatMaxFiles;           /* Maximum files to write to volume */
+   uint64_t VolCatMaxBytes;           /* Max bytes to write to volume */
    uint64_t VolCatCapacityBytes;      /* capacity estimate */
-   char VolCatStatus[20];            /* Volume status */
+   char VolCatStatus[20];             /* Volume status */
    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
 } VOLUME_CAT_INFO;
 
 
 typedef struct s_steal_lock {
-   pthread_t        no_wait_id;      /* id of no wait thread */
-   int              dev_blocked;     /* state */
+   pthread_t         no_wait_id;      /* id of no wait thread */
+   int               dev_blocked;     /* state */
 } bsteal_lock_t;
 
 
 /* Device structure definition */
 typedef struct s_device {
-   struct s_device *next;            /* pointer to next open device */
-   void *attached_jcrs;              /* attached JCR list */
-   pthread_mutex_t mutex;            /* access control */
-   pthread_cond_t wait;              /* thread wait variable */
+   struct s_device *next;             /* pointer to next open device */
+   struct s_device *prev;             /* pointer to prev open device */
+   void *attached_jcrs;               /* attached JCR list */
+   pthread_mutex_t mutex;             /* access control */
+   pthread_cond_t wait;               /* thread wait variable */
    pthread_cond_t wait_next_vol;      /* wait for tape to be mounted */
-   pthread_t no_wait_id;             /* this thread must not wait */
-   int dev_blocked;                  /* set if we must wait (i.e. change tape) */
-   int num_waiting;                  /* number of threads waiting */
-   int num_writers;                  /* number of writing threads */
-   int use_count;                    /* usage count on this device */
-   int fd;                           /* file descriptor */
-   int capabilities;                 /* capabilities mask */
-   int state;                        /* state mask */
-   int dev_errno;                    /* Our own errno */
-   int mode;                         /* read/write modes */
-   char *dev_name;                   /* device name */
-   char *errmsg;                     /* nicely edited error message */
-   uint32_t block_num;               /* current block number base 0 */
-   uint32_t file;                    /* current file number base 0 */
-   uint64_t file_addr;               /* Current file read/write address */
-   uint32_t EndBlock;                /* last block written */
-   uint32_t EndFile;                 /* last file written */
-   uint32_t min_block_size;          /* min block size */
-   uint32_t max_block_size;          /* max block size */
-   uint32_t max_volume_jobs;         /* max jobs to put on one volume */
-   uint64_t max_volume_files;        /* max files to put on one volume */
-   uint64_t max_volume_size;         /* max bytes to put on one volume */
-   uint64_t max_file_size;           /* max file size to put in one file on volume */
-   uint64_t volume_capacity;         /* advisory capacity */
-   uint32_t max_rewind_wait;         /* max secs to allow for rewind */
-   uint32_t max_open_wait;           /* max secs to allow for open */
-   void *device;                     /* pointer to Device Resource */
-   btimer_id tid;                    /* timer id */
-
-   VOLUME_CAT_INFO VolCatInfo;       /* Volume Catalog Information */
-   VOLUME_LABEL VolHdr;              /* Actual volume label */
+   pthread_t no_wait_id;              /* this thread must not wait */
+   int dev_blocked;                   /* set if we must wait (i.e. change tape) */
+   int num_waiting;                   /* number of threads waiting */
+   int num_writers;                   /* number of writing threads */
+   int use_count;                     /* usage count on this device */
+   int fd;                            /* file descriptor */
+   int capabilities;                  /* capabilities mask */
+   int state;                         /* state mask */
+   int dev_errno;                     /* Our own errno */
+   int mode;                          /* read/write modes */
+   char *dev_name;                    /* device name */
+   char *errmsg;                      /* nicely edited error message */
+   uint32_t block_num;                /* current block number base 0 */
+   uint32_t file;                     /* current file number base 0 */
+   uint64_t file_addr;                /* Current file read/write address */
+   uint32_t EndBlock;                 /* last block written */
+   uint32_t EndFile;                  /* last file written */
+   uint32_t min_block_size;           /* min block size */
+   uint32_t max_block_size;           /* max block size */
+   uint32_t max_volume_jobs;          /* max jobs to put on one volume */
+   uint64_t max_volume_files;         /* max files to put on one volume */
+   uint64_t max_volume_size;          /* max bytes to put on one volume */
+   uint64_t max_file_size;            /* max file size to put in one file on volume */
+   uint64_t volume_capacity;          /* advisory capacity */
+   uint32_t max_rewind_wait;          /* max secs to allow for rewind */
+   uint32_t max_open_wait;            /* max secs to allow for open */
+   uint32_t max_open_vols;            /* max simultaneous open volumes */
+   void *device;                      /* pointer to Device Resource */
+   btimer_id tid;                     /* timer id */
+
+   VOLUME_CAT_INFO VolCatInfo;        /* Volume Catalog Information */
+   VOLUME_LABEL VolHdr;               /* Actual volume label */
 
 } DEVICE;
 
@@ -213,7 +215,7 @@ typedef struct s_device {
  *  dependent. Arrgggg!
  */
 #ifndef MTEOM
-#ifdef MTSEOD
+#ifdef  MTSEOD
 #define MTEOM MTSEOD
 #endif
 #ifdef MTEOD
index 339246e335daa32145d9bbbe38536292afb1a49d..6f0b4db6ff706138c63f6e916c017c5540f4e106 100644 (file)
@@ -28,7 +28,7 @@
 uint32_t new_VolSessionId();
 
 /* From acquire.c */
-int      acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+DEVICE  *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 int      acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 int      release_device(JCR *jcr, DEVICE *dev);
 
index b3424330144570dcf6cc7156a3d1866ad09b0990..864b0534ad6bb20d33cf8e765d5aacf0f674fefd 100644 (file)
@@ -99,6 +99,7 @@ static struct res_items dev_items[] = {
    {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
    {"maximumchangerwait",    store_pint,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 2 * 60},
    {"maximumopenwait",       store_pint,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
+   {"maximumopenvolumes",    store_pint,   ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
    {"offlineonunmount",      store_yesno,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
    {"maximumrewindwait",     store_pint,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
    {"minimumblocksize",      store_pint,   ITEM(res_dev.min_block_size), 0, 0, 0},
index 80c0f98a5841c596e3f239f5628ea20186646cbb..aead24a37806d2b6e04b9d46b2154ae696dc3089 100644 (file)
@@ -77,6 +77,7 @@ struct s_res_dev {
    uint32_t max_changer_wait;         /* Changer timeout */
    uint32_t max_rewind_wait;          /* maximum secs to wait for rewind */
    uint32_t max_open_wait;            /* maximum secs to wait for open */
+   uint32_t max_open_vols;            /* maximum simultaneous open volumes */
    uint32_t min_block_size;           /* min block size */
    uint32_t max_block_size;           /* max block size */
    uint32_t max_volume_jobs;          /* max jobs to put on one volume */
index 9bcd124c6c6cf2f8ed9dcbfa2227e1c6b45b1a7d..50be4a7ac7bed8c2df43f20a01e3764b82d00e56 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #define VERSION "1.30"
 #define VSTRING "1"
-#define DATE    "26 January 2003"
-#define LSMDATE "26Jan03"
+#define DATE    "1 February 2003"
+#define LSMDATE "01Feb03"
 
 /* Debug flags */
 #define DEBUG 1