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