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_attr(ext2_filsys fs, blk_t block, void *buf) 64 { 65 errcode_t retval; 66 67 retval = io_channel_read_blk(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_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf) 77 { 78 errcode_t retval; 79 char *write_buf; 80 char *buf = NULL; 81 82 #ifdef WORDS_BIGENDIAN 83 retval = ext2fs_get_mem(fs->blocksize, &buf); 84 if (retval) 85 return retval; 86 write_buf = buf; 87 ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1); 88 #else 89 write_buf = (char *) inbuf; 90 #endif 91 retval = io_channel_write_blk(fs->io, block, 1, write_buf); 92 if (buf) 93 ext2fs_free_mem(&buf); 94 if (!retval) 95 ext2fs_mark_changed(fs); 96 return retval; 97 } 98 99 /* 100 * This function adjusts the reference count of the EA block. 101 */ 102 errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, 103 char *block_buf, int adjust, 104 __u32 *newcount) 105 { 106 errcode_t retval; 107 struct ext2_ext_attr_header *header; 108 char *buf = 0; 109 110 if ((blk >= fs->super->s_blocks_count) || 111 (blk < fs->super->s_first_data_block)) 112 return EXT2_ET_BAD_EA_BLOCK_NUM; 113 114 if (!block_buf) { 115 retval = ext2fs_get_mem(fs->blocksize, &buf); 116 if (retval) 117 return retval; 118 block_buf = buf; 119 } 120 121 retval = ext2fs_read_ext_attr(fs, blk, block_buf); 122 if (retval) 123 goto errout; 124 125 header = (struct ext2_ext_attr_header *) block_buf; 126 header->h_refcount += adjust; 127 if (newcount) 128 *newcount = header->h_refcount; 129 130 retval = ext2fs_write_ext_attr(fs, blk, block_buf); 131 if (retval) 132 goto errout; 133 134 errout: 135 if (buf) 136 ext2fs_free_mem(&buf); 137 return retval; 138 } 139