Home | History | Annotate | Download | only in ext2fs
      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