/* $NetBSD: ecma167-udf.h,v 1.17 2022/03/18 16:06:18 reinoud Exp $ */

/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2008, 2009, 2017, 2018
*      Reinoud Zandijk <[email protected]>
* Copyright (c) 2001, 2002 Scott Long <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* Extended and adapted for UDFv2.50+ bij Reinoud Zandijk based on the
* original by Scott Long.
*
* 20030508 Made some small typo and explanatory comments
* 20030510 Added UDF 2.01 structures
* 20030519 Added/correct comments on multi-partitioned logical volume space
* 20050616 Added pseudo overwrite
* 20050624 Added the missing extended attribute types and `magic values'.
* 20051106 Reworked some implementation use parts
*
*/


#ifndef _FS_UDF_ECMA167_UDF_H_
#define _FS_UDF_ECMA167_UDF_H_


/*
* in case of an older gcc versions, define the __packed as explicit
* attribute
*/

/*
* You may specify the `aligned' and `transparent_union' attributes either in
* a `typedef' declaration or just past the closing curly brace of a complete
* enum, struct or union type _definition_ and the `packed' attribute only
* past the closing brace of a definition.  You may also specify attributes
* between the enum, struct or union tag and the name of the type rather than
* after the closing brace.
*/

#ifndef __packed
#define __packed __attribute__((packed))
#endif


/* ecma167-udf.h */

/* Volume recognition sequence ECMA 167 rev. 3 16.1 */
struct vrs_desc {
       uint8_t                 struct_type;
       uint8_t                 identifier[5];
       uint8_t                 version;
       uint8_t                 data[2041];
} __packed;


#define VRS_NSR02               "NSR02"
#define VRS_NSR03               "NSR03"
#define VRS_BEA01               "BEA01"
#define VRS_TEA01               "TEA01"
#define VRS_CD001               "CD001"
#define VRS_CDW02               "CDW02"


/* Structure/definitions/constants a la ECMA 167 rev. 3 */


#define MAX_TAGID_VOLUMES 9
/* Tag identifiers */
enum {
       TAGID_SPARING_TABLE =     0,
       TAGID_PRI_VOL =           1,
       TAGID_ANCHOR =            2,
       TAGID_VOL =               3,
       TAGID_IMP_VOL =           4,
       TAGID_PARTITION =         5,
       TAGID_LOGVOL =            6,
       TAGID_UNALLOC_SPACE =     7,
       TAGID_TERM =              8,
       TAGID_LOGVOL_INTEGRITY=   9,
       TAGID_FSD =             256,
       TAGID_FID =             257,
       TAGID_ALLOCEXTENT =     258,
       TAGID_INDIRECTENTRY =   259,
       TAGID_ICB_TERM =        260,
       TAGID_FENTRY =          261,
       TAGID_EXTATTR_HDR =     262,
       TAGID_UNALL_SP_ENTRY =  263,
       TAGID_SPACE_BITMAP =    264,
       TAGID_PART_INTEGRITY =  265,
       TAGID_EXTFENTRY =       266,
       TAGID_MAX =             266
};


enum {
       UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT = 1,
       UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT = 2
};


enum {
       UDF_ACCESSTYPE_NOT_SPECIFIED   = 0,     /* unknown                              */
       UDF_ACCESSTYPE_PSEUDO_OVERWITE = 0,     /* pseudo overwritable, e.g. BD-R's LOW */
       UDF_ACCESSTYPE_READ_ONLY       = 1,     /* really only readable                 */
       UDF_ACCESSTYPE_WRITE_ONCE      = 2,     /* write once and you're done           */
       UDF_ACCESSTYPE_REWRITEABLE     = 3,     /* may need extra work to rewrite       */
       UDF_ACCESSTYPE_OVERWRITABLE    = 4      /* no limits on rewriting; e.g. harddisc*/
};


/* Descriptor tag [3/7.2] */
struct desc_tag {
       uint16_t        id;
       uint16_t        descriptor_ver;
       uint8_t         cksum;
       uint8_t         reserved;
       uint16_t        serial_num;
       uint16_t        desc_crc;
       uint16_t        desc_crc_len;
       uint32_t        tag_loc;
} __packed;
#define UDF_DESC_TAG_LENGTH 16


