%%
%%

\chapter{Storage Media Output Format}
\label{TheChapterStart9}
\index{Format!Storage Media Output}
\index{Storage Media Output Format}
\addcontentsline{toc}{section}{Storage Media Output Format}

\section{General}
\index{General}
\addcontentsline{toc}{subsection}{General}

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. 

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 {\bf
Bacula}. 

\section{Definitions}
\index{Definitions}
\addcontentsline{toc}{subsection}{Definitions}

\begin{description}

\item [Block]
   \index{Block}
   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. In older Bacula tape  versions, a block could
contain records (see record definition below)  from multiple  jobs. However,
all blocks currently written by Bacula are  block level BB02, and a given
block contains records for  only a single job. Different jobs simply have
their own private  blocks that are intermingled with the other blocks from
other jobs  on the Volume (previously the records were intermingled within 
the blocks). Having only records from a single job in any  give block
permitted moving the VolumeSessionId  and VolumeSessionTime (see below) from
each record heading to  the Block header. This has two advantages: 1. a block
can be  quickly rejected based on the contents of the header without  reading
all the records. 2. because there is on the average  more than one record per
block, less data is written to the  Volume for each job.  

\item [Record]
   \index{Record}
   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. A record is the
primitive unit  of information sent to and from the Storage daemon by the 
Client (File daemon) programs. The details are described below.  

\item [JobId]
   \index{JobId}
   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.  

\item [Session]
   \index{Session}
   A Session is a concept used in the Storage daemon  corresponds one to one to a
Job with the exception that  each session is uniquely identified within the
Storage  daemon by a unique SessionId/SessionTime pair (see below).  

\item [VolSessionId]
   \index{VolSessionId}
   A unique number assigned by the Storage daemon  to a particular session (Job)
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.  

\item [VolSessionTime]
   \index{VolSessionTime}
   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
{\bf VolSessionId} and the {\bf VolSessionTime}  for a given Storage daemon is
guaranteed to be unique for each  Job (or session). 

\item [FileIndex]
   \index{FileIndex}
   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. Thus, the  combination of
VolSessionId, VolSessionTime, and FileIndex  uniquely identifies the records
for a single file written  to a Volume.  

\item [Stream]
   \index{Stream}
   While writing the information for any particular  file to the Volume, there
can be any number of distinct  pieces of information about that file, e.g. the
attributes,  the file data, ... The Stream indicates what piece of data  it
is, and it is an arbitrary number assigned by the File daemon to the  parts
(Unix attributes, Win32 attributes, data, compressed data,\ ...) 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 single record,
or in multiple  records.  

\item [Block Header]
   \index{Block Header}
   A block header consists of a block identification  (``BB02''), 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. Current block
headers also contain the VolSessionId  and VolSessionTime for the records
written to that block.  

\item [Record Header]
   \index{Record Header}
   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 as written to tape does not
contain  the Volume Session Id and the Volume Session Time as these two 
fields are stored in the BB02 Block header. The in-memory record  header does
have those fields for convenience. 

\item [Data Record]
   \index{Data Record}
   A data record consists of a binary stream of bytes  and is always preceded by
a Record Header. The details of the  meaning of the binary stream of bytes are
unknown to the Storage  daemon, but the Client programs (File daemon) defines
and thus  knows the details of each record type.  

\item [Volume Label]
   \index{Volume Label}
   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. The Storage daemon  manages Volume Labels, and if the client wants, he
may also  read them.  

\item [Begin Session Label]
   \index{Begin Session Label}
   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.  

\item [End Session Label]
   \index{End Session Label}
   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. 
\end{description}

\section{Storage Daemon File Output Format}
\index{Format!Storage Daemon File Output}
\index{Storage Daemon File Output Format}
\addcontentsline{toc}{subsection}{Storage Daemon File Output Format}

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. 

\section{Overall Format}
\index{Format!Overall}
\index{Overall Format}
\addcontentsline{toc}{subsection}{Overall Format}

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. 

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. 

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). 

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. 

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 or duplicated. 

