root/fs/udf/misc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. udf_tgetblk
  2. udf_tread
  3. udf_add_extendedattr
  4. udf_get_extendedattr
  5. udf_read_tagged
  6. udf_read_ptagged
  7. udf_update_tag
  8. udf_new_tag
  9. udf_tag_checksum

   1 /*
   2  * misc.c
   3  *
   4  * PURPOSE
   5  *      Miscellaneous routines for the OSTA-UDF(tm) filesystem.
   6  *
   7  * COPYRIGHT
   8  *      This file is distributed under the terms of the GNU General Public
   9  *      License (GPL). Copies of the GPL can be obtained from:
  10  *              ftp://prep.ai.mit.edu/pub/gnu/GPL
  11  *      Each contributing author retains all rights to their own work.
  12  *
  13  *  (C) 1998 Dave Boynton
  14  *  (C) 1998-2004 Ben Fennema
  15  *  (C) 1999-2000 Stelias Computing Inc
  16  *
  17  * HISTORY
  18  *
  19  *  04/19/99 blf  partial support for reading/writing specific EA's
  20  */
  21 
  22 #include "udfdecl.h"
  23 
  24 #include <linux/fs.h>
  25 #include <linux/string.h>
  26 #include <linux/crc-itu-t.h>
  27 
  28 #include "udf_i.h"
  29 #include "udf_sb.h"
  30 
  31 struct buffer_head *udf_tgetblk(struct super_block *sb, udf_pblk_t block)
  32 {
  33         if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
  34                 return sb_getblk(sb, udf_fixed_to_variable(block));
  35         else
  36                 return sb_getblk(sb, block);
  37 }
  38 
  39 struct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block)
  40 {
  41         if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
  42                 return sb_bread(sb, udf_fixed_to_variable(block));
  43         else
  44                 return sb_bread(sb, block);
  45 }
  46 
  47 struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
  48                                            uint32_t type, uint8_t loc)
  49 {
  50         uint8_t *ea = NULL, *ad = NULL;
  51         int offset;
  52         uint16_t crclen;
  53         struct udf_inode_info *iinfo = UDF_I(inode);
  54 
  55         ea = iinfo->i_ext.i_data;
  56         if (iinfo->i_lenEAttr) {
  57                 ad = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
  58         } else {
  59                 ad = ea;
  60                 size += sizeof(struct extendedAttrHeaderDesc);
  61         }
  62 
  63         offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
  64                 iinfo->i_lenAlloc;
  65 
  66         /* TODO - Check for FreeEASpace */
  67 
  68         if (loc & 0x01 && offset >= size) {
  69                 struct extendedAttrHeaderDesc *eahd;
  70                 eahd = (struct extendedAttrHeaderDesc *)ea;
  71 
  72                 if (iinfo->i_lenAlloc)
  73                         memmove(&ad[size], ad, iinfo->i_lenAlloc);
  74 
  75                 if (iinfo->i_lenEAttr) {
  76                         /* check checksum/crc */
  77                         if (eahd->descTag.tagIdent !=
  78                                         cpu_to_le16(TAG_IDENT_EAHD) ||
  79                             le32_to_cpu(eahd->descTag.tagLocation) !=
  80                                         iinfo->i_location.logicalBlockNum)
  81                                 return NULL;
  82                 } else {
  83                         struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
  84 
  85                         size -= sizeof(struct extendedAttrHeaderDesc);
  86                         iinfo->i_lenEAttr +=
  87                                 sizeof(struct extendedAttrHeaderDesc);
  88                         eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
  89                         if (sbi->s_udfrev >= 0x0200)
  90                                 eahd->descTag.descVersion = cpu_to_le16(3);
  91                         else
  92                                 eahd->descTag.descVersion = cpu_to_le16(2);
  93                         eahd->descTag.tagSerialNum =
  94                                         cpu_to_le16(sbi->s_serial_number);
  95                         eahd->descTag.tagLocation = cpu_to_le32(
  96                                         iinfo->i_location.logicalBlockNum);
  97                         eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
  98                         eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
  99                 }
 100 
 101                 offset = iinfo->i_lenEAttr;
 102                 if (type < 2048) {
 103                         if (le32_to_cpu(eahd->appAttrLocation) <
 104                                         iinfo->i_lenEAttr) {
 105                                 uint32_t aal =
 106                                         le32_to_cpu(eahd->appAttrLocation);
 107                                 memmove(&ea[offset - aal + size],
 108                                         &ea[aal], offset - aal);
 109                                 offset -= aal;
 110                                 eahd->appAttrLocation =
 111                                                 cpu_to_le32(aal + size);
 112                         }
 113                         if (le32_to_cpu(eahd->impAttrLocation) <
 114                                         iinfo->i_lenEAttr) {
 115                                 uint32_t ial =
 116                                         le32_to_cpu(eahd->impAttrLocation);
 117                                 memmove(&ea[offset - ial + size],
 118                                         &ea[ial], offset - ial);
 119                                 offset -= ial;
 120                                 eahd->impAttrLocation =
 121                                                 cpu_to_le32(ial + size);
 122                         }
 123                 } else if (type < 65536) {
 124                         if (le32_to_cpu(eahd->appAttrLocation) <
 125                                         iinfo->i_lenEAttr) {
 126                                 uint32_t aal =
 127                                         le32_to_cpu(eahd->appAttrLocation);
 128                                 memmove(&ea[offset - aal + size],
 129                                         &ea[aal], offset - aal);
 130                                 offset -= aal;
 131                                 eahd->appAttrLocation =
 132                                                 cpu_to_le32(aal + size);
 133                         }
 134                 }
 135                 /* rewrite CRC + checksum of eahd */
 136                 crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag);
 137                 eahd->descTag.descCRCLength = cpu_to_le16(crclen);
 138                 eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
 139                                                 sizeof(struct tag), crclen));
 140                 eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
 141                 iinfo->i_lenEAttr += size;
 142                 return (struct genericFormat *)&ea[offset];
 143         }
 144 
 145         return NULL;
 146 }
 147 
 148 struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
 149                                            uint8_t subtype)
 150 {
 151         struct genericFormat *gaf;
 152         uint8_t *ea = NULL;
 153         uint32_t offset;
 154         struct udf_inode_info *iinfo = UDF_I(inode);
 155 
 156         ea = iinfo->i_ext.i_data;
 157 
 158         if (iinfo->i_lenEAttr) {
 159                 struct extendedAttrHeaderDesc *eahd;
 160                 eahd = (struct extendedAttrHeaderDesc *)ea;
 161 
 162                 /* check checksum/crc */
 163                 if (eahd->descTag.tagIdent !=
 164                                 cpu_to_le16(TAG_IDENT_EAHD) ||
 165                     le32_to_cpu(eahd->descTag.tagLocation) !=
 166                                 iinfo->i_location.logicalBlockNum)
 167                         return NULL;
 168 
 169                 if (type < 2048)
 170                         offset = sizeof(struct extendedAttrHeaderDesc);
 171                 else if (type < 65536)
 172                         offset = le32_to_cpu(eahd->impAttrLocation);
 173                 else
 174                         offset = le32_to_cpu(eahd->appAttrLocation);
 175 
 176                 while (offset < iinfo->i_lenEAttr) {
 177                         gaf = (struct genericFormat *)&ea[offset];
 178                         if (le32_to_cpu(gaf->attrType) == type &&
 179                                         gaf->attrSubtype == subtype)
 180                                 return gaf;
 181                         else
 182                                 offset += le32_to_cpu(gaf->attrLength);
 183                 }
 184         }
 185 
 186         return NULL;
 187 }
 188 
 189 /*
 190  * udf_read_tagged
 191  *
 192  * PURPOSE
 193  *      Read the first block of a tagged descriptor.
 194  *
 195  * HISTORY
 196  *      July 1, 1997 - Andrew E. Mileski
 197  *      Written, tested, and released.
 198  */
 199 struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
 200                                     uint32_t location, uint16_t *ident)
 201 {
 202         struct tag *tag_p;
 203         struct buffer_head *bh = NULL;
 204         u8 checksum;
 205 
 206         /* Read the block */
 207         if (block == 0xFFFFFFFF)
 208                 return NULL;
 209 
 210         bh = udf_tread(sb, block);
 211         if (!bh) {
 212                 udf_err(sb, "read failed, block=%u, location=%u\n",
 213                         block, location);
 214                 return NULL;
 215         }
 216 
 217         tag_p = (struct tag *)(bh->b_data);
 218 
 219         *ident = le16_to_cpu(tag_p->tagIdent);
 220 
 221         if (location != le32_to_cpu(tag_p->tagLocation)) {
 222                 udf_debug("location mismatch block %u, tag %u != %u\n",
 223                           block, le32_to_cpu(tag_p->tagLocation), location);
 224                 goto error_out;
 225         }
 226 
 227         /* Verify the tag checksum */
 228         checksum = udf_tag_checksum(tag_p);
 229         if (checksum != tag_p->tagChecksum) {
 230                 udf_err(sb, "tag checksum failed, block %u: 0x%02x != 0x%02x\n",
 231                         block, checksum, tag_p->tagChecksum);
 232                 goto error_out;
 233         }
 234 
 235         /* Verify the tag version */
 236         if (tag_p->descVersion != cpu_to_le16(0x0002U) &&
 237             tag_p->descVersion != cpu_to_le16(0x0003U)) {
 238                 udf_err(sb, "tag version 0x%04x != 0x0002 || 0x0003, block %u\n",
 239                         le16_to_cpu(tag_p->descVersion), block);
 240                 goto error_out;
 241         }
 242 
 243         /* Verify the descriptor CRC */
 244         if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
 245             le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
 246                                         bh->b_data + sizeof(struct tag),
 247                                         le16_to_cpu(tag_p->descCRCLength)))
 248                 return bh;
 249 
 250         udf_debug("Crc failure block %u: crc = %u, crclen = %u\n", block,
 251                   le16_to_cpu(tag_p->descCRC),
 252                   le16_to_cpu(tag_p->descCRCLength));
 253 error_out:
 254         brelse(bh);
 255         return NULL;
 256 }
 257 
 258 struct buffer_head *udf_read_ptagged(struct super_block *sb,
 259                                      struct kernel_lb_addr *loc,
 260                                      uint32_t offset, uint16_t *ident)
 261 {
 262         return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
 263                                loc->logicalBlockNum + offset, ident);
 264 }
 265 
 266 void udf_update_tag(char *data, int length)
 267 {
 268         struct tag *tptr = (struct tag *)data;
 269         length -= sizeof(struct tag);
 270 
 271         tptr->descCRCLength = cpu_to_le16(length);
 272         tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length));
 273         tptr->tagChecksum = udf_tag_checksum(tptr);
 274 }
 275 
 276 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
 277                  uint32_t loc, int length)
 278 {
 279         struct tag *tptr = (struct tag *)data;
 280         tptr->tagIdent = cpu_to_le16(ident);
 281         tptr->descVersion = cpu_to_le16(version);
 282         tptr->tagSerialNum = cpu_to_le16(snum);
 283         tptr->tagLocation = cpu_to_le32(loc);
 284         udf_update_tag(data, length);
 285 }
 286 
 287 u8 udf_tag_checksum(const struct tag *t)
 288 {
 289         u8 *data = (u8 *)t;
 290         u8 checksum = 0;
 291         int i;
 292         for (i = 0; i < sizeof(struct tag); ++i)
 293                 if (i != 4) /* position of checksum */
 294                         checksum += data[i];
 295         return checksum;
 296 }

/* [<][>][^][v][top][bottom][index][help] */