• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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   */
ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry * entry,void * data)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  
ext2fs_read_ext_attr(ext2_filsys fs,blk_t block,void * buf)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  
ext2fs_write_ext_attr(ext2_filsys fs,blk_t block,void * inbuf)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   */
ext2fs_adjust_ea_refcount(ext2_filsys fs,blk_t blk,char * block_buf,int adjust,__u32 * newcount)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