
#include "bacula_template.inc" title="Storage Media Output Format"

<H1>Storage Media Output Format</H1>

<h2>General</h2>
This document describes the media format written by the
Storage daemon. The Storage daemon reads and writes in units
of blocks. Blocks contain records. Each block has a block
header followed by records, and each record has a record header
followed by record data.
<p>This chapter is intended to be a technical discussion of the
Media Format and as such is not targeted at end users but
rather at developers and system administrators that want or
need to know more of the working details of <b>Bacula</b>.

<h2>Definitions</h2>
<dl>
  <dt>Block<dd>A block represents the primitive unit of information
      that the Storage daemon reads and writes to a physical
      device. Normally, for a tape device, it will be the same as a 
      tape block. The Storage daemon always reads and writes
      blocks.  A block consists of block header information
      followed by records. Clients of the Storage daemon (the
      File daemon) normally never see blocks. However, some
      of the Storage tools (bls, bscan, bextract, ...) may
      be use block header information.
  <dt>Record<dd>A record consists of a Record Header, which is managed 
      by the Storage daemon and Record Data, which is the data
      received from the Client. The details are described below.
   <dt>JobId<dd>A number assigned by the Director daemon for a 
      particular job. This number will be unique for
      that particular Director (Catalog). The daemons use this
      number to keep track of individual jobs. Within the Storage
      daemon, the JobId may not be unique if several Directors are
      accessing the Storage daemon simultaneously.
  <dt>Session<dd>A Session corresponds to a Job with the exception that
      each session is uniquely identified within the Storage
      daemon (see below).
  <dt>VolSessionId<dd>A unique number assigned by the Storage daemon
      to a particular session it is having with a File
      daemon. This number by itself is not unique to the
      given Volume, but with the VolSessionTime, it is unique.
  <dt>VolSessionTime<dd>A unique number assigned by the Storage daemon
      to a particular Storage daemon execution. It is actually
      the Unix time_t value of when the Storage daemon began 
      execution cast to a 32 bit unsigned integer. The combination
      of the <b>VolSessionId</b> and the <b>VolSessionTime</b> 
      for a given Storage daemon is guaranteed to be unique for each
      Job (or session).
  <dt>FileIndex<dd>A sequential number beginning at one assigned by the File
      daemon to the files within a job that are sent to the Storage daemon
      for backup. The Storage daemon ensures that this number
      is greater than zero and sequential. Note, the Storage
      daemon uses negative FileIndexes to flag Session Start
      and End Labels as well as End of Volume Labels.
  <dt>Stream<dd>An arbitrary number assigned by the File daemon to the
      parts (Unix attributes, Win32 attributes, data, compressed data,&nbsp;...) of a file that are sent to
      the Storage daemon. The Storage daemon has no knowledge of
      the details of a Stream; it simply represents a numbered
      stream of bytes. The data for a given stream may be
      passed to the Storage daemon in multiple packets.
  <dt>Block Header<dd>A block header consists of a block identification
      (&quot;BB01&quot;), a block length in bytes (typically
      64,512) a checksum, and sequential block number.
      Each block starts with a Block Header and is followed
      by Records.
  <dt>Record Header<dd>A record header contains the Volume Session Id, the
      Volume Session Time, the FileIndex, the Stream, and the size of the
      data record which follows. The Record Header is always immediately
      followed by a Data Record if the size given in the Header is greater
      than zero.  Note, for Block headers of level BB02 (version 1.27
      and later), the Record header does not contain the Volume Session
      Id and the Volume Session Time as these two fields are stored in
      the BB02 Block header.
  <dt>Data Record<dd>A data record consists of a binary stream of bytes
      and is always preceded by a Record Header.
  <dt>Volume Label<dd>A label placed by the Storage daemon at the beginning
      of each storage volume. It contains general information about
      the volume. It is written in Record format.
  <dt>Begin Session Label<dd>The Begin Session Label is a special record placed by the Storage daemon
      on the storage medium as the first record of an append session job
      with a File daemon. This record is useful for finding
      the beginning of a particular session (Job), since no records 
      with the same VolSessionId and VolSessionTime will precede this record.
      This record is not normally visible outside of
      the Storage daemon. The Begin Session Label 
      is similar to the Volume Label except that it contains
      additional information pertaining to the Session.</dd>
  <dt>End Session Label<dd>The End Session Label is a special record
      placed by the Storage daemon on the storage medium as the last
      record of an append session job with a File daemon.  The End
      Session Record is distinguished by a FileIndex with a value of
      minus two (-2).  This record is useful for detecting the end of a
      particular session since no records with the same VolSessionId and
      VolSessionTime will follow this record.  This record is not normally
      visible outside of the Storage daemon.  The End Session Label is
      similar to the Volume Label except that it contains additional
      information pertaining to the Session.</dd>

