~wb-munzinger/+junk/ocfs2-tools

« back to all changes in this revision

Viewing changes to libocfs2/xattr.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2009-07-06 07:26:30 UTC
  • mfrom: (1.1.7 upstream) (0.1.5 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090706072630-59335sl51k3rvu74
Tags: 1.4.2-1
* New upstream release (Closes: #535471).
* Drop patch for limits.h, included upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 8; -*-
 
2
 * vim: noexpandtab sw=8 ts=8 sts=0:
 
3
 *
 
4
 * xattr.c
 
5
 *
 
6
 * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public
 
10
 * License version 2 as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 */
 
17
#include <string.h>
 
18
#include <inttypes.h>
 
19
 
 
20
#include "ocfs2/byteorder.h"
 
21
#include "ocfs2/ocfs2.h"
 
22
 
 
23
struct ocfs2_xattr_def_value_root {
 
24
        struct ocfs2_xattr_value_root   xv;
 
25
        struct ocfs2_extent_rec         er;
 
26
};
 
27
 
 
28
#define OCFS2_XATTR_ROOT_SIZE   (sizeof(struct ocfs2_xattr_def_value_root))
 
29
 
 
30
uint32_t ocfs2_xattr_uuid_hash(unsigned char *uuid)
 
31
{
 
32
        uint32_t i, hash = 0;
 
33
 
 
34
        for (i = 0; i < OCFS2_VOL_UUID_LEN; i++) {
 
35
                hash = (hash << OCFS2_HASH_SHIFT) ^
 
36
                        (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
 
37
                        *uuid++;
 
38
        }
 
39
        return hash;
 
40
}
 
41
 
 
42
uint32_t ocfs2_xattr_name_hash(uint32_t uuid_hash,
 
43
                         const char *name,
 
44
                         int name_len)
 
45
{
 
46
        /* Get hash value of uuid from super block */
 
47
        uint32_t hash = uuid_hash;
 
48
        int i;
 
49
 
 
50
        /* hash extended attribute name */
 
51
        for (i = 0; i < name_len; i++) {
 
52
                hash = (hash << OCFS2_HASH_SHIFT) ^
 
53
                       (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
 
54
                       *name++;
 
55
        }
 
56
 
 
57
        return hash;
 
58
}
 
59
 
 
60
uint16_t ocfs2_xattr_buckets_per_cluster(ocfs2_filesys *fs)
 
61
{
 
62
        return fs->fs_clustersize / OCFS2_XATTR_BUCKET_SIZE;
 
63
}
 
64
 
 
65
uint16_t ocfs2_blocks_per_xattr_bucket(ocfs2_filesys *fs)
 
66
{
 
67
        return OCFS2_XATTR_BUCKET_SIZE / fs->fs_blocksize;
 
68
}
 
69
 
 
70
static void ocfs2_swap_xattr_entry(struct ocfs2_xattr_entry *xe)
 
71
{
 
72
        xe->xe_name_hash        = bswap_32(xe->xe_name_hash);
 
73
        xe->xe_name_offset      = bswap_16(xe->xe_name_offset);
 
74
        xe->xe_value_size       = bswap_64(xe->xe_value_size);
 
75
}
 
76
 
 
77
static void ocfs2_swap_xattr_tree_root(struct ocfs2_xattr_tree_root *xt)
 
78
{
 
79
        xt->xt_clusters         = bswap_32(xt->xt_clusters);
 
80
        xt->xt_last_eb_blk      = bswap_64(xt->xt_last_eb_blk);
 
81
}
 
82
 
 
83
static void ocfs2_swap_xattr_value_root(struct ocfs2_xattr_value_root *xr)
 
84
{
 
85
        xr->xr_clusters         = bswap_32(xr->xr_clusters);
 
86
        xr->xr_last_eb_blk      = bswap_64(xr->xr_last_eb_blk);
 
87
}
 
88
 
 
89
static void ocfs2_swap_xattr_block_header(struct ocfs2_xattr_block *xb)
 
90
{
 
91
        xb->xb_suballoc_slot    = bswap_16(xb->xb_suballoc_slot);
 
92
        xb->xb_suballoc_bit     = bswap_16(xb->xb_suballoc_bit);
 
93
        xb->xb_fs_generation    = bswap_32(xb->xb_fs_generation);
 
94
        xb->xb_blkno            = bswap_64(xb->xb_blkno);
 
95
        xb->xb_flags            = bswap_16(xb->xb_flags);
 
96
}
 
97
 
 
98
static void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh)
 
99
{
 
100
        if (cpu_is_little_endian)
 
101
                return;
 
102
 
 
103
        xh->xh_count            = bswap_16(xh->xh_count);
 
104
        xh->xh_free_start       = bswap_16(xh->xh_free_start);
 
105
        xh->xh_name_value_len   = bswap_16(xh->xh_name_value_len);
 
106
        xh->xh_num_buckets      = bswap_16(xh->xh_num_buckets);
 
107
}
 
108
 
 
109
static void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh)
 
110
{
 
111
        uint16_t i;
 
112
 
 
113
        if (cpu_is_little_endian)
 
114
                return;
 
115
 
 
116
        for (i = 0; i < xh->xh_count; i++) {
 
117
                struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
 
118
 
 
119
                ocfs2_swap_xattr_entry(xe);
 
120
 
 
121
                if (!ocfs2_xattr_is_local(xe)) {
 
122
                        struct ocfs2_xattr_value_root *xr =
 
123
                                (struct ocfs2_xattr_value_root *)
 
124
                                ((char *)xh + xe->xe_name_offset +
 
125
                                OCFS2_XATTR_SIZE(xe->xe_name_len));
 
126
 
 
127
                        ocfs2_swap_xattr_value_root(xr);
 
128
                        ocfs2_swap_extent_list_to_cpu(&xr->xr_list);
 
129
                }
 
130
        }
 
131
}
 
132
 
 
133
static void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh)
 
134
{
 
135
        uint16_t i;
 
136
 
 
137
        if (cpu_is_little_endian)
 
138
                return;
 
139
 
 
140
        for (i = 0; i < xh->xh_count; i++) {
 
141
                struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
 
142
 
 
143
                if (!ocfs2_xattr_is_local(xe)) {
 
144
                        struct ocfs2_xattr_value_root *xr =
 
145
                                (struct ocfs2_xattr_value_root *)
 
146
                                ((char *)xh + xe->xe_name_offset +
 
147
                                OCFS2_XATTR_SIZE(xe->xe_name_len));
 
148
 
 
149
                        ocfs2_swap_extent_list_from_cpu(&xr->xr_list);
 
150
                        ocfs2_swap_xattr_value_root(xr);
 
151
                }
 
152
                ocfs2_swap_xattr_entry(xe);
 
153
        }
 
154
}
 
155
 
 
156
void ocfs2_swap_xattrs_to_cpu(struct ocfs2_xattr_header *xh)
 
157
{
 
158
        ocfs2_swap_xattr_header(xh);
 
159
        ocfs2_swap_xattr_entries_to_cpu(xh);
 
160
}
 
161
 
 
162
void ocfs2_swap_xattrs_from_cpu(struct ocfs2_xattr_header *xh)
 
163
{
 
164
        ocfs2_swap_xattr_entries_from_cpu(xh);
 
165
        ocfs2_swap_xattr_header(xh);
 
166
}
 
167
 
 
168
void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb)
 
