linux/fs/udf/misc.c
<<
>>
Prefs
   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
  31struct 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
  39struct 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
  47struct 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_data;
  56        if (iinfo->i_lenEAttr) {
  57                ad = iinfo->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
 148struct 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_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 */
 199struct 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));
 253error_out:
 254        brelse(bh);
 255        return NULL;
 256}
 257
 258struct 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
 266void 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
 276void 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
 287u8 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}
 297