1 /**
2 * dir.c
3 *
4 * Many parts of codes are copied from Linux kernel/fs/f2fs.
5 *
6 * Copyright (C) 2015 Huawei Ltd.
7 * Witten by:
8 * Hou Pengyang <houpengyang@huawei.com>
9 * Liu Shuoran <liushuoran@huawei.com>
10 * Jaegeuk Kim <jaegeuk@kernel.org>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16 #include "fsck.h"
17 #include "node.h"
18
room_for_filename(const u8 * bitmap,int slots,int max_slots)19 static int room_for_filename(const u8 *bitmap, int slots, int max_slots)
20 {
21 int bit_start = 0;
22 int zero_start, zero_end;
23 next:
24 zero_start = find_next_zero_bit_le(bitmap, max_slots, bit_start);
25 if (zero_start >= max_slots)
26 return max_slots;
27
28 zero_end = find_next_bit_le(bitmap, max_slots, zero_start + 1);
29
30 if (zero_end - zero_start >= slots)
31 return zero_start;
32 bit_start = zero_end;
33 goto next;
34
35 }
36
make_dentry_ptr(struct f2fs_dentry_ptr * d,void * src,int type)37 static void make_dentry_ptr(struct f2fs_dentry_ptr *d, void *src, int type)
38 {
39 if (type == 1) {
40 struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src;
41 d->max = NR_DENTRY_IN_BLOCK;
42 d->bitmap = t->dentry_bitmap;
43 d->dentry = t->dentry;
44 d->filename = t->filename;
45 } else {
46 struct f2fs_inline_dentry *t = (struct f2fs_inline_dentry *)src;
47 d->max = NR_INLINE_DENTRY;
48 d->bitmap = t->dentry_bitmap;
49 d->dentry = t->dentry;
50 d->filename = t->filename;
51 }
52 }
53
find_target_dentry(const u8 * name,unsigned int len,f2fs_hash_t namehash,int * max_slots,struct f2fs_dentry_ptr * d)54 static struct f2fs_dir_entry *find_target_dentry(const u8 *name,
55 unsigned int len, f2fs_hash_t namehash, int *max_slots,
56 struct f2fs_dentry_ptr *d)
57 {
58 struct f2fs_dir_entry *de;
59 unsigned long bit_pos = 0;
60 int max_len = 0;
61
62 if (max_slots)
63 *max_slots = 0;
64 while (bit_pos < d->max) {
65 if (!test_bit_le(bit_pos, d->bitmap)) {
66 bit_pos++;
67 max_len++;
68 continue;
69 }
70
71 de = &d->dentry[bit_pos];
72 if (le16_to_cpu(de->name_len) == len &&
73 de->hash_code == namehash &&
74 !memcmp(d->filename[bit_pos], name, len)) {
75 goto found;
76 }
77
78 if (max_slots && max_len > *max_slots)
79 *max_slots = max_len;
80 max_len = 0;
81 bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
82 }
83 de = NULL;
84 found:
85 if (max_slots && max_len > *max_slots)
86 *max_slots = max_len;
87 return de;
88 }
89
find_in_block(void * block,const u8 * name,int len,f2fs_hash_t namehash,int * max_slots)90 static struct f2fs_dir_entry *find_in_block(void *block,
91 const u8 *name, int len, f2fs_hash_t namehash,
92 int *max_slots)
93 {
94 struct f2fs_dentry_ptr d;
95
96 make_dentry_ptr(&d, block, 1);
97 return find_target_dentry(name, len, namehash, max_slots, &d);
98 }
99
find_in_level(struct f2fs_sb_info * sbi,struct f2fs_node * dir,unsigned int level,struct dentry * de)100 static int find_in_level(struct f2fs_sb_info *sbi,struct f2fs_node *dir,
101 unsigned int level, struct dentry *de)
102 {
103 unsigned int nbucket, nblock;
104 unsigned int bidx, end_block;
105 struct f2fs_dir_entry *dentry = NULL;
106 struct dnode_of_data dn = {0};
107 void *dentry_blk;
108 int max_slots = 214;
109 nid_t ino = le32_to_cpu(dir->footer.ino);
110 f2fs_hash_t namehash;
111 unsigned int dir_level = dir->i.i_dir_level;
112 int ret = 0;
113
114 namehash = f2fs_dentry_hash(de->name, de->len);
115
116 nbucket = dir_buckets(level, dir_level);
117 nblock = bucket_blocks(level);
118
119 bidx = dir_block_index(level, dir_level, le32_to_cpu(namehash) % nbucket);
120 end_block = bidx + nblock;
121
122 dentry_blk = calloc(BLOCK_SZ, 1);
123 ASSERT(dentry_blk);
124
125 for (; bidx < end_block; bidx++) {
126
127 /* Firstly, we should know direct node of target data blk */
128 if (dn.node_blk && dn.node_blk != dn.inode_blk)
129 free(dn.node_blk);
130
131 set_new_dnode(&dn, dir, NULL, ino);
132 get_dnode_of_data(sbi, &dn, bidx, LOOKUP_NODE);
133 if (dn.data_blkaddr == NULL_ADDR)
134 continue;
135
136 ret = dev_read_block(dentry_blk, dn.data_blkaddr);
137 ASSERT(ret >= 0);
138
139 dentry = find_in_block(dentry_blk, de->name, de->len,
140 namehash, &max_slots);
141 if (dentry) {
142 ret = 1;
143 de->ino = le32_to_cpu(dentry->ino);
144 break;
145 }
146 }
147
148 if (dn.node_blk && dn.node_blk != dn.inode_blk)
149 free(dn.node_blk);
150 free(dentry_blk);
151
152 return ret;
153 }
154
f2fs_find_entry(struct f2fs_sb_info * sbi,struct f2fs_node * dir,struct dentry * de)155 static int f2fs_find_entry(struct f2fs_sb_info *sbi,
156 struct f2fs_node *dir, struct dentry *de)
157 {
158 unsigned int max_depth;
159 unsigned int level;
160
161 max_depth = le32_to_cpu(dir->i.i_current_depth);
162 for (level = 0; level < max_depth; level ++) {
163 if (find_in_level(sbi, dir, level, de))
164 return 1;
165 }
166 return 0;
167 }
168
f2fs_update_dentry(nid_t ino,int file_type,struct f2fs_dentry_ptr * d,const unsigned char * name,int len,f2fs_hash_t name_hash,unsigned int bit_pos)169 static void f2fs_update_dentry(nid_t ino, int file_type,
170 struct f2fs_dentry_ptr *d,
171 const unsigned char *name, int len, f2fs_hash_t name_hash,
172 unsigned int bit_pos)
173 {
174 struct f2fs_dir_entry *de;
175 int slots = GET_DENTRY_SLOTS(len);
176 int i;
177
178 de = &d->dentry[bit_pos];
179 de->name_len = cpu_to_le16(len);
180 de->hash_code = name_hash;
181 memcpy(d->filename[bit_pos], name, len);
182 d->filename[bit_pos][len] = 0;
183 de->ino = cpu_to_le32(ino);
184 de->file_type = file_type;
185 for (i = 0; i < slots; i++)
186 test_and_set_bit_le(bit_pos + i, d->bitmap);
187 }
188
189 /*
190 * f2fs_add_link - Add a new file(dir) to parent dir.
191 */
f2fs_add_link(struct f2fs_sb_info * sbi,struct f2fs_node * parent,const unsigned char * name,int name_len,nid_t ino,int file_type,block_t p_blkaddr,int inc_link)192 static int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent,
193 const unsigned char *name, int name_len, nid_t ino,
194 int file_type, block_t p_blkaddr, int inc_link)
195 {
196 int level = 0, current_depth, bit_pos;
197 int nbucket, nblock, bidx, block;
198 int slots = GET_DENTRY_SLOTS(name_len);
199 f2fs_hash_t dentry_hash = f2fs_dentry_hash(name, name_len);
200 struct f2fs_dentry_block *dentry_blk;
201 struct f2fs_dentry_ptr d;
202 struct dnode_of_data dn = {0};
203 nid_t pino = le32_to_cpu(parent->footer.ino);
204 unsigned int dir_level = parent->i.i_dir_level;
205 int ret;
206
207 if (parent == NULL)
208 return -EINVAL;
209
210 if (!pino) {
211 ERR_MSG("Wrong parent ino:%d \n", pino);
212 return -EINVAL;
213 }
214
215 dentry_blk = calloc(BLOCK_SZ, 1);
216 ASSERT(dentry_blk);
217
218 current_depth = le32_to_cpu(parent->i.i_current_depth);
219 start:
220 if (current_depth == MAX_DIR_HASH_DEPTH) {
221 free(dentry_blk);
222 ERR_MSG("\tError: MAX_DIR_HASH\n");
223 return -ENOSPC;
224 }
225
226 /* Need a new dentry block */
227 if (level == current_depth)
228 ++current_depth;
229
230 nbucket = dir_buckets(level, dir_level);
231 nblock = bucket_blocks(level);
232 bidx = dir_block_index(level, dir_level, le32_to_cpu(dentry_hash) % nbucket);
233
234 for (block = bidx; block <= (bidx + nblock - 1); block++) {
235
236 /* Firstly, we should know the direct node of target data blk */
237 if (dn.node_blk && dn.node_blk != dn.inode_blk)
238 free(dn.node_blk);
239
240 set_new_dnode(&dn, parent, NULL, pino);
241 get_dnode_of_data(sbi, &dn, block, ALLOC_NODE);
242
243 if (dn.data_blkaddr == NULL_ADDR) {
244 new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA);
245 } else {
246 ret = dev_read_block(dentry_blk, dn.data_blkaddr);
247 ASSERT(ret >= 0);
248 }
249 bit_pos = room_for_filename(dentry_blk->dentry_bitmap,
250 slots, NR_DENTRY_IN_BLOCK);
251
252 if (bit_pos < NR_DENTRY_IN_BLOCK)
253 goto add_dentry;
254 }
255 level ++;
256 goto start;
257
258 add_dentry:
259 make_dentry_ptr(&d, (void *)dentry_blk, 1);
260 f2fs_update_dentry(ino, file_type, &d, name, name_len, dentry_hash, bit_pos);
261
262 ret = dev_write_block(dentry_blk, dn.data_blkaddr);
263 ASSERT(ret >= 0);
264
265 /*
266 * Parent inode needs updating, because its inode info may be changed.
267 * such as i_current_depth and i_blocks.
268 */
269 if (parent->i.i_current_depth != cpu_to_le32(current_depth)) {
270 parent->i.i_current_depth = cpu_to_le32(current_depth);
271 dn.idirty = 1;
272 }
273
274 /* Update parent's i_links info*/
275 if (inc_link && (file_type == F2FS_FT_DIR)){
276 u32 links = le32_to_cpu(parent->i.i_links);
277 parent->i.i_links = cpu_to_le32(links + 1);
278 dn.idirty = 1;
279 }
280
281 if ((block + 1) * F2FS_BLKSIZE > le64_to_cpu(parent->i.i_size)) {
282 parent->i.i_size = cpu_to_le64((block + 1) * F2FS_BLKSIZE);
283 dn.idirty = 1;
284 }
285
286 if (dn.ndirty) {
287 ret = dev_write_block(dn.node_blk, dn.node_blkaddr);
288 ASSERT(ret >= 0);
289 }
290
291 if (dn.idirty) {
292 ASSERT(parent == dn.inode_blk);
293 ret = dev_write_block(dn.inode_blk, p_blkaddr);
294 ASSERT(ret >= 0);
295 }
296
297 if (dn.node_blk != dn.inode_blk)
298 free(dn.node_blk);
299 free(dentry_blk);
300 return 0;
301 }
302
make_empty_dir(struct f2fs_sb_info * sbi,struct f2fs_node * inode)303 static void make_empty_dir(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
304 {
305 struct f2fs_dentry_block *dent_blk;
306 nid_t ino = le32_to_cpu(inode->footer.ino);
307 nid_t pino = le32_to_cpu(inode->i.i_pino);
308 struct f2fs_summary sum;
309 struct node_info ni;
310 block_t blkaddr;
311 int ret;
312
313 get_node_info(sbi, ino, &ni);
314
315 dent_blk = calloc(BLOCK_SZ, 1);
316 ASSERT(dent_blk);
317
318 dent_blk->dentry[0].hash_code = 0;
319 dent_blk->dentry[0].ino = cpu_to_le32(ino);
320 dent_blk->dentry[0].name_len = cpu_to_le16(1);
321 dent_blk->dentry[0].file_type = F2FS_FT_DIR;
322 memcpy(dent_blk->filename[0], ".", 1);
323
324 dent_blk->dentry[1].hash_code = 0;
325 dent_blk->dentry[1].ino = cpu_to_le32(pino);
326 dent_blk->dentry[1].name_len = cpu_to_le16(2);
327 dent_blk->dentry[1].file_type = F2FS_FT_DIR;
328 memcpy(dent_blk->filename[1], "..", 2);
329
330 test_and_set_bit_le(0, dent_blk->dentry_bitmap);
331 test_and_set_bit_le(1, dent_blk->dentry_bitmap);
332
333 set_summary(&sum, ino, 0, ni.version);
334 reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_DATA);
335
336 ret = dev_write_block(dent_blk, blkaddr);
337 ASSERT(ret >= 0);
338
339 inode->i.i_addr[0] = cpu_to_le32(blkaddr);
340 free(dent_blk);
341 }
342
page_symlink(struct f2fs_sb_info * sbi,struct f2fs_node * inode,const char * symname,int symlen)343 static void page_symlink(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
344 const char *symname, int symlen)
345 {
346 nid_t ino = le32_to_cpu(inode->footer.ino);
347 struct f2fs_summary sum;
348 struct node_info ni;
349 char *data_blk;
350 block_t blkaddr;
351 int ret;
352
353 get_node_info(sbi, ino, &ni);
354
355 /* store into inline_data */
356 if (symlen + 1 <= MAX_INLINE_DATA) {
357 inode->i.i_inline |= F2FS_INLINE_DATA;
358 inode->i.i_inline |= F2FS_DATA_EXIST;
359 memcpy(&inode->i.i_addr[1], symname, symlen);
360 return;
361 }
362
363 data_blk = calloc(BLOCK_SZ, 1);
364 ASSERT(data_blk);
365
366 memcpy(data_blk, symname, symlen);
367
368 set_summary(&sum, ino, 0, ni.version);
369 reserve_new_block(sbi, &blkaddr, &sum, CURSEG_WARM_DATA);
370
371 ret = dev_write_block(data_blk, blkaddr);
372 ASSERT(ret >= 0);
373
374 inode->i.i_addr[0] = cpu_to_le32(blkaddr);
375 free(data_blk);
376 }
377
init_inode_block(struct f2fs_sb_info * sbi,struct f2fs_node * node_blk,struct dentry * de)378 static void init_inode_block(struct f2fs_sb_info *sbi,
379 struct f2fs_node *node_blk, struct dentry *de)
380 {
381 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
382 mode_t mode = de->mode;
383 int links = 1;
384 unsigned int size;
385 int blocks = 1;
386
387 if (de->file_type == F2FS_FT_DIR) {
388 mode |= S_IFDIR;
389 size = 4096;
390 links++;
391 blocks++;
392 } else if (de->file_type == F2FS_FT_REG_FILE) {
393 mode |= S_IFREG;
394 size = 0;
395 } else if (de->file_type == F2FS_FT_SYMLINK) {
396 ASSERT(de->link);
397 mode |= S_IFLNK;
398 size = strlen(de->link);
399 if (size + 1 > MAX_INLINE_DATA)
400 blocks++;
401 } else {
402 ASSERT(0);
403 }
404
405 node_blk->i.i_mode = cpu_to_le16(mode);
406 node_blk->i.i_advise = 0;
407 node_blk->i.i_uid = cpu_to_le32(de->uid);
408 node_blk->i.i_gid = cpu_to_le32(de->gid);
409 node_blk->i.i_links = cpu_to_le32(links);
410 node_blk->i.i_size = cpu_to_le32(size);
411 node_blk->i.i_blocks = cpu_to_le32(blocks);
412 node_blk->i.i_atime = cpu_to_le64(de->mtime);
413 node_blk->i.i_ctime = cpu_to_le64(de->mtime);
414 node_blk->i.i_mtime = cpu_to_le64(de->mtime);
415 node_blk->i.i_atime_nsec = 0;
416 node_blk->i.i_ctime_nsec = 0;
417 node_blk->i.i_mtime_nsec = 0;
418 node_blk->i.i_generation = 0;
419 node_blk->i.i_current_depth = cpu_to_le32(1);
420 node_blk->i.i_xattr_nid = 0;
421 node_blk->i.i_flags = 0;
422 node_blk->i.i_inline = F2FS_INLINE_XATTR;
423 node_blk->i.i_pino = cpu_to_le32(de->pino);
424 node_blk->i.i_namelen = cpu_to_le32(de->len);
425 memcpy(node_blk->i.i_name, de->name, de->len);
426 node_blk->i.i_name[de->len] = 0;
427
428 node_blk->footer.ino = cpu_to_le32(de->ino);
429 node_blk->footer.nid = cpu_to_le32(de->ino);
430 node_blk->footer.flag = 0;
431 node_blk->footer.cp_ver = ckpt->checkpoint_ver;
432
433 if (S_ISDIR(mode))
434 make_empty_dir(sbi, node_blk);
435 else if (S_ISLNK(mode))
436 page_symlink(sbi, node_blk, de->link, size);
437 }
438
convert_inline_dentry(struct f2fs_sb_info * sbi,struct f2fs_node * node,block_t p_blkaddr)439 int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
440 block_t p_blkaddr)
441 {
442 struct f2fs_inode *inode = &(node->i);
443 unsigned int dir_level = node->i.i_dir_level;
444 nid_t ino = le32_to_cpu(node->footer.ino);
445 char inline_data[MAX_INLINE_DATA];
446 struct dnode_of_data dn = {0};
447 struct f2fs_dentry_ptr d;
448 unsigned long bit_pos = 0;
449 int ret = 0;
450
451 if (!(inode->i_inline & F2FS_INLINE_DENTRY))
452 return 0;
453
454 memcpy(inline_data, inline_data_addr(node), MAX_INLINE_DATA);
455 memset(inline_data_addr(node), 0, MAX_INLINE_DATA);
456 inode->i_inline &= ~F2FS_INLINE_DENTRY;
457
458 ret = dev_write_block(node, p_blkaddr);
459 ASSERT(ret >= 0);
460
461 if (!dir_level) {
462 struct f2fs_inline_dentry *inline_dentry;
463 struct f2fs_dentry_block *dentry_blk;
464
465 dentry_blk = calloc(BLOCK_SZ, 1);
466 ASSERT(dentry_blk);
467
468 set_new_dnode(&dn, node, NULL, ino);
469 get_dnode_of_data(sbi, &dn, 0, ALLOC_NODE);
470 if (dn.data_blkaddr == NULL_ADDR)
471 new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA);
472
473 inline_dentry = (struct f2fs_inline_dentry *)inline_data;
474 /* copy data from inline dentry block to new dentry block */
475 memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap,
476 INLINE_DENTRY_BITMAP_SIZE);
477 memset(dentry_blk->dentry_bitmap + INLINE_DENTRY_BITMAP_SIZE, 0,
478 SIZE_OF_DENTRY_BITMAP - INLINE_DENTRY_BITMAP_SIZE);
479
480 memcpy(dentry_blk->dentry, inline_dentry->dentry,
481 sizeof(struct f2fs_dir_entry) * NR_INLINE_DENTRY);
482 memcpy(dentry_blk->filename, inline_dentry->filename,
483 NR_INLINE_DENTRY * F2FS_SLOT_LEN);
484
485 ret = dev_write_block(dentry_blk, dn.data_blkaddr);
486 ASSERT(ret >= 0);
487
488 MSG(1, "%s: copy inline entry to block\n", __func__);
489
490 free(dentry_blk);
491 return ret;
492 }
493
494 make_empty_dir(sbi, node);
495 make_dentry_ptr(&d, (void *)inline_data, 2);
496
497 while (bit_pos < d.max) {
498 struct f2fs_dir_entry *de;
499 const unsigned char *filename;
500 int namelen;
501
502 if (!test_bit_le(bit_pos, d.bitmap)) {
503 bit_pos++;
504 continue;
505 }
506
507 de = &d.dentry[bit_pos];
508 if (!de->name_len) {
509 bit_pos++;
510 continue;
511 }
512
513 filename = d.filename[bit_pos];
514 namelen = le32_to_cpu(de->name_len);
515
516 if (is_dot_dotdot(filename, namelen)) {
517 bit_pos += GET_DENTRY_SLOTS(namelen);
518 continue;
519 }
520
521 ret = f2fs_add_link(sbi, node, filename, namelen,
522 le32_to_cpu(de->ino),
523 de->file_type, p_blkaddr, 0);
524 if (ret)
525 MSG(0, "Convert file \"%s\" ERR=%d\n", filename, ret);
526 else
527 MSG(1, "%s: add inline entry to block\n", __func__);
528
529 bit_pos += GET_DENTRY_SLOTS(namelen);
530 }
531
532 return 0;
533 }
534
f2fs_create(struct f2fs_sb_info * sbi,struct dentry * de)535 int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
536 {
537 struct f2fs_node *parent, *child;
538 struct node_info ni;
539 struct f2fs_summary sum;
540 block_t blkaddr;
541 int ret;
542
543 /* Find if there is a */
544 get_node_info(sbi, de->pino, &ni);
545 if (ni.blk_addr == NULL_ADDR) {
546 MSG(0, "No parent directory pino=%x\n", de->pino);
547 return -1;
548 }
549
550 parent = calloc(BLOCK_SZ, 1);
551 ASSERT(parent);
552
553 ret = dev_read_block(parent, ni.blk_addr);
554 ASSERT(ret >= 0);
555
556 /* Must convert inline dentry before the following opertions */
557 ret = convert_inline_dentry(sbi, parent, ni.blk_addr);
558 if (ret) {
559 MSG(0, "Convert inline dentry for pino=%x failed.\n", de->pino);
560 return -1;
561 }
562
563 ret = f2fs_find_entry(sbi, parent, de);
564 if (ret) {
565 MSG(0, "Skip the existing \"%s\" pino=%x ERR=%d\n",
566 de->name, de->pino, ret);
567 if (de->file_type == F2FS_FT_REG_FILE)
568 de->ino = 0;
569 goto free_parent_dir;
570 }
571
572 child = calloc(BLOCK_SZ, 1);
573 ASSERT(child);
574
575 f2fs_alloc_nid(sbi, &de->ino, 1);
576
577 init_inode_block(sbi, child, de);
578
579 ret = f2fs_add_link(sbi, parent, child->i.i_name,
580 le32_to_cpu(child->i.i_namelen),
581 le32_to_cpu(child->footer.ino),
582 map_de_type(le16_to_cpu(child->i.i_mode)),
583 ni.blk_addr, 1);
584 if (ret) {
585 MSG(0, "Skip the existing \"%s\" pino=%x ERR=%d\n",
586 de->name, de->pino, ret);
587 goto free_child_dir;
588 }
589
590 /* write child */
591 set_summary(&sum, de->ino, 0, ni.version);
592 reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE);
593
594 /* update nat info */
595 update_nat_blkaddr(sbi, de->ino, de->ino, blkaddr);
596
597 ret = dev_write_block(child, blkaddr);
598 ASSERT(ret >= 0);
599
600 update_free_segments(sbi);
601 MSG(1, "Info: Create \"%s\" type=%x, ino=%x / %x into \"%s\"\n",
602 de->full_path, de->file_type,
603 de->ino, de->pino, de->path);
604 free_child_dir:
605 free(child);
606 free_parent_dir:
607 free(parent);
608 return 0;
609 }
610
f2fs_mkdir(struct f2fs_sb_info * sbi,struct dentry * de)611 int f2fs_mkdir(struct f2fs_sb_info *sbi, struct dentry *de)
612 {
613 return f2fs_create(sbi, de);
614 }
615
f2fs_symlink(struct f2fs_sb_info * sbi,struct dentry * de)616 int f2fs_symlink(struct f2fs_sb_info *sbi, struct dentry *de)
617 {
618 return f2fs_create(sbi, de);
619 }
620
f2fs_find_path(struct f2fs_sb_info * sbi,char * path,nid_t * ino)621 int f2fs_find_path(struct f2fs_sb_info *sbi, char *path, nid_t *ino)
622 {
623 struct f2fs_node *parent;
624 struct node_info ni;
625 struct dentry de;
626 int err = 0;
627 int ret;
628 char *p;
629
630 if (path[0] != '/')
631 return -ENOENT;
632
633 *ino = F2FS_ROOT_INO(sbi);
634 parent = calloc(BLOCK_SZ, 1);
635 ASSERT(parent);
636
637 p = strtok(path, "/");
638 while (p) {
639 de.name = (const u8 *)p;
640 de.len = strlen(p);
641
642 get_node_info(sbi, *ino, &ni);
643 if (ni.blk_addr == NULL_ADDR) {
644 err = -ENOENT;
645 goto err;
646 }
647 ret = dev_read_block(parent, ni.blk_addr);
648 ASSERT(ret >= 0);
649
650 ret = f2fs_find_entry(sbi, parent, &de);
651 if (!ret) {
652 err = -ENOENT;
653 goto err;
654 }
655
656 *ino = de.ino;
657 p = strtok(NULL, "/");
658 }
659 err:
660 free(parent);
661 return err;
662 }
663