169
{
 
170
        if (cpu_is_little_endian)
 
171
                return;
 
172
 
 
173
        ocfs2_swap_xattr_block_header(xb);
 
174
        if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
 
175
                ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header);
 
176
                ocfs2_swap_xattr_entries_to_cpu(&xb->xb_attrs.xb_header);
 
177
        } else {
 
178
                ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root);
 
179
                ocfs2_swap_extent_list_to_cpu(&xb->xb_attrs.xb_root.xt_list);
 
180
        }
 
181
}
 
182
 
 
183
void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb)
 
184
{
 
185
        if (cpu_is_little_endian)
 
186
                return;
 
187
 
 
188
        if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
 
189
                ocfs2_swap_xattr_entries_from_cpu(&xb->xb_attrs.xb_header);
 
190
                ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header);
 
191
        } else {
 
192
                ocfs2_swap_extent_list_from_cpu(&xb->xb_attrs.xb_root.xt_list);
 
193
                ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root);
 
194
        }
 
195
 
 
196
        ocfs2_swap_xattr_block_header(xb);
 
197
}
 
198
 
 
199
errcode_t ocfs2_read_xattr_block(ocfs2_filesys *fs,
 
200
                                 uint64_t blkno,
 
201
                                 char *xb_buf)
 
202
{
 
203
        errcode_t ret = 0;
 
204
        char *blk;
 
205
        struct ocfs2_xattr_block *xb;
 
206
 
 
207
        if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) ||
 
208
            (blkno > fs->fs_blocks))
 
209
                return OCFS2_ET_BAD_BLKNO;
 
210
 
 
211
        ret = ocfs2_malloc_block(fs->fs_io, &blk);
 
212
        if (ret)
 
213
                return ret;
 
