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_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