<!--  begin comment out -----------------------
  <dt>*End of Volume Label<dd>NOT YET IMPLEMENTED! The End of Volume
      label is a special record placed by the Storage daemon on the
      storage medium as the last record on the medium.  It is somewhat
      analogous to the Volume Label except that it appears at the end of
      the volume.  The End of Volume Label is distinguished by a
      File-Index with a value of minus three (-3).  This record is not
      visible outside of the Storage daemon.  It should be noted that
      this record is not guaranteed to be on every volume because on
      certain media such as old streaming tapes, there is no logical end
      of tape.  As a consequence, when Bacula is writing the tape and
      detects the end of tape condition, on these older tapes, Bacula
      will be unable to write additional data to the tape.</dd>
 end comment out -------------- -->

</dl>


<h2>Storage Daemon File Output Format</h2>
The file storage and tape storage formats are identical except that
tape records are by default blocked into blocks of 64,512 bytes, except
for the last block, which is the actual number of bytes written rounded
up to a multiple of 1024 whereas the last record of file storage is not
rounded up.  The default block size of 64,512 bytes may be overridden
by the user (some older tape drives only support block sizes of
32K). Each Session written to tape is terminated with an End of
File mark (this will be removed later).  Sessions written to file are
simply appended to the end of the file.

<h2>Overall Format</h2>
A Bacula output file consists of Blocks of data. Each block contains a
block header followed by records. Each record consists of a record header
followed by the record data. The first record on a tape will always be
the Volume Label Record.
<p>
No Record Header will be split across Bacula blocks. However, 
Record Data may be split across any number of Bacula blocks. Obviously
this will not be the case for the Volume Label which will always be smaller
than the Bacula Block size.
<p>
To simplify reading tapes, the Start of Session (SOS) and End of
Session (EOS) records are never split across blocks. If this is
about to happen, Bacula will write a short block before writing
the session record (actually, the SOS record should always be
the first record in a block, excepting perhaps the Volume label).
<p>
Due to hardware limitations, the last block written to the tape may
not be fully written. If your drive permits backspace record, Bacula
will backup over the last record written on the tape, re-read it
and verify that it was correctly written.
<p>When a new tape is mounted Bacula will write the full contents of the
partially written block to the new tape ensuring that there is no loss
of data.  When reading a tape, Bacula will discard any block that is not
totally written, thus ensuring that there is no duplication of data.  In
addition, since Bacula blocks are sequentially numbered within a Job, it
is easy to ensure that no block is missing.

<h2>Serialization</h2>
All Block Headers, Record Headers, and Label Records are written using
Bacula's serialization routines. These routines guarantee that the data
is written to the output volume in a machine independent format.
<h2>Block Header</h2>
The format of the Block Header (version 1.27 and later) is:
<pre>
   uint32_t CheckSum;                /* Block check sum */
   uint32_t BlockSize;               /* Block byte size including the header */
   uint32_t BlockNumber;             /* Block number */
   char ID[4] = "BB02";              /* Identification and block level */
   uint32_t VolSessionId;            /* Session Id for Job */
   uint32_t VolSessionTime;          /* Session Time for Job */
</pre>
 
The Block header is a fixed length and fixed format and is followed by
Record Headers and Record Data.  The CheckSum field is a 32 bit checksum
of the block data and the block header but not including the CheckSum
field.  The Block Header is always immediately followed by a Record
Header.  If the tape is damaged, a Bacula utility will be able to
recover as much information as possible from the tape by recovering
blocks which are valid.  The Block header is written using the Bacula
serialization routines and thus is guaranteed to be in machine
independent format.  See below for version 2 of the
block header.

<h2>Record Header</h2>
Each binary data record is preceded by a Record Header. The Record Header
is fixed length and fixed format, whereas the binary data record
is of variable length. The Record Header is written using the
Bacula serialization routines and thus is guaranteed to be in machine
independent format.
<p>
The format of the Record Header (version 1.27 or later) is:
<pre>
  int32_t FileIndex;                  /* File index supplied by File daemon */
  int32_t Stream;                     /* Stream number supplied by File daemon */
  uint32_t DataSize;                  /* size of following data record in bytes */