214
 
 
215
        ret = io_read_block(fs->fs_io, blkno, 1, blk);
 
216
        if (ret)
 
217
                goto out;
 
218
 
 
219
        xb = (struct ocfs2_xattr_block *)blk;
 
220
 
 
221
        ret = ocfs2_validate_meta_ecc(fs, blk, &xb->xb_check);
 
222
        if (ret)
 
223
                goto out;
 
224
 
 
225
        if (memcmp(xb->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE,
 
226
                strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
 
227
                ret = OCFS2_ET_BAD_XATTR_BLOCK_MAGIC;
 
228
                goto out;
 
229
        }
 
230
 
 
231
        memcpy(xb_buf, blk, fs->fs_blocksize);
 
232
        xb = (struct ocfs2_xattr_block *)xb_buf;
 
233
        ocfs2_swap_xattr_block_to_cpu(xb);
 
234
out:
 
235
        ocfs2_free(&blk);
 
236
        return ret;
 
237
}
 
238
 
 
239
errcode_t ocfs2_write_xattr_block(ocfs2_filesys *fs,
 
240
                                  uint64_t blkno,
 
241
                                  char *xb_buf)
 
242
{
 
243
        errcode_t ret = 0;
 
244
        char *blk;
 
245
        struct ocfs2_xattr_block *xb;
 
246
 
 
247
        if (!(fs->fs_flags & OCFS2_FLAG_RW))
 
248
                return OCFS2_ET_RO_FILESYS;
 
249
 
 
250
        if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) ||
 
251
            (blkno > fs->fs_blocks))
 
252
                return OCFS2_ET_BAD_BLKNO;
 
253
 
 
254
        ret = ocfs2_malloc_block(fs->fs_io, &blk);
 
255
        if (ret)
 
256
                return ret;
 
257
 
 
258
        memcpy(blk, xb_buf, fs->fs_blocksize);
 
259
 
 
260
        xb = (struct ocfs2_xattr_block *)blk;
 
261
        ocfs2_swap_xattr_block_from_cpu(xb);
 
262
 
 
263
        ocfs2_compute_meta_ecc(fs, blk, &xb->xb_check);
 
264
        ret = io_write_block(fs->fs_io, blkno, 1, blk);
 
265
        if (!ret)
 
266
                fs->fs_flags |= OCFS2_FLAG_CHANGED;
 
267
 
 
268
        ocfs2_free(&blk);
 
269
        return ret;
 
270
}
 
271
 
 
272
errcode_t ocfs2_xattr_get_rec(ocfs2_filesys *fs,
 
273
                              struct ocfs2_xattr_block *xb,
 
274
                              uint32_t name_hash,
 
275
                              uint64_t *p_blkno,
 
276
                              uint32_t *e_cpos,
 
277
                              uint32_t *num_clusters)
 
278
{
 
279
        int i;
 
280
        errcode_t ret = 0;
 
281
        char *eb_buf = NULL;
 
282
        struct ocfs2_extent_block *eb;
 
283
        struct ocfs2_extent_rec *rec = NULL;
 
284
        struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
 
285
        uint64_t e_blkno = 0;
 
286
 
 
287
        if (!(xb->xb_flags & OCFS2_XATTR_INDEXED))
 
288
                return OCFS2_ET_INVALID_ARGUMENT;
 
289
 
 
290
        if (el->l_tree_depth) {
 
291
                ret = ocfs2_xattr_find_leaf(fs, xb, name_hash, &eb_buf);
 
292
                if (ret)
 
293
                        goto out;
 
294
 
 
295
                eb = (struct ocfs2_extent_block *) eb_buf;
 
296
                el = &eb->h_list;
 
297
 
 
298
                if (el->l_tree_depth) {
 
299
                        ret = OCFS2_ET_INVALID_ARGUMENT;
 
300
                        goto out;
 
301
                }
 
302
        }
 
303
 
 
304
        for (i = el->l_next_free_rec - 1; i >= 0; i--) {
 
305
                rec = &el->l_recs[i];
 
306
 
 
307
                if (rec->e_cpos <= name_hash) {
 
308
                        e_blkno = rec->e_blkno;
 
309
                        break;
 
310
                }
 
311
        }
 
312
 
 
313
        if (!e_blkno) {
 
314
                ret = OCFS2_ET_INVALID_ARGUMENT;
 
315
                goto out;
 
316
        }
 
317
 
 
318
        *p_blkno = rec->e_blkno;
 
319
        *num_clusters = rec->e_leaf_clusters;
 
320
        if (e_cpos)
 
321
                *e_cpos = rec->e_cpos;
 
322
out:
 
323
        if (eb_buf)
 
324
                ocfs2_free(&eb_buf);
 
325
        return ret;
 
326
}
 
