blob: 1889824c359ed85fd1f973885fc72e2ebc49a795 [file] [log] [blame]
Theodore Ts'o342d8472001-07-02 11:54:09 -04001/*
2 * ext_attr.c --- extended attribute blocks
Theodore Ts'oefc6f622008-08-27 23:07:54 -04003 *
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04004 * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
5 *
6 * Copyright (C) 2002 Theodore Ts'o.
Theodore Ts'o342d8472001-07-02 11:54:09 -04007 *
8 * %Begin-Header%
Theodore Ts'o543547a2010-05-17 21:31:56 -04009 * This file may be redistributed under the terms of the GNU Library
10 * General Public License, version 2.
Theodore Ts'o342d8472001-07-02 11:54:09 -040011 * %End-Header%
12 */
13
Theodore Ts'od1154eb2011-09-18 17:34:37 -040014#include "config.h"
Theodore Ts'o342d8472001-07-02 11:54:09 -040015#include <stdio.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <string.h>
20#include <time.h>
21
22#include "ext2_fs.h"
23#include "ext2_ext_attr.h"
24
25#include "ext2fs.h"
26
Andreas Dilgerfefaef32008-02-02 01:16:32 -070027#define NAME_HASH_SHIFT 5
28#define VALUE_HASH_SHIFT 16
29
30/*
31 * ext2_xattr_hash_entry()
32 *
33 * Compute the hash of an extended attribute.
34 */
35__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
36{
37 __u32 hash = 0;
38 char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry);
39 int n;
40
41 for (n = 0; n < entry->e_name_len; n++) {
42 hash = (hash << NAME_HASH_SHIFT) ^
43 (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
44 *name++;
45 }
46
47 /* The hash needs to be calculated on the data in little-endian. */
48 if (entry->e_value_block == 0 && entry->e_value_size != 0) {
49 __u32 *value = (__u32 *)data;
50 for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
51 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
52 hash = (hash << VALUE_HASH_SHIFT) ^
53 (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
54 ext2fs_le32_to_cpu(*value++);
55 }
56 }
57
58 return hash;
59}
60
61#undef NAME_HASH_SHIFT
62#undef VALUE_HASH_SHIFT
63
Jose R. Santosb91f14b2009-06-01 16:15:40 -040064errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
Theodore Ts'o342d8472001-07-02 11:54:09 -040065{
66 errcode_t retval;
Theodore Ts'o342d8472001-07-02 11:54:09 -040067
Jose R. Santosb91f14b2009-06-01 16:15:40 -040068 retval = io_channel_read_blk64(fs->io, block, 1, buf);
Theodore Ts'o342d8472001-07-02 11:54:09 -040069 if (retval)
70 return retval;
Theodore Ts'o126a2912007-08-11 01:56:48 -040071#ifdef WORDS_BIGENDIAN
72 ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
Theodore Ts'o342d8472001-07-02 11:54:09 -040073#endif
74 return 0;
75}
76
Jose R. Santosb91f14b2009-06-01 16:15:40 -040077errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
78{
79 return ext2fs_read_ext_attr2(fs, block, buf);
80}
81
82errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
Theodore Ts'o342d8472001-07-02 11:54:09 -040083{
84 errcode_t retval;
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -050085 char *write_buf;
Eric Sandeend0f196d2011-09-16 15:49:20 -050086#ifdef WORDS_BIGENDIAN
Theodore Ts'o342d8472001-07-02 11:54:09 -040087 char *buf = NULL;
Theodore Ts'o342d8472001-07-02 11:54:09 -040088
Theodore Ts'o126a2912007-08-11 01:56:48 -040089 retval = ext2fs_get_mem(fs->blocksize, &buf);
90 if (retval)
91 return retval;
92 write_buf = buf;
93 ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
94#else
95 write_buf = (char *) inbuf;
Theodore Ts'o342d8472001-07-02 11:54:09 -040096#endif
Jose R. Santosb91f14b2009-06-01 16:15:40 -040097 retval = io_channel_write_blk64(fs->io, block, 1, write_buf);
Eric Sandeend0f196d2011-09-16 15:49:20 -050098#ifdef WORDS_BIGENDIAN
99 ext2fs_free_mem(&buf);
100#endif
Theodore Ts'o241f7d22001-07-20 14:17:19 -0400101 if (!retval)
102 ext2fs_mark_changed(fs);
Theodore Ts'o342d8472001-07-02 11:54:09 -0400103 return retval;
104}
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400105
Jose R. Santosb91f14b2009-06-01 16:15:40 -0400106errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
107{
108 return ext2fs_write_ext_attr2(fs, block, inbuf);
109}
110
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400111/*
112 * This function adjusts the reference count of the EA block.
113 */
Jose R. Santosb91f14b2009-06-01 16:15:40 -0400114errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400115 char *block_buf, int adjust,
116 __u32 *newcount)
117{
118 errcode_t retval;
119 struct ext2_ext_attr_header *header;
120 char *buf = 0;
121
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400122 if ((blk >= ext2fs_blocks_count(fs->super)) ||
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400123 (blk < fs->super->s_first_data_block))
124 return EXT2_ET_BAD_EA_BLOCK_NUM;
125
126 if (!block_buf) {
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400127 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400128 if (retval)
129 return retval;
130 block_buf = buf;
131 }
132
Jose R. Santosb91f14b2009-06-01 16:15:40 -0400133 retval = ext2fs_read_ext_attr2(fs, blk, block_buf);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400134 if (retval)
135 goto errout;
136
137 header = (struct ext2_ext_attr_header *) block_buf;
138 header->h_refcount += adjust;
139 if (newcount)
140 *newcount = header->h_refcount;
141
Jose R. Santosb91f14b2009-06-01 16:15:40 -0400142 retval = ext2fs_write_ext_attr2(fs, blk, block_buf);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400143 if (retval)
144 goto errout;
145
146errout:
147 if (buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400148 ext2fs_free_mem(&buf);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400149 return retval;
150}
Jose R. Santosb91f14b2009-06-01 16:15:40 -0400151
152errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
153 char *block_buf, int adjust,
154 __u32 *newcount)
155{
156 return ext2fs_adjust_ea_refcount(fs, blk, block_buf, adjust, newcount);
157}