\section{Serialization}
\index{Serialization}
\addcontentsline{toc}{subsection}{Serialization}

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. 

\section{Block Header}
\index{Header!Block}
\index{Block Header}
\addcontentsline{toc}{subsection}{Block Header}

The format of the Block Header (version 1.27 and later) is: 

\footnotesize
\begin{verbatim}
   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 */
\end{verbatim}
\normalsize

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.


\section{Record Header}
\index{Header!Record}
\index{Record Header}
\addcontentsline{toc}{subsection}{Record Header}

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. 

The format of the Record Header (version 1.27 or later) is: 

\footnotesize
\begin{verbatim}
  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 */
\end{verbatim}
\normalsize

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. 

Additional notes on the above: 

\begin{description}

\item [The {\bf VolSessionId} ]
   \index{VolSessionId}
   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. 

\item [The {\bf VolSessionTime} ]
   \index{VolSessionTime}
   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. 

\item [The {\bf FileIndex} ]
   \index{FileIndex}
   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. 

\item [The {\bf Stream} ]
   \index{Stream}
   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).  

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:  

\footnotesize
\begin{verbatim}
#define STREAM_UNIX_ATTRIBUTES    1    /* Generic Unix attributes */
#define STREAM_FILE_DATA          2    /* Standard uncompressed data */
#define STREAM_MD5_SIGNATURE      3    /* MD5 signature for the file */
#define STREAM_GZIP_DATA          4    /* GZip compressed file data */
/* Extended Unix attributes with Win32 Extended data.  Deprecated. */
#define STREAM_UNIX_ATTRIBUTES_EX 5    /* Extended Unix attr for Win32 EX */
#define STREAM_SPARSE_DATA        6    /* Sparse data stream */
#define STREAM_SPARSE_GZIP_DATA   7
#define STREAM_PROGRAM_NAMES      8    /* program names for program data */
#define STREAM_PROGRAM_DATA       9    /* Data needing program */
#define STREAM_SHA1_SIGNATURE    10    /* SHA1 signature for the file */
#define STREAM_WIN32_DATA        11    /* Win32 BackupRead data */
#define STREAM_WIN32_GZIP_DATA   12    /* Gzipped Win32 BackupRead data */
#define STREAM_MACOS_FORK_DATA   13    /* Mac resource fork */
#define STREAM_HFSPLUS_ATTRIBUTES 14   /* Mac OS extra attributes */
#define STREAM_UNIX_ATTRIBUTES_ACCESS_ACL 15 /* Standard ACL attributes on UNIX */
#define STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL 16 /* Default ACL attributes on UNIX */
\end{verbatim}
\normalsize

\item [The {\bf DataSize} ]
   \index{DataSize}
   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. 
\end{description}

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. 

\section{Version BB02 Block Header}
\index{Version BB02 Block Header}
\index{Header!Version BB02 Block}
\addcontentsline{toc}{subsection}{Version BB02 Block Header}

Each session or Job has its own private block. As a consequence, the SessionId
and SessionTime are written once in each Block Header and not in the Record
Header. So, the second and current version of the Block Header BB02 is: 

\footnotesize
\begin{verbatim}
   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 */
\end{verbatim}
\normalsize

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 CRC 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. 

\section{Version 2 Record Header}
\index{Version 2 Record Header}
\index{Header!Version 2 Record}
\addcontentsline{toc}{subsection}{Version 2 Record Header}

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 old BB01
Record Header, but on the storage medium, the first two fields, namely
VolSessionId and VolSessionTime are not written. The Block Header is 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 is filled in the Record Header from the Block
Header. 

\section{Volume Label Format}
\index{Volume Label Format}
\index{Format!Volume Label}
\addcontentsline{toc}{subsection}{Volume Label Format}

Tape volume labels are created by the Storage daemon in response to a {\bf
label} command given to the Console program, or alternatively by the {\bf
btape} program. created. Each volume is labeled with the following information
using the Bacula serialization routines, which guarantee machine byte order
independence. 

For Bacula versions 1.27 and later, the Volume Label Format is: 