</pre>

This record is followed by the binary Stream data of DataSize bytes,
followed by another Record Header record and the binary stream data.
For the definitive definition of this record, see record.h in the
src/stored directory.

<p>Additional notes on the above:
<dl>
<dt>The <b>VolSessionId</b> <dd>is a unique sequential number that is
   assigned by the Storage Daemon to a particular Job. This number
   is sequential since the start of execution of the daemon.</dd>
<dt>The <b>VolSessionTime</b> <dd>is the time/date that the current execution
   of the Storage Daemon started. It assures that the combination of
   VolSessionId and VolSessionTime is unique for every jobs written
   to the tape, even if there was a machine crash between two writes.</dd>
<dt>The <b>FileIndex</b> <dd>is a sequential file number within a job.
   The Storage daemon requires this index to be greater than zero and
   sequential.  Note, however, that the File daemon may send multiple
   Streams for the same FileIndex.  In addition, the Storage daemon uses
   negative FileIndices to hold the Begin Session Label, the End Session
   Label, and the End of Volume Label.</dd>

<dt>The <b>Stream</b> <dd>is defined by the File daemon and is 
   used to identify separate parts of the data saved for each file
   (Unix attributes, Win32 attributes, file data, compressed file data, 
    sparse file data, ...). The Storage Daemon has no idea
   of what a Stream is or what it contains except that the Stream
   is required to be a positive integer. Negative Stream numbers are
   used internally by the Storage daemon to indicate that the record
   is a continuation of the previous record (the previous record would
   not entirely fit in the block). 
   <p>For Start Session and End Session Labels (where the FileIndex is negative),
   the Storage daemon uses the Stream field to contain the JobId.
   The current stream definitions are:
   <pre>
STREAM_UNIX_ATTRIBUTES   1    /* Generic Unix attributes */
STREAM_FILE_DATA         2    /* Standard uncompressed data */
STREAM_MD5_SIGNATURE     3    /* MD5 signature for the file */
STREAM_GZIP_DATA         4    /* GZip compressed file data */
STREAM_WIN32_ATTRIBUTES  5    /* Windows attributes (superset of Unix) */
STREAM_SPARSE_DATA       6    /* Sparse data stream */
STREAM_SPARSE_GZIP_DATA  7
STREAM_PROGRAM_NAMES     8    /* program names for program data */
STREAM_PROGRAM_DATA      9    /* Data needing program */
STREAM_SHA1_SIGNATURE   10    /* SHA1 signature for the file */
STREAM_WIN32_DATA       11    /* Win32 BackupRead data */
STREAM_WIN32_GZIP_DATA  12    /* Gzipped Win32 BackupRead data */
   </pre>
</dd>

<dt>The <b>DataSize</b> <dd>is the size in bytes of the binary data
   record that follows the Session Record header.  The Storage Daemon
   has no idea of the actual contents of the binary data record.  For
   standard Unix files, the data record typically contains the file
   attributes or the file data.  For a sparse file 
   the first 64 bits of the file data contains the storage
   address for the data block.</dd>
</dl>
The Record Header is never split across two blocks.  If there is not
enough room in a block for the full Record Header, the block is padded
to the end with zeros and the Record Header begins in the next block.
The data record, on the other hand, may be split across multiple blocks
and even multiple physical volumes.  When a data record is split, the
second (and possibly subsequent) piece of the data is preceded by a new
Record Header.  Thus each piece of data is always immediately preceded
by a Record Header.  When reading a record, if Bacula finds only part of
the data in the first record, it will automatically read the next record
and concatenate the data record to form a full data record.

<p>
Records no longer used:<p>
The format of the Block Header (version 1.26 and earlier) is:
<pre>
   uint32_t CheckSum;                /* Block check sum */
   uint32_t BlockSize;               /* Block byte size including the header */
   uint32_t BlockNumber;             /* Block number */
   char ID[4] = "BB01";              /* Identification and block level */
</pre>
The format of the Record Header (version 1.26 or earlier) is:
<pre>
  uint32_t VolSessionId;              /* Unique ID for this session */
  uint32_t VolSessionTime;            /* Start time/date of session */
  int32_t FileIndex;                  /* File index supplied by File daemon */
  int32_t Stream;                     /* Stream number supplied by File daemon */
  uint32_t DataSize;                  /* size of following data record in bytes */