/* Recorded Address [4/7.1] */
struct lb_addr {                        /* within partition space */
       uint32_t        lb_num;
       uint16_t        part_num;
} __packed;


/* Extent Descriptor [3/7.1] */
struct extent_ad {
       uint32_t        len;
       uint32_t        loc;
} __packed;


/* Short Allocation Descriptor [4/14.14.1] */
struct short_ad {
       uint32_t        len;
       uint32_t        lb_num;
} __packed;


/* Long Allocation Descriptor [4/14.14.2] */
struct UDF_ADImp_use {
       uint16_t        flags;
       uint32_t        unique_id;
} __packed;
#define UDF_ADIMP_FLAGS_EXTENT_ERASED 1


struct long_ad {
       uint32_t        len;
       struct lb_addr  loc;                    /* within a logical volume mapped partition space !! */
       union {
               uint8_t bytes[6];
               struct UDF_ADImp_use im_used;
       } impl;
} __packed;
#define longad_uniqueid impl.im_used.unique_id


/* Extended Allocation Descriptor [4/14.14.3] ; identifies an extent of allocation descriptors ; also in UDF ? */
struct ext_ad {
       uint32_t        ex_len;
       uint32_t        rec_len;
       uint32_t        inf_len;
       struct lb_addr  ex_loc;
       uint8_t         reserved[2];
} __packed;


/* ICB : Information Control Block; positioning */
union icb {
       struct short_ad s_ad;
       struct long_ad  l_ad;
       struct ext_ad   e_ad;
};


/* short/long/ext extent have flags encoded in length */
#define UDF_EXT_ALLOCATED              (0U<<30)
#define UDF_EXT_FREED                  (1U<<30)
#define UDF_EXT_ALLOCATED_BUT_NOT_USED (1U<<30)
#define UDF_EXT_FREE                   (2U<<30)
#define UDF_EXT_REDIRECT               (3U<<30)
#define UDF_EXT_FLAGS(len) ((len) & (3U<<30))
#define UDF_EXT_LEN(len)   ((len) & ((1U<<30)-1))
#define UDF_EXT_MAXLEN     ((1U<<30)-1)


/* Character set spec [1/7.2.1] */
struct charspec {
       uint8_t         type;
       uint8_t         inf[63];
} __packed;


struct pathcomp {
       uint8_t         type;
       uint8_t         l_ci;
       uint16_t        comp_filever;
       uint8_t         ident[256];
} __packed;
#define UDF_PATH_COMP_SIZE 4
#define UDF_PATH_COMP_RESERVED          0
#define UDF_PATH_COMP_ROOT              1
#define UDF_PATH_COMP_MOUNTROOT         2
#define UDF_PATH_COMP_PARENTDIR         3
#define UDF_PATH_COMP_CURDIR            4
#define UDF_PATH_COMP_NAME              5


/* Timestamp [1/7.3] */
struct timestamp {
       uint16_t        type_tz;
       uint16_t        year;
       uint8_t         month;
       uint8_t         day;
       uint8_t         hour;
       uint8_t         minute;
       uint8_t         second;
       uint8_t         centisec;
       uint8_t         hund_usec;
       uint8_t         usec;
} __packed;
#define UDF_TIMESTAMP_SIZE 12


/* Entity Identifier [1/7.4] */
#define UDF_REGID_ID_SIZE       23
struct regid {
       uint8_t         flags;
       uint8_t         id[UDF_REGID_ID_SIZE];
       uint8_t         id_suffix[8];
} __packed;


/* ICB Tag [4/14.6] */
struct icb_tag {
       uint32_t        prev_num_dirs;
       uint16_t        strat_type;
       union {
               uint8_t  strat_param[2];
               uint16_t strat_param16;
       };
       uint16_t        max_num_entries;
       uint8_t         reserved;
       uint8_t         file_type;
       struct lb_addr  parent_icb;
       uint16_t        flags;
} __packed;
#define UDF_ICB_TAG_FLAGS_ALLOC_MASK    0x03
#define UDF_ICB_SHORT_ALLOC             0x00
#define UDF_ICB_LONG_ALLOC              0x01
#define UDF_ICB_EXT_ALLOC               0x02
#define UDF_ICB_INTERN_ALLOC            0x03