\footnotesize
\begin{verbatim}
  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 */
\end{verbatim}
\normalsize

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. 

\section{Session Label}
\index{Label!Session}
\index{Session Label}
\addcontentsline{toc}{subsection}{Session Label}

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:


\footnotesize
\begin{verbatim}
  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;
\end{verbatim}
\normalsize

In addition, the EOS label contains: 

\footnotesize
\begin{verbatim}
  /* 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;
\end{verbatim}
\normalsize

In addition, for VerNum greater than 10, the EOS label contains (in addition
to the above): 

\footnotesize
\begin{verbatim}
  uint32_t JobStatus          /* Job termination code */
\end{verbatim}
\normalsize

: 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. 

\section{Overall Storage Format}
\index{Format!Overall Storage}
\index{Overall Storage Format}
\addcontentsline{toc}{subsection}{Overall Storage Format}

\footnotesize
\begin{verbatim}
               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)               |
   |                                                       |
   |-------------------------------------------------------|
   |                                                       |
   |              Record Header (12 bytes)                 |
   |                                                       |
   |-------------------------------------------------------|
   |                                                       |
   |                  Record Data                          |
   |                                                       |
   |-------------------------------------------------------|
   |                                                       |
   |              Record Header (12 bytes)                 |
   |                                                       |
   |-------------------------------------------------------|
   |                                                       |
   |                       ...                             |
   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)              |
   |-------------------------------------------------------|
   |              "BB02"           (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.
   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)              |
   :=======================================================:
   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 "Bacula 1.0 immortal\n"
   (old version also recognized:)
   Id: 32 byte Bacula identifier "Bacula 0.9 mortal\n"
   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   |
   |-------------------------------------------------------|
   |                 0             (float64_t) VerNum 11   |
   |-------------------------------------------------------|
   |              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 "Bacula 1.0 immortal\n"
   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.
\end{verbatim}
\normalsize

\section{Unix File Attributes}
\index{Unix File Attributes}
\index{Attributes!Unix File}
\addcontentsline{toc}{subsection}{Unix File Attributes}

The Unix File Attributes packet consists of the following: 

\lt{}File-Index\gt{} \lt{}Type\gt{}
\lt{}Filename\gt{}@\lt{}File-Attributes\gt{}@\lt{}Link\gt{}
@\lt{}Extended-Attributes@\gt{} where 

\begin{description}

\item [@]
   represents a byte containing a binary zero.  

\item [FileIndex]
   \index{FileIndex}
   is the sequential file index starting from one assigned  by the File daemon.  

\item [Type]
   \index{Type}
   is one of the following: 

\footnotesize
\begin{verbatim}
#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    /* Soft 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_DIRNOCHG  11    /* Incremental option, directory not changed */
#define FT_ISARCH    12    /* Trying to save archive file */
#define FT_NORECURSE 13    /* No recursion into directory */
#define FT_NOFSCHG   14    /* Different file system, prohibited */
#define FT_NOOPEN    15    /* Could not open directory */
#define FT_RAW       16    /* Raw block device */
#define FT_FIFO      17    /* Raw fifo device */
\end{verbatim}
\normalsize

\item [Filename]
   \index{Filename}
   is the fully qualified filename.  

\item [File-Attributes]
   \index{File-Attributes}
   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.  

\item [Link]
   \index{Link}
   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.  

\item [Extended-Attributes]
   \index{Extended-Attributes}
   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. 
\end{description}

The File-attributes consist of the following: 

\addcontentsline{lot}{table}{File Attributes}
\begin{longtable}{|p{0.6in}|p{0.7in}|p{1in}|p{1in}|p{1.4in}|}
 \hline 
\multicolumn{1}{|c|}{\bf Field No. } & \multicolumn{1}{c|}{\bf Stat Name }
& \multicolumn{1}{c|}{\bf Unix } & \multicolumn{1}{c|}{\bf Win98/NT } &
\multicolumn{1}{c|}{\bf MacOS } \\
 \hline 