</pre>


<h2>Version BB02 Block Header</h2>
The existing block header BB01 was designed to hold
records from multiple sessions. However,
it is simpler (and probably more efficient) for each session
(Job) to have its own private block. As a consequence, the  
SessionId and SessionTime can be written once in each 
Block Header and not in the Record Header. So, the
second version of the Block Header is:
<pre>
   uint32_t CheckSum;                /* Block check sum */
   uint32_t BlockSize;               /* Block byte size including the header */
   uint32_t BlockNumber;             /* Block number */
   char ID[4] = "BB02";              /* Identification and block level */
   uint32_t VolSessionId;            /* Applies to all records  */
   uint32_t VolSessionTime;          /*   contained in this block */
</pre>
As with the previous version, the BB02 Block header is a fixed length
and fixed format and is followed by Record Headers and Record Data.  The
CheckSum field is a 32 bit checksum of the block data and the block
header but not including the CheckSum field.  The Block Header is always
immediately followed by a Record Header.  If the tape is damaged, a
Bacula utility will be able to recover as much information as possible
from the tape by recovering blocks which are valid.  The Block header is
written using the Bacula serialization routines and thus is guaranteed
to be in machine independent format.
<p>

<h2>Version 2 Record Header</h2>
Version 2 Record Header is written to the medium when using
Version BB02 Block Headers. The memory representation of the
record is identical to the BB01 Record Header, but on the
storage medium, the first two fields, namely VolSessionId
and VolSessionTime will not be written. The Block Header
will be filled with these values when the First user 
record is written (i.e. non label record) so that when
the block is written, it will have the current and unique
VolSessionId and VolSessionTime. On reading each record
from the Block, the VolSessionId and VolSessionTime will
be filled in the Record Header from the Block Header.

<h2>Volume Label Format</h2>
Tape volume labels are created by the Storage daemon in response to
a <b>label</b> command given to the Console program, or alternatively
by the <b>btape</b> program. 
created. Each volume is labeled with the following information
using the Bacula serialization routines, which guarantee machine 
byte order independence.
<p>For Bacula versions 1.27 and later, the Volume Label Format is:
<pre>
  char Id[32];                        /* Bacula 1.0 Immortal\n */
  uint32_t VerNum;                    /* Label version number */

  /* VerNum 11 and greater Bacula 1.27 and later */
  btime_t   label_btime;              /* Time/date tape labeled */
  btime_t   write_btime;              /* Time/date tape first written */

  /* The following are 0 in VerNum 11 and greater */
  float64_t write_date;               /* Date this label written */
  float64_t write_time;               /* Time this label written */

  char VolName[128];                  /* Volume name */
  char PrevVolName[128];              /* Previous Volume Name */
  char PoolName[128];                 /* Pool name */
  char PoolType[128];                 /* Pool type */
  char MediaType[128];                /* Type of this media */

  char HostName[128];                 /* Host name of writing computer */
  char LabelProg[32];                 /* Label program name */
  char ProgVersion[32];               /* Program version */
  char ProgDate[32];                  /* Program build date/time */
</pre>

For Bacula versions 1.26 and earlier, the Volume Label is:
<pre>
  char Id[32];                        /* Bacula 0.9 mortal\n */
  uint32_t VerNum;                    /* Label version number */

  float64_t label_date;               /* Date tape labeled */
  float64_t label_time;               /* Time tape labeled */

  float64_t write_date;               /* Date this label written */
  float64_t write_time;               /* Time this label written */

  char VolName[128];                  /* Volume name */
  char PrevVolName[128];              /* Previous Volume Name */
  char PoolName[128];                 /* Pool name */
  char PoolType[128];                 /* Pool type */
  char MediaType[128];                /* Type of this media */

  char HostName[128];                 /* Host name of writing computer */
  char LabelProg[32];                 /* Label program name */
  char ProgVersion[32];               /* Program version */
  char ProgDate[32];                  /* Program build date/time */
</pre>


Note, the LabelType (Volume Label, Volume PreLabel, Session Start Label, ...)
is stored in the record FileIndex field of the Record Header and does not appear in the data
part of the record.