#define UDF_ICB_TAG_FLAGS_DIRORDERED    (1<< 3)
#define UDF_ICB_TAG_FLAGS_NONRELOC      (1<< 4)
#define UDF_ICB_TAG_FLAGS_CONTIGUES     (1<< 9)
#define UDF_ICB_TAG_FLAGS_MULTIPLEVERS  (1<<12)

#define UDF_ICB_TAG_FLAGS_SETUID        (1<< 6)
#define UDF_ICB_TAG_FLAGS_SETGID        (1<< 7)
#define UDF_ICB_TAG_FLAGS_STICKY        (1<< 8)

#define UDF_ICB_FILETYPE_UNKNOWN          0
#define UDF_ICB_FILETYPE_UNALLOCSPACE     1
#define UDF_ICB_FILETYPE_PARTINTEGRITY    2
#define UDF_ICB_FILETYPE_INDIRECTENTRY    3
#define UDF_ICB_FILETYPE_DIRECTORY        4
#define UDF_ICB_FILETYPE_RANDOMACCESS     5
#define UDF_ICB_FILETYPE_BLOCKDEVICE      6
#define UDF_ICB_FILETYPE_CHARDEVICE       7
#define UDF_ICB_FILETYPE_EXTATTRREC       8
#define UDF_ICB_FILETYPE_FIFO             9
#define UDF_ICB_FILETYPE_SOCKET          10
#define UDF_ICB_FILETYPE_TERM            11
#define UDF_ICB_FILETYPE_SYMLINK         12
#define UDF_ICB_FILETYPE_STREAMDIR       13
#define UDF_ICB_FILETYPE_VAT            248
#define UDF_ICB_FILETYPE_REALTIME       249
#define UDF_ICB_FILETYPE_META_MAIN      250
#define UDF_ICB_FILETYPE_META_MIRROR    251
#define UDF_ICB_FILETYPE_META_BITMAP    252


/* Anchor Volume Descriptor Pointer [3/10.2] */
struct anchor_vdp {
       struct desc_tag         tag;
       struct extent_ad        main_vds_ex;            /* to main volume descriptor set      ; 16 sectors min */
       struct extent_ad        reserve_vds_ex;         /* copy of main volume descriptor set ; 16 sectors min */
} __packed;


/* Volume Descriptor Pointer [3/10.3] */
struct vol_desc_ptr {
       struct desc_tag         tag;                    /* use for extending the volume descriptor space */
       uint32_t                vds_number;
       struct extent_ad        next_vds_ex;            /* points to the next block for volume descriptor space */
} __packed;


/* Primary Volume Descriptor [3/10.1] */
struct pri_vol_desc {
       struct desc_tag         tag;
       uint32_t                seq_num;                /* MAX prevail */
       uint32_t                pvd_num;                /* assigned by author; 0 is special as in it may only occur once */
       char                    vol_id[32];             /* KEY ; main identifier of this disc */
       uint16_t                vds_num;                /* volume descriptor number; i.e. what volume number is it */
       uint16_t                max_vol_seq;            /* maximum volume descriptor number known */
       uint16_t                ichg_lvl;
       uint16_t                max_ichg_lvl;
       uint32_t                charset_list;
       uint32_t                max_charset_list;
       char                    volset_id[128];         /* KEY ; if part of a multi-disc set or a band of volumes */
       struct charspec         desc_charset;           /* KEY according to ECMA 167 */
       struct charspec         explanatory_charset;
       struct extent_ad        vol_abstract;
       struct extent_ad        vol_copyright;
       struct regid            app_id;
       struct timestamp        time;
       struct regid            imp_id;
       uint8_t                 imp_use[64];
       uint32_t                prev_vds_loc;           /* location of predecessor _lov ? */
       uint16_t                flags;                  /* bit 0 : if set indicates volume set name is meaningful */
       uint8_t                 reserved[22];
} __packed;


/* UDF specific implementation use part of the implementation use volume descriptor */
struct udf_lv_info {
       struct charspec         lvi_charset;
       char                    logvol_id[128];

