1 /* 2 * ext_attr.c --- extended attribute blocks 3 * 4 * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher (at) 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 Library 10 * General Public License, version 2. 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 63 errcode_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 76 errcode_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 81 errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf) 82 { 83 errcode_t retval; 84 char *write_buf; 85 #ifdef WORDS_BIGENDIAN 86 char *buf = NULL; 87 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 #ifdef WORDS_BIGENDIAN 98 ext2fs_free_mem(&buf); 99 #endif 100 if (!retval) 101 ext2fs_mark_changed(fs); 102 return retval; 103 } 104 105 errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf) 106 { 107 return ext2fs_write_ext_attr2(fs, block, inbuf); 108 } 109 110 /* 111 * This function adjusts the reference count of the EA block. 112 */ 113 errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk, 114 char *block_buf, int adjust, 115 __u32 *newcount) 116 { 117 errcode_t retval; 118 struct ext2_ext_attr_header *header; 119 char *buf = 0; 120 121 if ((blk >= ext2fs_blocks_count(fs->super)) || 122 (blk < fs->super->s_first_data_block)) 123 return EXT2_ET_BAD_EA_BLOCK_NUM; 124 125 if (!block_buf) { 126 retval = ext2fs_get_mem(fs->blocksize, &buf); 127 if (retval) 128 return retval; 129 block_buf = buf; 130 } 131 132 retval = ext2fs_read_ext_attr2(fs, blk, block_buf); 133 if (retval) 134 goto errout; 135 136 header = (struct ext2_ext_attr_header *) block_buf; 137 header->h_refcount += adjust; 138 if (newcount) 139 *newcount = header->h_refcount; 140 141 retval = ext2fs_write_ext_attr2(fs, blk, block_buf); 142 if (retval) 143 goto errout; 144 145 errout: 146 if (buf) 147 ext2fs_free_mem(&buf); 148 return retval; 149 } 150 151 errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, 152 char *block_buf, int adjust, 153 __u32 *newcount) 154 { 155 return ext2fs_adjust_ea_refcount(fs, blk, block_buf, adjust, newcount); 156 } 157