<h2>Session Label</h2>
The Session Label is written at the beginning and end of each session as
well as the last record on the physical medium.
It has the following binary format:
<pre>
  char Id[32];                        /* Bacula Immortal ... */
  uint32_t VerNum;                    /* Label version number */

  uint32_t JobId;                     /* Job id */
  uint32_t VolumeIndex;               /* sequence no of vol */

  /* Prior to VerNum 11 */
  float64_t write_date;               /* Date this label written */

  /* VerNum 11 and greater */
  btime_t   write_btime;              /* time/date record written */

  /* The following is zero VerNum 11 and greater */
  float64_t write_time;               /* Time this label written */

  char PoolName[128];                 /* Pool name */
  char PoolType[128];                 /* Pool type */
  char JobName[128];                  /* base Job name */
  char ClientName[128];
  /* Added in VerNum 10 */
  char Job[128];                      /* Unique Job name */
  char FileSetName[128];              /* FileSet name */
  uint32_t JobType;
  uint32_t JobLevel;
</pre>
In addition, the EOS label contains:
<pre>
  /* The remainder are part of EOS label only */
  uint32_t JobFiles;
  uint64_t JobBytes;
  uint32_t start_block;
  uint32_t end_block;
  uint32_t start_file;
  uint32_t end_file;
  uint32_t JobErrors;
</pre>
In addition, for VerNum greater than 10, the EOS label
contains (in addition to the above):
<pre>
  uint32_t JobStatus                  /* Job termination code */
</pre>:

Note, the LabelType (Volume Label, Volume PreLabel, Session Start Label, ...)
is stored in the record FileIndex field and does not appear in the data
part of the record.
Also, the Stream field of the Record Header contains the JobId. This
permits quick filtering without actually reading all the session data
in many cases.

<h2>Overall Storage Format</h2>