327
 
 
328
uint16_t ocfs2_xattr_value_real_size(uint16_t name_len,
 
329
                                     uint16_t value_len)
 
330
{
 
331
        uint16_t size = 0;
 
332
 
 
333
        if (value_len <= OCFS2_XATTR_INLINE_SIZE)
 
334
                size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len);
 
335
        else
 
336
                size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
 
337
 
 
338
        return size;
 
339
}
 
340
 
 
341
uint16_t ocfs2_xattr_min_offset(struct ocfs2_xattr_header *xh, uint16_t size)
 
342
{
 
343
        int i;
 
344
        uint16_t min_offs = size;
 
345
 
 
346
        for (i = 0 ; i < xh->xh_count; i++) {
 
347
                struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
 
348
                size_t offs = xe->xe_name_offset;
 
349
 
 
350
                if (offs < min_offs)
 
351
                        min_offs = offs;
 
352
        }
 
353
        return min_offs;
 
354
}
 
355
 
 
356
uint16_t ocfs2_xattr_name_value_len(struct ocfs2_xattr_header *xh)
 
357
{
 
358
        int i;
 
359
        uint16_t total_len = 0;
 
360
 
 
361
        for (i = 0 ; i < xh->xh_count; i++) {
 
362
                struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
 
363
 
 
364
                total_len += ocfs2_xattr_value_real_size(xe->xe_name_len,
 
365
                                                         xe->xe_value_size);
 
366
        }
 
367
        return total_len;
 
368
}
 
369
 
 
370
errcode_t ocfs2_read_xattr_bucket(ocfs2_filesys *fs,
 
371
                                  uint64_t blkno,
 
372
                                  char *bucket_buf)
 
373
{
 
374
        errcode_t ret = 0;
 
375
        char *bucket;
 
376
        struct ocfs2_xattr_header *xh;
 
377
        int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs);
 
378
 
 
379
        ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket);
 
380
        if (ret)
 
381
                return ret;
 
382
 
 
383
        ret = io_read_block(fs->fs_io, blkno, blk_per_bucket, bucket);
 
384
        if (ret)
 
385
                goto out;
 
386
 
 
387
        xh = (struct ocfs2_xattr_header *)bucket;
 
388
        if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super))) {
 
389
                ret = ocfs2_block_check_validate(bucket,
 
390
                                                 OCFS2_XATTR_BUCKET_SIZE,
 
391
                                                 &xh->xh_check);
 
392
                if (ret)
 
393
                        goto out;
 
394
        }
 
395
 
 
396
        memcpy(bucket_buf, bucket, OCFS2_XATTR_BUCKET_SIZE);
 
397
        xh = (struct ocfs2_xattr_header *)bucket_buf;
 
398
        ocfs2_swap_xattrs_to_cpu(xh);
 
399
out:
 
400
        ocfs2_free(&bucket);
 
401
        return ret;
 
402
}
 
403
 
 
404
errcode_t ocfs2_write_xattr_bucket(ocfs2_filesys *fs,
 
405
                                   uint64_t blkno,
 
406
                                   char *bucket_buf)
 
407
{
 
408
 
 
409
        errcode_t ret = 0;
 
410
        char *bucket;
 
411
        struct ocfs2_xattr_header *xh;
 
412
        int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs);
 
413
 
 
414
        if (!(fs->fs_flags & OCFS2_FLAG_RW))
 
415
                return OCFS2_ET_RO_FILESYS;
 
416
 
 
417
        if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) ||
 
418
            (blkno > fs->fs_blocks))
 
419
                return OCFS2_ET_BAD_BLKNO;
 
420
 
 
421
        ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket);
 
422
        if (ret)
 
423
                return ret;
 
424
 
 
425
        memcpy(bucket, bucket_buf, OCFS2_XATTR_BUCKET_SIZE);
 
426
 
 
427
        xh = (struct ocfs2_xattr_header *)bucket;
 
428
        ocfs2_swap_xattrs_from_cpu(xh);
 
429
 
 
430
        if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super)))
 
431
                ocfs2_block_check_compute(bucket, OCFS2_XATTR_BUCKET_SIZE,
 
432
                                          &xh->xh_check);
 
433
 
 
434
        ret = io_write_block(fs->fs_io, blkno, blk_per_bucket, bucket);
 
435
        if (!ret)
 
436
                fs->fs_flags |= OCFS2_FLAG_CHANGED;
 
437
 
 
438
        ocfs2_free(&bucket);
 
439
        return ret;
 
440
}