\multicolumn{1}{|c|}{1 } & {st\_dev } & {Device number of filesystem } &
{Drive number } & {vRefNum } \\
 \hline 
\multicolumn{1}{|c|}{2 } & {st\_ino } & {Inode number } & {Always 0 } &
{fileID/dirID } \\
 \hline 
\multicolumn{1}{|c|}{3 } & {st\_mode } & {File mode } & {File mode } &
{777 dirs/apps; 666 docs; 444 locked docs } \\
 \hline 
\multicolumn{1}{|c|}{4 } & {st\_nlink } & {Number of links to the file } &
{Number of link (only on NTFS) } & {Always 1 } \\
 \hline 
\multicolumn{1}{|c|}{5 } & {st\_uid } & {Owner ID } & {Always 0 } &
{Always 0 } \\
 \hline 
\multicolumn{1}{|c|}{6 } & {st\_gid } & {Group ID } & {Always 0 } &
{Always 0 } \\
 \hline 
\multicolumn{1}{|c|}{7 } & {st\_rdev } & {Device ID for special files } &
{Drive No. } & {Always 0 } \\
 \hline 
\multicolumn{1}{|c|}{8 } & {st\_size } & {File size in bytes } & {File
size in bytes } & {Data fork file size in bytes } \\
 \hline 
\multicolumn{1}{|c|}{9 } & {st\_blksize } & {Preferred block size } &
{Always 0 } & {Preferred block size } \\
 \hline 
\multicolumn{1}{|c|}{10 } & {st\_blocks } & {Number of blocks allocated }
& {Always 0 } & {Number of blocks allocated } \\
 \hline 
\multicolumn{1}{|c|}{11 } & {st\_atime } & {Last access time since epoch }
& {Last access time since epoch } & {Last access time -66 years } \\
 \hline 
\multicolumn{1}{|c|}{12 } & {st\_mtime } & {Last modify time since epoch }
& {Last modify time since epoch } & {Last access time -66 years } \\
 \hline 
\multicolumn{1}{|c|}{13 } & {st\_ctime } & {Inode change time since epoch 
} & {File create time since epoch } & {File create time -66 years}
\\ \hline 

\end{longtable}

\section{Old Depreciated Tape Format}
\index{Old Depreciated Tape Format}
\index{Format!Old Depreciated Tape}
\addcontentsline{toc}{subsection}{Old Depreciated Tape Format}

The format of the Block Header (version 1.26 and earlier) is: 

\footnotesize
\begin{verbatim}
   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 */
\end{verbatim}
\normalsize

The format of the Record Header (version 1.26 or earlier) is: 

\footnotesize
\begin{verbatim}
  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 */
\end{verbatim}
\normalsize

\footnotesize
\begin{verbatim}
               Current Bacula Tape Format
                     6 June 2001
           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                          |
   |                 (16 bytes version BB01)               |
   |-------------------------------------------------------|
   |                                                       |
   |              Record Header                            |
   |               (20 bytes version BB01)                 |
   |-------------------------------------------------------|
   |                                                       |
   |                  Record Data                          |
   |                                                       |
   |-------------------------------------------------------|
   |                                                       |
   |              Record Header                            |
   |               (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 BB01 (deprecated)
   :=======================================================:
   |              CheckSum         (uint32_t)              |
   |-------------------------------------------------------|
   |              BlockSize        (uint32_t)              |
   |-------------------------------------------------------|
   |              BlockNumber      (uint32_t)              |
   |-------------------------------------------------------|
   |              "BB01"           (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 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_time       (float64_t)             |
   |-------------------------------------------------------|
   |              write_date       (float64_t)             |
   |-------------------------------------------------------|
   |              write_time       (float64_t)             |
   |-------------------------------------------------------|
   |              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 "Bacula 1.0 immortal\n"
   (old version also recognized:)
   Id: 32 byte Bacula identifier "Bacula 0.9 mortal\n"
   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)
   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_date       (float64_t) VerNum 10   |
   |-------------------------------------------------------|
   |             *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 "Bacula 1.0 immortal\n"
   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.
\end{verbatim}
\normalsize