<pre>

               Current Bacula Tape Format
                     6 June 2001

           Version BB02 added 28 September 2002
           Version BB01 is the old deprecated format.


   A Bacula tape is composed of tape Blocks.  Each block
     has a Block header followed by the block data. Block
     Data consists of Records. Records consist of Record
     Headers followed by Record Data.

   :=======================================================:
   |                                                       |      
   |                 Block Header (24 bytes)               | 
   |                 (16 bytes version BB01)               |      
   |-------------------------------------------------------|    
   |                                                       | 
   |              Record Header (12 bytes)                 | 
   |               (20 bytes version BB01)                 |
   |-------------------------------------------------------|
   |                                                       |
   |                  Record Data                          |
   |                                                       |
   |-------------------------------------------------------|
   |                                                       |
   |              Record Header (12 bytes)                 |
   |               (20 bytes version BB01)                 |
   |-------------------------------------------------------|
   |                                                       |
   |                       ...                             |


   Block Header: the first item in each block. The format is
     shown below.

   Partial Data block: occurs if the data from a previous
     block spills over to this block (the normal case except
     for the first block on a tape). However, this partial
         data block is always preceded by a record header.

   Record Header: identifies the Volume Session, the Stream
     and the following Record Data size. See below for format.

   Record data: arbitrary binary data.


                    Block Header Format BB02
   :=======================================================:
   |              CheckSum         (uint32_t)              |
   |-------------------------------------------------------|  
   |              BlockSize        (uint32_t)              |  
   |-------------------------------------------------------| 
   |              BlockNumber      (uint32_t)              |  
   |-------------------------------------------------------|
   |              &quot;BB02&quot;           (char [4])              |
   |-------------------------------------------------------|  
   |              VolSessionId     (uint32_t)              |
   |-------------------------------------------------------|  
   |              VolSessionTime   (uint32_t)              |  
   :=======================================================:

   BBO2: Serves to identify the block as a 
     Bacula block and also servers as a block format identifier
     should we ever need to change the format.

                    Block Header Format BB01 (deprecated)
   :=======================================================:
   |              CheckSum         (uint32_t)              |
   |-------------------------------------------------------|  
   |              BlockSize        (uint32_t)              |  
   |-------------------------------------------------------| 
   |              BlockNumber      (uint32_t)              |  
   |-------------------------------------------------------|
   |              &quot;BB01&quot;           (char [4])              |
   :=======================================================:

   BBO1: Serves to identify the block as a 
     Bacula block and also servers as a block format identifier
     should we ever need to change the format.


   BlockSize: is the size in bytes of the block. When reading
     back a block, if the BlockSize does not agree with the
     actual size read, Bacula discards the block.

   CheckSum: a checksum for the Block.

   BlockNumber: is the sequential block number on the tape.

   VolSessionId: a unique sequential number that is assigned
                 by the Storage Daemon to a particular Job.
                 This number is sequential since the start
                 of execution of the daemon.

   VolSessionTime: the time/date that the current execution
                 of the Storage Daemon started.  It assures
                 that the combination of VolSessionId and
                 VolSessionTime is unique for all jobs
                 written to the tape, even if there was a
                 machine crash between two writes.

                  Record Header Format BB02
   :=======================================================:
   |              FileIndex        (int32_t)               | 
   |-------------------------------------------------------|
   |              Stream           (int32_t)               |
   |-------------------------------------------------------|
   |              DataSize         (uint32_t)              |
   :=======================================================:


                  Record Header Format BB01 (deprecated)
   :=======================================================:
   |              VolSessionId     (uint32_t)              |
   |-------------------------------------------------------|  
   |              VolSessionTime   (uint32_t)              |  
   |-------------------------------------------------------| 
   |              FileIndex        (int32_t)               | 
   |-------------------------------------------------------|
   |              Stream           (int32_t)               |
   |-------------------------------------------------------|
   |              DataSize         (uint32_t)              |
   :=======================================================:


   VolSessionId: a unique sequential number that is assigned
                 by the Storage Daemon to a particular Job.
                 This number is sequential since the start
                 of execution of the daemon.

   VolSessionTime: the time/date that the current execution
                 of the Storage Daemon started.  It assures
                 that the combination of VolSessionId and
                 VolSessionTime is unique for all jobs
                 written to the tape, even if there was a
                 machine crash between two writes.

   FileIndex: a sequential file number within a job.  The
                 Storage daemon enforces this index to be
                 greater than zero and sequential.  Note,
                 however, that the File daemon may send
                 multiple Streams for the same FileIndex.
                 The Storage Daemon uses negative FileIndices
                 to identify Session Start and End labels
                 as well as the End of Volume labels.

   Stream: defined by the File daemon and is intended to be
                 used to identify separate parts of the data
                 saved for each file (attributes, file data,
                 ...).  The Storage Daemon has no idea of
                 what a Stream is or what it contains.  

   DataSize: the size in bytes of the binary data record
                 that follows the Session Record header.
                 The Storage Daemon has no idea of the
                 actual contents of the binary data record.
                 For standard Unix files, the data record
                 typically contains the file attributes or
                 the file data.  For a sparse file 
                 the first 64 bits of the data contains
                 the storage address for the data block.

                       Volume Label
   :=======================================================:
   |              Id               (32 bytes)              |
   |-------------------------------------------------------|
   |              VerNum           (uint32_t)              |
   |-------------------------------------------------------|
   |              label_date       (float64_t)             |
   |              label_btime      (btime_t VerNum 11      |
   |-------------------------------------------------------|
   |              label_time       (float64_t)             |
   |              write_btime      (btime_t VerNum 11      |
   |-------------------------------------------------------|
   |              write_date       (float64_t)             |
   |                  0            (float64_t) VerNum 11   |
   |-------------------------------------------------------|
   |              write_time       (float64_t)             |
   |                  0            (float64_t) VerNum 11   |
   |-------------------------------------------------------|
   |              VolName          (128 bytes)             |
   |-------------------------------------------------------|
   |              PrevVolName      (128 bytes)             |
   |-------------------------------------------------------|
   |              PoolName         (128 bytes)             |
   |-------------------------------------------------------|
   |              PoolType         (128 bytes)             |
   |-------------------------------------------------------|
   |              MediaType        (128 bytes)             |
   |-------------------------------------------------------|
   |              HostName         (128 bytes)             |
   |-------------------------------------------------------|
   |              LabelProg        (32 bytes)              |
   |-------------------------------------------------------|
   |              ProgVersion      (32 bytes)              |
   |-------------------------------------------------------|
   |              ProgDate         (32 bytes)              |
   |-------------------------------------------------------|
   :=======================================================:

                 
   Id: 32 byte Bacula identifier &quot;Bacula 1.0 immortal\n&quot;

   (old version also recognized:)
   Id: 32 byte Bacula identifier &quot;Bacula 0.9 mortal\n&quot;

   LabelType (Saved in the FileIndex of the Header record).
       PRE_LABEL -1    Volume label on unwritten tape
       VOL_LABEL -2    Volume label after tape written
       EOM_LABEL -3    Label at EOM (not currently implemented)
       SOS_LABEL -4    Start of Session label (format given below)
       EOS_LABEL -5    End of Session label (format given below)


   VerNum: 11

   label_date: Julian day tape labeled
   label_time: Julian time tape labeled

   write_date: Julian date tape first used (data written)    
   write_time: Julian time tape first used (data written)

   VolName: "Physical" Volume name

   PrevVolName: The VolName of the previous tape (if this tape is
                a continuation of the previous one).

   PoolName: Pool Name

   PoolType: Pool Type

   MediaType: Media Type

   HostName: Name of host that is first writing the tape

   LabelProg: Name of the program that labeled the tape

   ProgVersion: Version of the label program

   ProgDate: Date Label program built



                       Session Label
   :=======================================================:
   |              Id               (32 bytes)              |
   |-------------------------------------------------------|
   |              VerNum           (uint32_t)              |
   |-------------------------------------------------------|
   |              JobId            (uint32_t)              |
   |-------------------------------------------------------|
   |              write_btime      (btime_t)   VerNum 11   |
   |             *write_date       (float64_t) VerNum 10   |
   |-------------------------------------------------------|
   |                 0             (float64_t) VerNum 11   |
   |             *write_time       (float64_t) VerNum 10   |
   |-------------------------------------------------------|
   |              PoolName         (128 bytes)             |
   |-------------------------------------------------------|
   |              PoolType         (128 bytes)             |
   |-------------------------------------------------------|
   |              JobName          (128 bytes)             |
   |-------------------------------------------------------|
   |              ClientName       (128 bytes)             |
   |-------------------------------------------------------|
   |              Job              (128 bytes)             |
   |-------------------------------------------------------|
   |              FileSetName      (128 bytes)             |
   |-------------------------------------------------------|
   |              JobType          (uint32_t)              |
   |-------------------------------------------------------|
   |              JobLevel         (uint32_t)              |
   |-------------------------------------------------------|
   |              FileSetMD5       (50 bytes)   VerNum 11  |
   |-------------------------------------------------------|

           Additional fields in End Of Session Label

   |-------------------------------------------------------|
   |              JobFiles         (uint32_t)              |
   |-------------------------------------------------------|
   |              JobBytes         (uint32_t)              |
   |-------------------------------------------------------|
   |              start_block      (uint32_t)              |
   |-------------------------------------------------------|
   |              end_block        (uint32_t)              |
   |-------------------------------------------------------|
   |              start_file       (uint32_t)              |
   |-------------------------------------------------------|
   |              end_file         (uint32_t)              |
   |-------------------------------------------------------|
   |              JobErrors        (uint32_t)              |
   |-------------------------------------------------------|
   |              JobStatus        (uint32_t) VerNum 11    |
   :=======================================================:

   * => fields deprecated

   Id: 32 byte Bacula Identifier &quot;Bacula 1.0 immortal\n&quot;


   LabelType (in FileIndex field of Header):
       EOM_LABEL -3     Label at EOM
       SOS_LABEL -4     Start of Session label
       EOS_LABEL -5     End of Session label

   VerNum: 11

   JobId: JobId

   write_btime: Bacula time/date this tape record written 

   write_date: Julian date tape this record written - deprecated
   write_time: Julian time tape this record written - deprecated.

   PoolName: Pool Name

   PoolType: Pool Type

   MediaType: Media Type

   ClientName: Name of File daemon or Client writing this session
               Not used for EOM_LABEL.

</pre>

<h2>Unix File Attributes</h2>
<p>The Unix File Attributes packet consists of the following:
<p class="tty">&lt;File-Index&gt; &lt;Type&gt; 
&lt;Filename&gt;@&lt;File-Attributes&gt;@&lt;Link&gt;
@&lt;Extended-Attributes@&gt;</p>
where
<dl>
  <dt>@<dd>represents a byte containing a binary zero.
  <dt>FileIndex<dd>is the sequential file index starting from one assigned
                    by the File daemon.
  <dt>Type<dd>is one of the following:
  <pre>
#define FT_LNKSAVED   1               /* hard link to file already saved */  
#define FT_REGE       2               /* Regular file but empty */
#define FT_REG        3               /* Regular file */
#define FT_LNK        4               /* Link */
#define FT_DIR        5               /* Directory */
#define FT_SPEC       6               /* Special file -- chr, blk, fifo, sock */
#define FT_NOACCESS   7               /* Not able to access */
#define FT_NOFOLLOW   8               /* Could not follow link */
#define FT_NOSTAT     9               /* Could not stat file */
#define FT_NOCHG     10               /* Incremental option, file not changed */
#define FT_ISARCH    11               /* Trying to save archive file */
#define FT_NORECURSE 12               /* No recursion into directory */
#define FT_NOFSCHG   13               /* Different file system, prohibited */
#define FT_NOOPEN    14               /* Could not open directory */
</pre>
  <dt>Filename</dt><dd>is the fully qualified filename.</dd>
  <dt>File-Attributes</dt><dd>consists of the 13 fields of the stat() buffer in 
      ASCII base64 format separated by spaces. These fields
      and their meanings are shown below. This stat() packet is in Unix
      format, and MUST be provided (constructed) for ALL systems.</dd>
  <dt>Link</dt><dd>when the FT code is FT_LNK or FT_LNKSAVED, the item in
      question is a Unix link, and this field contains the fully
      qualified link name.  When the FT code is not FT_LNK or
      FT_LNKSAVED, this field is null.</dd>
   <dt>Extended-Attributes</dt><dd>The exact format of this field is
      operating system dependent. It contains additional or extended 
      attributes of a system dependent nature. Currently, this field is
      used only on WIN32 systems where it contains a ASCII base64 
      representation of the WIN32_FILE_ATTRIBUTE_DATA structure as defined
      by Windows. The fields in the base64 representation of this structure
      are like the File-Attributes separated by spaces.</dd>

</dl>
<p>The File-attributes consist of the following:
<p>
<table border="2" cellpadding="2">
<tr>
    <th>Field No.</th>
        <th>Stat Name</th>
        <th>Unix</th>
        <th>Win98/NT</th>
        <th>MacOS</th>
</tr>
<tr>
        <td align="center">1</td>
        <td>st_dev</td>
        <td>Device number of filesystem</td>
        <td>Drive number</td>
        <td>vRefNum</td>
</tr>

<tr>
        <td align="center">2</td>
        <td>st_ino</td>
        <td>Inode number</td>
        <td>Always 0</td>
        <td>fileID/dirID</td>
</tr>
<tr>
        <td align="center">3</td>
        <td>st_mode</td>
        <td>File mode</td>
        <td>File mode</td>
        <td>777 dirs/apps; 666 docs; 444 locked docs</td>
</tr>
<tr>
        <td align="center">4</td>
        <td>st_nlink</td>
        <td>Number of links to the file</td>
        <td>Number of link (only on NTFS)</td>
        <td>Always 1</td>
</tr>
<tr>
        <td align="center">5</td>
        <td>st_uid</td>
        <td>Owner ID</td>
        <td>Always 0</td>
        <td>Always 0</td>
</tr>
<tr>
        <td align="center">6</td>
        <td>st_gid</td>
        <td>Group ID</td>
        <td>Always 0</td>
        <td>Always 0</td>
</tr>
<tr>
        <td align="center">7</td>
        <td>st_rdev</td>
        <td>Device ID for special files</td>
        <td>Drive No.</td>
        <td>Always 0</td>
</tr>
<tr>
        <td align="center">8</td>
        <td>st_size</td>
        <td>File size in bytes</td>
        <td>File size in bytes</td>
        <td>Data fork file size in bytes</td>
</tr>
<tr>
        <td align="center">9</td>
        <td>st_blksize</td>
        <td>Preferred block size</td>
        <td>Always 0</td>
        <td>Preferred block size</td>
</tr>
<tr>
        <td align="center">10</td>
        <td>st_blocks</td>
        <td>Number of blocks allocated</td>
        <td>Always 0</td>
        <td>Number of blocks allocated</td>
</tr>
<tr>
        <td align="center">11</td>
        <td>st_atime</td>
        <td>Last access time since epoch</td>
        <td>Last access time since epoch</td>
        <td>Last access time -66 years</td>
</tr>
<tr>
        <td align="center">12</td>
        <td>st_mtime</td>
        <td>Last modify time since epoch</td>
        <td>Last modify time since epoch</td>
        <td>Last access time -66 years</td>
</tr>
<tr>
        <td align="center">13</td>
        <td>st_ctime</td>
        <td>Inode change time since epoch</td>
        <td>File create time since epoch</td>
        <td>File create time -66 years</td>
</tr>
</table>

<page_prev name="Bacula Daemon Protocol" url="daemonprotocol.html">
<page_next name="Bacula Memory Management" url="mempool.html">
