Whamcloud - gitweb
libext2fs: handle inline data in dir iterator function
[tools/e2fsprogs.git] / lib / ext2fs / inline_data.c
1 /*
2  * inline_data.c --- data in inode
3  *
4  * Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com>
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU library
8  * General Public License, version 2.
9  * %End-Header%
10  */
11
12 #include "config.h"
13 #include <stdio.h>
14 #include <time.h>
15
16 #include "ext2_fs.h"
17 #include "ext2_ext_attr.h"
18
19 #include "ext2fs.h"
20 #include "ext2fsP.h"
21
22 struct ext2_inline_data {
23         ext2_filsys fs;
24         ext2_ino_t ino;
25         size_t ea_size; /* the size of inline data in ea area */
26         void *ea_data;
27 };
28
29 static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data)
30 {
31         struct ext2_xattr_handle *handle;
32         errcode_t retval;
33
34         retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
35         if (retval)
36                 return retval;
37
38         retval = ext2fs_xattrs_read(handle);
39         if (retval)
40                 goto err;
41
42         retval = ext2fs_xattr_set(handle, "system.data",
43                                   data->ea_data, data->ea_size);
44         if (retval)
45                 goto err;
46
47         retval = ext2fs_xattrs_write(handle);
48
49 err:
50         (void) ext2fs_xattrs_close(&handle);
51         return retval;
52 }
53
54 static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data)
55 {
56         struct ext2_xattr_handle *handle;
57         errcode_t retval;
58
59         data->ea_size = 0;
60         data->ea_data = 0;
61
62         retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
63         if (retval)
64                 return retval;
65
66         retval = ext2fs_xattrs_read(handle);
67         if (retval)
68                 goto err;
69
70         retval = ext2fs_xattr_get(handle, "system.data",
71                                   (void **)&data->ea_data, &data->ea_size);
72         if (retval)
73                 goto err;
74
75 err:
76         (void) ext2fs_xattrs_close(&handle);
77         return retval;
78 }
79
80
81 int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
82                                    void *priv_data)
83 {
84         struct dir_context *ctx;
85         struct ext2_inode inode;
86         struct ext2_dir_entry dirent;
87         struct ext2_inline_data data;
88         int ret = BLOCK_ABORT;
89         e2_blkcnt_t blockcnt = 0;
90
91         ctx = (struct dir_context *)priv_data;
92
93         ctx->errcode = ext2fs_read_inode(fs, ino, &inode);
94         if (ctx->errcode)
95                 goto out;
96
97         if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) {
98                 ctx->errcode = EXT2_ET_NO_INLINE_DATA;
99                 goto out;
100         }
101
102         if (!LINUX_S_ISDIR(inode.i_mode)) {
103                 ctx->errcode = EXT2_ET_NO_DIRECTORY;
104                 goto out;
105         }
106         ret = 0;
107
108         /* we first check '.' and '..' dir */
109         dirent.inode = ino;
110         dirent.name_len = 1;
111         ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
112         dirent.name[0] = '.';
113         dirent.name[1] = '\0';
114         ctx->buf = (char *)&dirent;
115         ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
116         ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
117         if (ret & BLOCK_ABORT)
118                 goto out;
119
120         dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
121         dirent.name_len = 2;
122         ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
123         dirent.name[0] = '.';
124         dirent.name[1] = '.';
125         dirent.name[2] = '\0';
126         ctx->buf = (char *)&dirent;
127         ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
128         ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
129         if (ret & BLOCK_INLINE_DATA_CHANGED) {
130                 errcode_t err;
131
132                 inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode);
133                 err = ext2fs_write_inode(fs, ino, &inode);
134                 if (err)
135                         goto out;
136                 ret &= ~BLOCK_INLINE_DATA_CHANGED;
137         }
138         if (ret & BLOCK_ABORT)
139                 goto out;
140
141         ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
142         ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
143 #ifdef WORDS_BIGENDIAN
144         ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
145         if (ctx->errcode) {
146                 ret |= BLOCK_ABORT;
147                 goto out;
148         }
149 #endif
150         ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
151         if (ret & BLOCK_INLINE_DATA_CHANGED) {
152 #ifdef WORDS_BIGENDIAN
153                 ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
154                                                        ctx->buflen, 0);
155                 if (ctx->errcode) {
156                         ret |= BLOCK_ABORT;
157                         goto out;
158                 }
159 #endif
160                 ctx->errcode = ext2fs_write_inode(fs, ino, &inode);
161                 if (ctx->errcode)
162                         ret |= BLOCK_ABORT;
163                 ret &= ~BLOCK_INLINE_DATA_CHANGED;
164         }
165         if (ret & BLOCK_ABORT)
166                 goto out;
167
168         data.fs = fs;
169         data.ino = ino;
170         ctx->errcode = ext2fs_inline_data_ea_get(&data);
171         if (ctx->errcode) {
172                 ret |= BLOCK_ABORT;
173                 goto out;
174         }
175         if (data.ea_size <= 0)
176                 goto out;
177
178         ctx->buf = data.ea_data;
179         ctx->buflen = data.ea_size;
180 #ifdef WORDS_BIGENDIAN
181         ctx.errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
182         if (ctx.errcode) {
183                 ret |= BLOCK_ABORT;
184                 goto out;
185         }
186 #endif
187
188         ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
189         if (ret & BLOCK_INLINE_DATA_CHANGED) {
190 #ifdef WORDS_BIGENDIAN
191                 ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
192                                                       ctx->buflen, 0);
193                 if (ctx->errcode) {
194                         ret |= BLOCK_ABORT;
195                         goto out1;
196                 }
197 #endif
198                 ctx->errcode = ext2fs_inline_data_ea_set(&data);
199                 if (ctx->errcode)
200                         ret |= BLOCK_ABORT;
201         }
202
203 out1:
204         ext2fs_free_mem(&data.ea_data);
205         ctx->buf = 0;
206
207 out:
208         ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED);
209         return ret;
210 }