Root/fs/udf/misc.c

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/buffer_head.h>
27#include <linux/crc-itu-t.h>
28
29#include "udf_i.h"
30#include "udf_sb.h"
31
32struct buffer_head *udf_tgetblk(struct super_block *sb, int block)
33{
34    if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
35        return sb_getblk(sb, udf_fixed_to_variable(block));
36    else
37        return sb_getblk(sb, block);
38}
39
40struct buffer_head *udf_tread(struct super_block *sb, int block)
41{
42    if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
43        return sb_bread(sb, udf_fixed_to_variable(block));
44    else
45        return sb_bread(sb, block);
46}
47
48struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
49                       uint32_t type, uint8_t loc)
50{
51    uint8_t *ea = NULL, *ad = NULL;
52    int offset;
53    uint16_t crclen;
54    struct udf_inode_info *iinfo = UDF_I(inode);
55
56    ea = iinfo->i_ext.i_data;
57    if (iinfo->i_lenEAttr) {
58        ad = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
59    } else {
60        ad = ea;
61        size += sizeof(struct extendedAttrHeaderDesc);
62    }
63
64    offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
65        iinfo->i_lenAlloc;
66
67    /* TODO - Check for FreeEASpace */
68
69    if (loc & 0x01 && offset >= size) {
70        struct extendedAttrHeaderDesc *eahd;
71        eahd = (struct extendedAttrHeaderDesc *)ea;
72
73        if (iinfo->i_lenAlloc)
74            memmove(&ad[size], ad, iinfo->i_lenAlloc);
75
76        if (iinfo->i_lenEAttr) {
77            /* check checksum/crc */
78            if (eahd->descTag.tagIdent !=
79                    cpu_to_le16(TAG_IDENT_EAHD) ||
80                le32_to_cpu(eahd->descTag.tagLocation) !=
81                    iinfo->i_location.logicalBlockNum)
82                return NULL;
83        } else {
84            struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
85
86            size -= sizeof(struct extendedAttrHeaderDesc);
87            iinfo->i_lenEAttr +=
88                sizeof(struct extendedAttrHeaderDesc);
89            eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
90            if (sbi->s_udfrev >= 0x0200)
91                eahd->descTag.descVersion = cpu_to_le16(3);
92            else
93                eahd->descTag.descVersion = cpu_to_le16(2);
94            eahd->descTag.tagSerialNum =
95                    cpu_to_le16(sbi->s_serial_number);
96            eahd->descTag.tagLocation = cpu_to_le32(
97                    iinfo->i_location.logicalBlockNum);
98            eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
99            eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
100        }
101
102        offset = iinfo->i_lenEAttr;
103        if (type < 2048) {
104            if (le32_to_cpu(eahd->appAttrLocation) <
105                    iinfo->i_lenEAttr) {
106                uint32_t aal =
107                    le32_to_cpu(eahd->appAttrLocation);
108                memmove(&ea[offset - aal + size],
109                    &ea[aal], offset - aal);
110                offset -= aal;
111                eahd->appAttrLocation =
112                        cpu_to_le32(aal + size);
113            }
114            if (le32_to_cpu(eahd->impAttrLocation) <
115                    iinfo->i_lenEAttr) {
116                uint32_t ial =
117                    le32_to_cpu(eahd->impAttrLocation);
118                memmove(&ea[offset - ial + size],
119                    &ea[ial], offset - ial);
120                offset -= ial;
121                eahd->impAttrLocation =
122                        cpu_to_le32(ial + size);
123            }
124        } else if (type < 65536) {
125            if (le32_to_cpu(eahd->appAttrLocation) <
126                    iinfo->i_lenEAttr) {
127                uint32_t aal =
128                    le32_to_cpu(eahd->appAttrLocation);
129                memmove(&ea[offset - aal + size],
130                    &ea[aal], offset - aal);
131                offset -= aal;
132                eahd->appAttrLocation =
133                        cpu_to_le32(aal + size);
134            }
135        }
136        /* rewrite CRC + checksum of eahd */
137        crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag);
138        eahd->descTag.descCRCLength = cpu_to_le16(crclen);
139        eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
140                        sizeof(struct tag), crclen));
141        eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
142        iinfo->i_lenEAttr += size;
143        return (struct genericFormat *)&ea[offset];
144    }
145    if (loc & 0x02)
146        ;
147
148    return NULL;
149}
150
151struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
152                       uint8_t subtype)
153{
154    struct genericFormat *gaf;
155    uint8_t *ea = NULL;
156    uint32_t offset;
157    struct udf_inode_info *iinfo = UDF_I(inode);
158
159    ea = iinfo->i_ext.i_data;
160
161    if (iinfo->i_lenEAttr) {
162        struct extendedAttrHeaderDesc *eahd;
163        eahd = (struct extendedAttrHeaderDesc *)ea;
164
165        /* check checksum/crc */
166        if (eahd->descTag.tagIdent !=
167                cpu_to_le16(TAG_IDENT_EAHD) ||
168            le32_to_cpu(eahd->descTag.tagLocation) !=
169                iinfo->i_location.logicalBlockNum)
170            return NULL;
171
172        if (type < 2048)
173            offset = sizeof(struct extendedAttrHeaderDesc);
174        else if (type < 65536)
175            offset = le32_to_cpu(eahd->impAttrLocation);
176        else
177            offset = le32_to_cpu(eahd->appAttrLocation);
178
179        while (offset < iinfo->i_lenEAttr) {
180            gaf = (struct genericFormat *)&ea[offset];
181            if (le32_to_cpu(gaf->attrType) == type &&
182                    gaf->attrSubtype == subtype)
183                return gaf;
184            else
185                offset += le32_to_cpu(gaf->attrLength);
186        }
187    }
188
189    return NULL;
190}
191
192/*
193 * udf_read_tagged
194 *
195 * PURPOSE
196 * Read the first block of a tagged descriptor.
197 *
198 * HISTORY
199 * July 1, 1997 - Andrew E. Mileski
200 * Written, tested, and released.
201 */
202struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
203                    uint32_t location, uint16_t *ident)
204{
205    struct tag *tag_p;
206    struct buffer_head *bh = NULL;
207
208    /* Read the block */
209    if (block == 0xFFFFFFFF)
210        return NULL;
211
212    bh = udf_tread(sb, block);
213    if (!bh) {
214        udf_debug("block=%d, location=%d: read failed\n",
215              block, location);
216        return NULL;
217    }
218
219    tag_p = (struct tag *)(bh->b_data);
220
221    *ident = le16_to_cpu(tag_p->tagIdent);
222
223    if (location != le32_to_cpu(tag_p->tagLocation)) {
224        udf_debug("location mismatch block %u, tag %u != %u\n",
225              block, le32_to_cpu(tag_p->tagLocation), location);
226        goto error_out;
227    }
228
229    /* Verify the tag checksum */
230    if (udf_tag_checksum(tag_p) != tag_p->tagChecksum) {
231        printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
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_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\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 %d: crc = %d, crclen = %d\n", block,
251        le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
252
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

Archive Download this file



interactive