       char                    lvinfo1[36];
       char                    lvinfo2[36];
       char                    lvinfo3[36];

       struct regid            impl_id;
       uint8_t                 impl_use[128];
} __packed;


/* Implementation use Volume Descriptor */
struct impvol_desc {
       struct desc_tag         tag;
       uint32_t                seq_num;
       struct regid            impl_id;
       union {
               struct udf_lv_info      lv_info;
               char                    impl_use[460];
       } _impl_use;
} __packed;


/* Logical Volume Descriptor [3/10.6] */
struct logvol_desc {
       struct desc_tag         tag;
       uint32_t                seq_num;                /* MAX prevail */
       struct charspec         desc_charset;           /* KEY */
       char                    logvol_id[128];         /* KEY */
       uint32_t                lb_size;
       struct regid            domain_id;
       union {
               struct long_ad  fsd_loc;                /* to fileset descriptor SEQUENCE */
               uint8_t         logvol_content_use[16];
       } _lvd_use;
       uint32_t                mt_l;                   /* Partition map length */
       uint32_t                n_pm;                   /* Number of partition maps */
       struct regid            imp_id;
       uint8_t                 imp_use[128];
       struct extent_ad        integrity_seq_loc;
       uint8_t                 maps[1];
} __packed;
#define lv_fsd_loc _lvd_use.fsd_loc

#define UDF_INTEGRITY_OPEN      0
#define UDF_INTEGRITY_CLOSED    1


#define UDF_PMAP_SIZE   64

/* Type 1 Partition Map [3/10.7.2] */
struct part_map_1 {
       uint8_t                 type;
       uint8_t                 len;
       uint16_t                vol_seq_num;
       uint16_t                part_num;
} __packed;


/* Type 2 Partition Map [3/10.7.3] */
struct part_map_2 {
       uint8_t                 type;
       uint8_t                 len;
       uint8_t                 reserved[2];
       struct regid            part_id;
       uint16_t                vol_seq_num;
       uint16_t                part_num;
       uint8_t                 reserved2[24];
} __packed;


/* Virtual Partition Map [UDF 2.01/2.2.8] */
struct part_map_virt {
       uint8_t                 type;
       uint8_t                 len;
       uint8_t                 reserved[2];
       struct regid            id;
       uint16_t                vol_seq_num;
       uint16_t                part_num;
       uint8_t                 reserved1[24];
} __packed;


/* Sparable Partition Map [UDF 2.01/2.2.9] */
struct part_map_spare {
       uint8_t                 type;
       uint8_t                 len;
       uint8_t                 reserved[2];
       struct regid            id;
       uint16_t                vol_seq_num;
       uint16_t                part_num;
       uint16_t                packet_len;
       uint8_t                 n_st;           /* Number of redundant sparing tables range 1-4 */
       uint8_t                 reserved1;
       uint32_t                st_size;        /* size of EACH sparing table  */
       uint32_t                st_loc[1];      /* locations of sparing tables */
} __packed;


/* Metadata Partition Map [UDF 2.50/2.2.10] */
struct part_map_meta {
       uint8_t                 type;
       uint8_t                 len;
       uint8_t                 reserved[2];
       struct regid            id;
       uint16_t                vol_seq_num;
       uint16_t                part_num;
       uint32_t                meta_file_lbn;          /* logical block number for file entry within part_num */
       uint32_t                meta_mirror_file_lbn;
       uint32_t                meta_bitmap_file_lbn;
       uint32_t                alloc_unit_size;        /* allocation unit size in blocks */
       uint16_t                alignment_unit_size;    /* alignment necessary in blocks  */
       uint8_t                 flags;
       uint8_t                 reserved1[5];
} __packed;
#define METADATA_DUPLICATED     1


union udf_pmap {
       uint8_t                 data[UDF_PMAP_SIZE];
       struct part_map_1       pm1;
       struct part_map_2       pm2;
       struct part_map_virt    pmv;
       struct part_map_spare   pms;
       struct part_map_meta    pmm;
};


/* Sparing Map Entry [UDF 2.01/2.2.11] */
struct spare_map_entry {
       uint32_t                org;                    /* partition relative address  */
       uint32_t                map;                    /* absolute disc address (!) can be in partition, but doesn't have to be */
} __packed;


