patch file systems with the acl checks
[lunaix-os.git] / lunaix-os / kernel / fs / ext2 / file.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/mm/page.h>
3 #include "ext2.h"
4
5 #define blkpos(e_sb, fpos) ((fpos) / (e_sb)->block_size)
6 #define blkoff(e_sb, fpos) ((fpos) % (e_sb)->block_size)
7
8 int
9 ext2_open_inode(struct v_inode* inode, struct v_file* file)
10 {
11     int errno = 0;
12     struct ext2_file* e_file;
13
14     e_file = valloc(sizeof(*e_file));
15     e_file->b_ino = EXT2_INO(inode);
16     
17     file->data = e_file;
18
19     if (check_directory_node(inode)) {
20         errno = ext2dr_open(inode, file);
21         goto done;
22     }
23
24     // XXX anything for regular file?
25
26 done:
27     if (!errno) {
28         return 0;
29     }
30     
31     vfree(e_file);
32     file->data = NULL;
33     return errno;
34 }
35
36 int
37 ext2_close_inode(struct v_file* file)
38 {
39     ext2ino_update(file->inode);
40
41     if (check_directory_node(file->inode)) {
42         ext2dr_close(file->inode, file);
43     }
44
45     vfree(file->data);
46     file->data = NULL;
47     return 0;
48 }
49
50 int
51 ext2_sync_inode(struct v_inode* inode)
52 {
53     // TODO
54     // a modification to an inode may involves multiple
55     //  blkbuf scattering among different groups.
56     // For now, we just sync everything, until we figure out
57     //  a way to track each dirtied blkbuf w.r.t inode
58     ext2ino_resizing(inode, inode->fsize);
59     blkbuf_syncall(inode->sb->blks, false);
60
61     return 0;
62 }
63
64 int
65 ext2_file_sync(struct v_file* file)
66 {
67     return ext2_sync_inode(file->inode);
68 }
69
70 int
71 ext2_seek_inode(struct v_file* file, size_t offset)
72 {
73     if (check_directory_node(file->inode)) {
74         return ext2dr_seek(file, offset);
75     }
76
77     // nothing to do, seek on file pos handled by vfs
78     return 0;
79 }
80
81 int
82 ext2_inode_read(struct v_inode *inode, 
83                 void *buffer, size_t len, size_t fpos)
84 {
85     struct ext2_sbinfo* e_sb;
86     struct ext2_iterator iter;
87     struct ext2b_inode* b_ino;
88     struct ext2_inode* e_ino;
89     unsigned int off;
90     unsigned int end;
91     unsigned int sz = 0, blksz, movsz;
92     
93     e_sb  = EXT2_SB(inode->sb);
94     e_ino = EXT2_INO(inode);
95     b_ino = e_ino->ino;
96     blksz = e_sb->block_size;
97     end = fpos + len;
98
99     ext2db_itbegin(&iter, inode);
100     ext2db_itffw(&iter, fpos / blksz);
101
102     while (fpos < end && ext2db_itnext(&iter)) {
103         off = fpos % blksz;
104         movsz = MIN(end - fpos, blksz - off);
105         
106         memcpy(buffer, offset(iter.data, off), movsz);
107
108         buffer = offset(buffer, movsz);
109         fpos += movsz;
110         sz += movsz;
111     }
112
113     ext2db_itend(&iter);
114     return itstate_sel(&iter, MIN(sz, e_ino->isize));
115 }
116
117 int
118 ext2_inode_read_page(struct v_inode *inode, void *buffer, size_t fpos)
119 {
120     struct ext2_sbinfo* e_sb;
121     struct ext2_iterator iter;
122     struct ext2_inode*  e_ino;
123     struct ext2b_inode* b_ino;
124     unsigned int blk_start, n, 
125                  transfer_sz, total_sz = 0;
126
127     assert(!va_offset(fpos));
128
129     e_sb = EXT2_SB(inode->sb);
130     e_ino = EXT2_INO(inode);
131     b_ino = e_ino->ino;
132     
133     blk_start = fpos / e_sb->block_size;
134     n = PAGE_SIZE / e_sb->block_size;
135     transfer_sz = MIN(PAGE_SIZE, e_sb->block_size);
136
137     ext2db_itbegin(&iter, inode);
138     ext2db_itffw(&iter, blk_start);
139
140     while (n-- && ext2db_itnext(&iter)) 
141     {
142         memcpy(buffer, iter.data, transfer_sz);
143         buffer = offset(buffer, transfer_sz);
144         total_sz += transfer_sz;
145     }
146     
147     ext2db_itend(&iter);
148     return itstate_sel(&iter, MIN(total_sz, e_ino->isize));
149 }
150
151 int
152 ext2_inode_write(struct v_inode *inode, 
153                  void *buffer, size_t len, size_t fpos)
154 {
155     int errno;
156     unsigned int acc, blk_off, end, size;
157     struct ext2_sbinfo* e_sb;
158     bbuf_t buf;
159
160     e_sb  = EXT2_SB(inode->sb);
161
162     acc = 0;
163     end = fpos + len;
164     while (fpos < end) {
165         errno = ext2db_acquire(inode, blkpos(e_sb, fpos), &buf);
166         if (errno) {
167             return errno;
168         }
169
170         blk_off = blkoff(e_sb, fpos);
171         size = e_sb->block_size - blk_off;
172
173         memcpy(offset(blkbuf_data(buf), blk_off), buffer, size);
174         buffer = offset(buffer, size);
175
176         fsblock_dirty(buf);
177         fsblock_put(buf);
178
179         fpos += size;
180         acc += size;
181     }
182
183     return (int)acc;
184 }
185
186 int
187 ext2_inode_write_page(struct v_inode *inode, void *buffer, size_t fpos)
188 {
189     return ext2_inode_write(inode, buffer, PAGE_SIZE, fpos);
190 }
191
192 #define SYMLNK_INPLACE \
193         sizeof(((struct ext2b_inode*)0)->i_block_arr)
194
195 static inline int
196 __readlink_symlink(struct v_inode *this, char* path)
197 {
198     size_t size;
199     char* link = NULL;
200     int errno;
201     bbuf_t buf;
202     struct ext2_inode* e_ino;
203     
204     e_ino = EXT2_INO(this);
205     size  = e_ino->isize;
206     if (size <= SYMLNK_INPLACE) {
207         link = (char*) e_ino->ino->i_block_arr;
208         strncpy(path, link, size);
209     }
210     else {
211         buf = ext2db_get(this, 0);
212         if (blkbuf_errbuf(buf)) {
213             return EIO;
214         }
215
216         link = blkbuf_data(buf);
217         strncpy(path, link, size);
218
219         fsblock_put(buf);
220     }
221
222     return 0;
223 }
224
225 int
226 ext2_get_symlink(struct v_inode *this, const char **path_out)
227 {
228     int errno;
229     size_t size;
230     char* symlink;
231     struct ext2_inode* e_ino;
232     
233     e_ino = EXT2_INO(this);
234     size  = e_ino->isize;
235
236     if (!size) {
237         return ENOENT;
238     }
239
240     if (!e_ino->symlink) {
241         symlink = valloc(size);
242         if ((errno = __readlink_symlink(this, symlink))) {
243             vfree(symlink);
244             return errno;
245         }
246
247         e_ino->symlink = symlink;
248     }
249
250     *path_out = e_ino->symlink;
251
252     return size;
253 }
254
255 int
256 ext2_set_symlink(struct v_inode *this, const char *target)
257 {
258     int errno = 0;
259     bbuf_t buf = NULL;
260     char* link;
261     size_t size, new_len;
262     struct ext2_inode* e_ino;
263     
264     e_ino = EXT2_INO(this);
265     size = e_ino->isize;
266     new_len = strlen(target);
267
268     if (new_len > this->sb->blksize) {
269         return ENAMETOOLONG;
270     }
271
272     if (size != new_len) {
273         vfree_safe(e_ino->symlink);
274         e_ino->symlink = valloc(new_len);
275     }
276     
277     link = (char*) e_ino->ino->i_block_arr;
278
279     // if new size is shrinked to inplace range
280     if (size > SYMLNK_INPLACE && new_len <= SYMLNK_INPLACE) 
281     {
282         ext2db_free_pos(this, 0);
283     }
284     
285     // if new size is too big to fit inpalce
286     if (new_len > SYMLNK_INPLACE) {
287
288         // repurpose the i_block array back to normal
289         if (size <= SYMLNK_INPLACE) {
290             memset(link, 0, SYMLNK_INPLACE);
291         }
292
293         errno = ext2db_acquire(this, 0, &buf);
294         if (errno) {
295             goto done;
296         }
297
298         link = blkbuf_data(buf);
299     }
300
301     strncpy(e_ino->symlink, target, new_len);
302     strncpy(link, target, new_len);
303
304     ext2ino_update(this);
305     ext2ino_resizing(this, new_len);
306
307     if (buf) {
308         fsblock_put(buf);
309     }
310
311 done:
312     return errno;
313 }