1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
/*
* ext_attr.c --- extended attribute blocks
*
* Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*
* Copyright (C) 2002 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Library
* General Public License, version 2.
* %End-Header%
*/
#include "config.h"
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2_ext_attr.h"
#include "ext2fs.h"
#define NAME_HASH_SHIFT 5
#define VALUE_HASH_SHIFT 16
/*
* ext2_xattr_hash_entry()
*
* Compute the hash of an extended attribute.
*/
__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
{
__u32 hash = 0;
char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry);
int n;
for (n = 0; n < entry->e_name_len; n++) {
hash = (hash << NAME_HASH_SHIFT) ^
(hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
*name++;
}
/* The hash needs to be calculated on the data in little-endian. */
if (entry->e_value_block == 0 && entry->e_value_size != 0) {
__u32 *value = (__u32 *)data;
for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
EXT2_EXT_ATTR_PAD_BITS; n; n--) {
hash = (hash << VALUE_HASH_SHIFT) ^
(hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
ext2fs_le32_to_cpu(*value++);
}
}
return hash;
}
#undef NAME_HASH_SHIFT
#undef VALUE_HASH_SHIFT
errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
{
errcode_t retval;
retval = io_channel_read_blk64(fs->io, block, 1, buf);
if (retval)
return retval;
#ifdef WORDS_BIGENDIAN
ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
#endif
return 0;
}
errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
{
return ext2fs_read_ext_attr2(fs, block, buf);
}
errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
{
errcode_t retval;
char *write_buf;
#ifdef WORDS_BIGENDIAN
char *buf = NULL;
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
write_buf = buf;
ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
#else
write_buf = (char *) inbuf;
#endif
retval = io_channel_write_blk64(fs->io, block, 1, write_buf);
#ifdef WORDS_BIGENDIAN
ext2fs_free_mem(&buf);
#endif
if (!retval)
ext2fs_mark_changed(fs);
return retval;
}
errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
{
return ext2fs_write_ext_attr2(fs, block, inbuf);
}
/*
* This function adjusts the reference count of the EA block.
*/
errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
char *block_buf, int adjust,
__u32 *newcount)
{
errcode_t retval;
struct ext2_ext_attr_header *header;
char *buf = 0;
if ((blk >= ext2fs_blocks_count(fs->super)) ||
(blk < fs->super->s_first_data_block))
return EXT2_ET_BAD_EA_BLOCK_NUM;
if (!block_buf) {
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
block_buf = buf;
}
retval = ext2fs_read_ext_attr2(fs, blk, block_buf);
if (retval)
goto errout;
header = (struct ext2_ext_attr_header *) block_buf;
header->h_refcount += adjust;
if (newcount)
*newcount = header->h_refcount;
retval = ext2fs_write_ext_attr2(fs, blk, block_buf);
if (retval)
goto errout;
errout:
if (buf)
ext2fs_free_mem(&buf);
return retval;
}
errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
char *block_buf, int adjust,
__u32 *newcount)
{
return ext2fs_adjust_ea_refcount(fs, blk, block_buf, adjust, newcount);
}
|