/* Sparing Table [UDF 2.01/2.2.11] */
struct udf_sparing_table {
       struct desc_tag         tag;
       struct regid            id;
       uint16_t                rt_l;                   /* Relocation Table len */
       uint8_t                 reserved[2];
       uint32_t                seq_num;
       struct spare_map_entry  entries[1];
} __packed;


#define UDF_NO_PREV_VAT         0xffffffff
/* UDF 1.50 VAT suffix [UDF 2.2.10 (UDF 1.50 spec)] */
struct udf_oldvat_tail {
       struct regid            id;                     /* "*UDF Virtual Alloc Tbl" */
       uint32_t                prev_vat;
} __packed;


/* VAT table [UDF 2.0.1/2.2.10] */
struct udf_vat {
       uint16_t                header_len;
       uint16_t                impl_use_len;
       char                    logvol_id[128];         /* newer version of the LVD one */
       uint32_t                prev_vat;
       uint32_t                num_files;
       uint32_t                num_directories;
       uint16_t                min_udf_readver;
       uint16_t                min_udf_writever;
       uint16_t                max_udf_writever;
       uint16_t                reserved;
       uint8_t                 data[1];                /* impl.use followed by VAT entries (uint32_t) */
} __packed;


/* Space bitmap descriptor as found in the partition header descriptor */
struct space_bitmap_desc {
       struct desc_tag         tag;                    /* TagId 264                    */
       uint32_t                num_bits;               /* number of bits               */
       uint32_t                num_bytes;              /* bytes that contain it        */
       uint8_t                 data[1];
} __packed;


/* Unalloc space entry as found in the partition header descriptor */
struct space_entry_desc {
       struct desc_tag         tag;                    /* TagId 263                    */
       struct icb_tag          icbtag;                 /* type 1                       */
       uint32_t                l_ad;                   /* in bytes                     */
       uint8_t                 entry[1];
} __packed;


/* Partition header descriptor; in the contents_use of part_desc */
struct part_hdr_desc {
       struct short_ad         unalloc_space_table;
       struct short_ad         unalloc_space_bitmap;
       struct short_ad         part_integrity_table;   /* has to be ZERO for UDF */
       struct short_ad         freed_space_table;
       struct short_ad         freed_space_bitmap;
       uint8_t                 reserved[88];
} __packed;


/* Partition Descriptor [3/10.5] */
struct part_desc {
       struct desc_tag         tag;
       uint32_t                seq_num;                /* MAX prevailing */
       uint16_t                flags;                  /* bit 0 : if set the space is allocated */
       uint16_t                part_num;               /* KEY */
       struct regid            contents;
       union {
               struct part_hdr_desc    part_hdr;
               uint8_t                 contents_use[128];
       } _impl_use;
       uint32_t                access_type;            /* R/W, WORM etc. */
       uint32_t                start_loc;              /* start of partition with given length */
       uint32_t                part_len;
       struct regid            imp_id;
       uint8_t                 imp_use[128];
       uint8_t                 reserved[156];
} __packed;
#define pd_part_hdr _impl_use.part_hdr
#define UDF_PART_FLAG_ALLOCATED         1


/* Unallocated Space Descriptor (UDF 2.01/2.2.5) */
struct unalloc_sp_desc {
       struct desc_tag         tag;
       uint32_t                seq_num;        /* MAX prevailing */
       uint32_t                alloc_desc_num;
       struct extent_ad        alloc_desc[1];
} __packed;


/* Logical Volume Integrity Descriptor [3/30.10] */
struct logvolhdr {
       uint64_t                next_unique_id;
       /* rest reserved */
} __packed;


struct udf_logvol_info {
       struct regid            impl_id;
       uint32_t                num_files;
       uint32_t                num_directories;
       uint16_t                min_udf_readver;
       uint16_t                min_udf_writever;
       uint16_t                max_udf_writever;
} __packed;


struct logvol_int_desc {
       struct desc_tag         tag;
       struct timestamp        time;
       uint32_t                integrity_type;
       struct extent_ad        next_extent;
       union {
               struct logvolhdr  logvolhdr;
               int8_t            reserved[32];
       } _impl_use;
       uint32_t                num_part;
       uint32_t                l_iu;
       uint32_t                tables[1];      /* Freespace table, Sizetable, Implementation use */
} __packed;
#define lvint_next_unique_id _impl_use.logvolhdr.next_unique_id


/* File Set Descriptor [4/14.1] */
struct fileset_desc {
       struct desc_tag         tag;
       struct timestamp        time;
       uint16_t                ichg_lvl;
       uint16_t                max_ichg_lvl;
       uint32_t                charset_list;
       uint32_t                max_charset_list;
       uint32_t                fileset_num;                    /* key! */
       uint32_t                fileset_desc_num;
       struct charspec         logvol_id_charset;
       char                    logvol_id[128];                 /* for recovery                 */
       struct charspec         fileset_charset;
       char                    fileset_id[32];                 /* Mountpoint !!                */
       char                    copyright_file_id[32];
       char                    abstract_file_id[32];
       struct long_ad          rootdir_icb;                    /* to rootdir; icb->virtual ?   */
       struct regid            domain_id;
       struct long_ad          next_ex;                        /* to the next fileset_desc extent */
       struct long_ad          streamdir_icb;                  /* streamdir; needed?           */
       uint8_t                 reserved[32];
} __packed;


/* File Identifier Descriptor [4/14.4] */
struct fileid_desc {
       struct desc_tag         tag;
       uint16_t                file_version_num;
       uint8_t                 file_char;
       uint8_t                 l_fi;   /* Length of file identifier area */
       struct long_ad          icb;
       uint16_t                l_iu;   /* Length of implementation use area */
       uint8_t                 data[1];
} __packed;
#define UDF_FID_SIZE    38
#define UDF_FILE_CHAR_VIS       (1 << 0) /* Invisible */
#define UDF_FILE_CHAR_DIR       (1 << 1) /* Directory */
#define UDF_FILE_CHAR_DEL       (1 << 2) /* Deleted */
#define UDF_FILE_CHAR_PAR       (1 << 3) /* Parent Directory */
#define UDF_FILE_CHAR_META      (1 << 4) /* Stream metadata */


/* Extended attributes [4/14.10.1] */
struct extattrhdr_desc {
       struct desc_tag         tag;
       uint32_t                impl_attr_loc;  /* offsets within this descriptor */
       uint32_t                appl_attr_loc;  /* ditto */
} __packed;
#define UDF_IMPL_ATTR_LOC_NOT_PRESENT 0xffffffff
#define UDF_APPL_ATTR_LOC_NOT_PRESENT 0xffffffff


/* Extended attribute entry [4/48.10.2] */
struct extattr_entry {
       uint32_t                type;
       uint8_t                 subtype;
       uint8_t                 reserved[3];
       uint32_t                a_l;
} __packed;


/* Extended attribute entry; type 2048 [4/48.10.8] */
struct impl_extattr_entry {
       struct extattr_entry    hdr;
       uint32_t                iu_l;
       struct regid            imp_id;
       union {
               uint8_t  data[1];
               uint16_t data16;
       };
} __packed;


/* Extended attribute entry; type 65 536 [4/48.10.9] */
struct appl_extattr_entry {
       struct extattr_entry    hdr;
       uint32_t                au_l;
       struct regid            appl_id;
       uint8_t                 data[1];
} __packed;


/* File Times attribute entry; type 5 or type 6 [4/48.10.5], [4/48.10.6] */
struct filetimes_extattr_entry {
       struct extattr_entry    hdr;
       uint32_t                d_l;            /* length of times[] data following */
       uint32_t                existence;      /* bitmask */
       struct timestamp        times[1];       /* in order of ascending bits */
} __packed;
#define UDF_FILETIMES_ATTR_NO   5
#define UDF_FILETIMES_FILE_CREATION     1
#define UDF_FILETIMES_FILE_DELETION     4
#define UDF_FILETIMES_FILE_EFFECTIVE    8
#define UDF_FILETIMES_FILE_BACKUPED     16
#define UDF_FILETIMES_ATTR_SIZE(no)     (20 + (no)*sizeof(struct timestamp))


/* Device Specification Extended Attribute [4/4.10.7] */
struct device_extattr_entry {
       struct extattr_entry    hdr;
       uint32_t                iu_l;           /* length of implementation use */
       uint32_t                major;
       uint32_t                minor;
       uint8_t                 data[1];        /* UDF: if nonzero length, contain developer ID regid */
} __packed;
#define UDF_DEVICESPEC_ATTR_NO  12


/* VAT LV extension Extended Attribute [UDF 3.3.4.5.1.3] 1.50 errata */
struct vatlvext_extattr_entry {
       uint64_t                unique_id_chk;  /* needs to be copy of ICB's */
       uint32_t                num_files;
       uint32_t                num_directories;
       char                    logvol_id[128]; /* replaces logvol name */
} __packed;


/* File Entry [4/14.9] */
struct file_entry {
       struct desc_tag         tag;
       struct icb_tag          icbtag;
       uint32_t                uid;
       uint32_t                gid;
       uint32_t                perm;
       uint16_t                link_cnt;
       uint8_t                 rec_format;
       uint8_t                 rec_disp_attr;
       uint32_t                rec_len;
       uint64_t                inf_len;
       uint64_t                logblks_rec;
       struct timestamp        atime;
       struct timestamp        mtime;
       struct timestamp        attrtime;
       uint32_t                ckpoint;
       struct long_ad          ex_attr_icb;
       struct regid            imp_id;
       uint64_t                unique_id;
       uint32_t                l_ea;   /* Length of extended attribute area */
       uint32_t                l_ad;   /* Length of allocation descriptors */
       uint8_t                 data[1];
} __packed;
#define UDF_FENTRY_SIZE 176
#define UDF_FENTRY_PERM_USER_MASK       0x07
#define UDF_FENTRY_PERM_GRP_MASK        0xE0
#define UDF_FENTRY_PERM_OWNER_MASK      0x1C00


/* Extended File Entry [4/48.17] */
struct extfile_entry {
       struct desc_tag         tag;
       struct icb_tag          icbtag;
       uint32_t                uid;
       uint32_t                gid;
       uint32_t                perm;
       uint16_t                link_cnt;
       uint8_t                 rec_format;
       uint8_t                 rec_disp_attr;
       uint32_t                rec_len;
       uint64_t                inf_len;
       uint64_t                obj_size;
       uint64_t                logblks_rec;
       struct timestamp        atime;
       struct timestamp        mtime;
       struct timestamp        ctime;
       struct timestamp        attrtime;
       uint32_t                ckpoint;
       uint32_t                reserved1;
       struct long_ad          ex_attr_icb;
       struct long_ad          streamdir_icb;
       struct regid            imp_id;
       uint64_t                unique_id;
       uint32_t                l_ea;   /* Length of extended attribute area */
       uint32_t                l_ad;   /* Length of allocation descriptors */
       uint8_t                 data[1];
} __packed;
#define UDF_EXTFENTRY_SIZE      216


/* Indirect entry [ecma 48.7] */
struct indirect_entry {
       struct desc_tag         tag;
       struct icb_tag          icbtag;
       struct long_ad          indirect_icb;
} __packed;


/* Allocation extent descriptor [ecma 48.5] */
struct alloc_ext_entry {
       struct desc_tag         tag;
       uint32_t                prev_entry;
       uint32_t                l_ad;
       uint8_t                 data[1];
} __packed;


union dscrptr {
       struct desc_tag          tag;
       struct anchor_vdp        avdp;
       struct vol_desc_ptr      vdp;
       struct pri_vol_desc      pvd;
       struct logvol_desc       lvd;
       struct unalloc_sp_desc   usd;
       struct logvol_int_desc   lvid;
       struct impvol_desc       ivd;
       struct part_desc         pd;
       struct fileset_desc      fsd;
       struct fileid_desc       fid;
       struct file_entry        fe;
       struct extfile_entry     efe;
       struct extattrhdr_desc   eahd;
       struct indirect_entry    inde;
       struct alloc_ext_entry   aee;
       struct udf_sparing_table spt;
       struct space_bitmap_desc sbd;
       struct space_entry_desc  sed;
};


#endif /* !_FS_UDF_ECMA167_UDF_H_ */