1 /*
2 * Copyright (c) 2006-2020, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020/08/21 ShaoJinchun first version
9 */
10
11 #include <rtthread.h>
12 #include <dfs.h>
13 #include <dfs_fs.h>
14 #include <dfs_file.h>
15 #include <dfs_dentry.h>
16 #include <dfs_mnt.h>
17
18 #include "dfs_cromfs.h"
19
20 #include <stdint.h>
21
22 #include "zlib.h"
23
24 #ifdef RT_USING_PAGECACHE
25 #include "dfs_pcache.h"
26 #endif
27
28 /**********************************/
29
30 #define CROMFS_PATITION_HEAD_SIZE 256
31 #define CROMFS_DIRENT_CACHE_SIZE 8
32
33 #define CROMFS_MAGIC "CROMFSMG"
34
35 #define CROMFS_CT_ASSERT(name, x) \
36 struct assert_##name {char ary[2 * (x) - 1];}
37
38 #define CROMFS_POS_ROOT (0x0UL)
39 #define CROMFS_POS_ERROR (0x1UL)
40
41 typedef struct
42 {
43 uint8_t magic[8]; /* CROMFS_MAGIC */
44 uint32_t version;
45 uint32_t partition_attr; /* expand, now reserved 0 */
46 uint32_t partition_size; /* with partition head */
47 uint32_t root_dir_pos; /* root dir pos */
48 uint32_t root_dir_size;
49 } partition_head_data;
50
51 typedef struct
52 {
53 partition_head_data head;
54 uint8_t padding[CROMFS_PATITION_HEAD_SIZE - sizeof(partition_head_data)];
55 } partition_head;
56
57 enum
58 {
59 CROMFS_DIRENT_ATTR_FILE = 0x0UL,
60 CROMFS_DIRENT_ATTR_DIR = 0x1UL,
61 CROMFS_DIRENT_ATTR_SYMLINK = 0x2UL,
62 };
63
64 typedef struct
65 {
66 uint16_t attr; /* dir or file add other */
67 uint16_t name_size; /* name real size */
68 uint32_t file_size; /* file data size */
69 uint32_t file_origin_size; /* file size before compress */
70 uint32_t parition_pos; /* offset of data */
71 uint8_t name[0]; /* name data */
72 } cromfs_dirent;
73
74 #define CROMFS_ALIGN_SIZE_BIT 4
75 #define CROMFS_ALIGN_SIZE (1UL << CROMFS_ALIGN_SIZE_BIT) /* must be same as sizeof cromfs_dirent */
76 #define CROMFS_ALIGN_SIZE_MASK (CROMFS_ALIGN_SIZE - 1)
77
78 CROMFS_CT_ASSERT(align_size, CROMFS_ALIGN_SIZE == sizeof(cromfs_dirent));
79
80 typedef union
81 {
82 cromfs_dirent dirent;
83 uint8_t name[CROMFS_ALIGN_SIZE];
84 } cromfs_dirent_item;
85
86 /**********************************/
87
88 typedef struct
89 {
90 rt_list_t list;
91 uint32_t partition_pos;
92 uint32_t size;
93 uint8_t *buff;
94 } cromfs_dirent_cache;
95
96 typedef struct st_cromfs_info
97 {
98 rt_device_t device;
99 uint32_t partition_size;
100 uint32_t bytes_per_sector;
101 uint32_t (*read_bytes)(struct st_cromfs_info *ci, uint32_t pos, void *buf, uint32_t size);
102 partition_head_data part_info;
103 struct rt_mutex lock;
104 struct cromfs_avl_struct *cromfs_avl_root;
105 rt_list_t cromfs_dirent_cache_head;
106 int cromfs_dirent_cache_nr;
107 const void *data;
108 } cromfs_info;
109
110 typedef struct
111 {
112 uint32_t ref;
113 uint32_t partition_pos;
114 cromfs_info *ci;
115 uint32_t size;
116 uint8_t *buff;
117 uint32_t partition_size;
118 int data_valid;
119 } file_info;
120
121 /**********************************/
122
123 #define avl_key_t uint32_t
124 #define AVL_EMPTY (struct cromfs_avl_struct *)0
125 #define avl_maxheight 32
126 #define heightof(tree) ((tree) == AVL_EMPTY ? 0 : (tree)->avl_height)
127
128 struct cromfs_avl_struct
129 {
130 struct cromfs_avl_struct *avl_left;
131 struct cromfs_avl_struct *avl_right;
132 int avl_height;
133 avl_key_t avl_key;
134 file_info *fi;
135 };
136
137 static void cromfs_avl_remove(struct cromfs_avl_struct *node_to_delete, struct cromfs_avl_struct **ptree);
138 static void cromfs_avl_insert(struct cromfs_avl_struct *new_node, struct cromfs_avl_struct **ptree);
139 static struct cromfs_avl_struct* cromfs_avl_find(avl_key_t key, struct cromfs_avl_struct *ptree);
140
cromfs_avl_rebalance(struct cromfs_avl_struct *** nodeplaces_ptr,int count)141 static void cromfs_avl_rebalance(struct cromfs_avl_struct ***nodeplaces_ptr, int count)
142 {
143 for (;count > 0; count--)
144 {
145 struct cromfs_avl_struct **nodeplace = *--nodeplaces_ptr;
146 struct cromfs_avl_struct *node = *nodeplace;
147 struct cromfs_avl_struct *nodeleft = node->avl_left;
148 struct cromfs_avl_struct *noderight = node->avl_right;
149 int heightleft = heightof(nodeleft);
150 int heightright = heightof(noderight);
151 if (heightright + 1 < heightleft)
152 {
153 struct cromfs_avl_struct * nodeleftleft = nodeleft->avl_left;
154 struct cromfs_avl_struct * nodeleftright = nodeleft->avl_right;
155 int heightleftright = heightof(nodeleftright);
156 if (heightof(nodeleftleft) >= heightleftright)
157 {
158 node->avl_left = nodeleftright;
159 nodeleft->avl_right = node;
160 nodeleft->avl_height = 1 + (node->avl_height = 1 + heightleftright);
161 *nodeplace = nodeleft;
162 }
163 else
164 {
165 nodeleft->avl_right = nodeleftright->avl_left;
166 node->avl_left = nodeleftright->avl_right;
167 nodeleftright->avl_left = nodeleft;
168 nodeleftright->avl_right = node;
169 nodeleft->avl_height = node->avl_height = heightleftright;
170 nodeleftright->avl_height = heightleft;
171 *nodeplace = nodeleftright;
172 }
173 }
174 else if (heightleft + 1 < heightright)
175 {
176 struct cromfs_avl_struct *noderightright = noderight->avl_right;
177 struct cromfs_avl_struct *noderightleft = noderight->avl_left;
178 int heightrightleft = heightof(noderightleft);
179 if (heightof(noderightright) >= heightrightleft)
180 {
181 node->avl_right = noderightleft;
182 noderight->avl_left = node;
183 noderight->avl_height = 1 + (node->avl_height = 1 + heightrightleft);
184 *nodeplace = noderight;
185 }
186 else
187 {
188 noderight->avl_left = noderightleft->avl_right;
189 node->avl_right = noderightleft->avl_left;
190 noderightleft->avl_right = noderight;
191 noderightleft->avl_left = node;
192 noderight->avl_height = node->avl_height = heightrightleft;
193 noderightleft->avl_height = heightright;
194 *nodeplace = noderightleft;
195 }
196 }
197 else {
198 int height = (heightleft<heightright ? heightright : heightleft) + 1;
199 if (height == node->avl_height)
200 {
201 break;
202 }
203 node->avl_height = height;
204 }
205 }
206 }
207
cromfs_avl_remove(struct cromfs_avl_struct * node_to_delete,struct cromfs_avl_struct ** ptree)208 static void cromfs_avl_remove(struct cromfs_avl_struct *node_to_delete, struct cromfs_avl_struct **ptree)
209 {
210 avl_key_t key = node_to_delete->avl_key;
211 struct cromfs_avl_struct **nodeplace = ptree;
212 struct cromfs_avl_struct **stack[avl_maxheight];
213 uint32_t stack_count = 0;
214 struct cromfs_avl_struct ***stack_ptr = &stack[0]; /* = &stack[stackcount] */
215 struct cromfs_avl_struct **nodeplace_to_delete;
216 for (;;)
217 {
218 struct cromfs_avl_struct *node = *nodeplace;
219 if (node == AVL_EMPTY)
220 {
221 return;
222 }
223 *stack_ptr++ = nodeplace;
224 stack_count++;
225 if (key == node->avl_key)
226 {
227 break;
228 }
229 if (key < node->avl_key)
230 {
231 nodeplace = &node->avl_left;
232 }
233 else
234 {
235 nodeplace = &node->avl_right;
236 }
237 }
238 nodeplace_to_delete = nodeplace;
239 if (node_to_delete->avl_left == AVL_EMPTY)
240 {
241 *nodeplace_to_delete = node_to_delete->avl_right;
242 stack_ptr--;
243 stack_count--;
244 }
245 else
246 {
247 struct cromfs_avl_struct *** stack_ptr_to_delete = stack_ptr;
248 struct cromfs_avl_struct ** nodeplace = &node_to_delete->avl_left;
249 struct cromfs_avl_struct * node;
250 for (;;)
251 {
252 node = *nodeplace;
253 if (node->avl_right == AVL_EMPTY)
254 {
255 break;
256 }
257 *stack_ptr++ = nodeplace;
258 stack_count++;
259 nodeplace = &node->avl_right;
260 }
261 *nodeplace = node->avl_left;
262 node->avl_left = node_to_delete->avl_left;
263 node->avl_right = node_to_delete->avl_right;
264 node->avl_height = node_to_delete->avl_height;
265 *nodeplace_to_delete = node;
266 *stack_ptr_to_delete = &node->avl_left;
267 }
268 cromfs_avl_rebalance(stack_ptr,stack_count);
269 }
270
cromfs_avl_insert(struct cromfs_avl_struct * new_node,struct cromfs_avl_struct ** ptree)271 static void cromfs_avl_insert(struct cromfs_avl_struct *new_node, struct cromfs_avl_struct **ptree)
272 {
273 avl_key_t key = new_node->avl_key;
274 struct cromfs_avl_struct **nodeplace = ptree;
275 struct cromfs_avl_struct **stack[avl_maxheight];
276 int stack_count = 0;
277 struct cromfs_avl_struct ***stack_ptr = &stack[0]; /* = &stack[stackcount] */
278 for (;;)
279 {
280 struct cromfs_avl_struct * node = *nodeplace;
281 if (node == AVL_EMPTY)
282 {
283 break;
284 }
285 *stack_ptr++ = nodeplace;
286 stack_count++;
287 if (key < node->avl_key)
288 {
289 nodeplace = &node->avl_left;
290 }
291 else
292 {
293 nodeplace = &node->avl_right;
294 }
295 }
296 new_node->avl_left = AVL_EMPTY;
297 new_node->avl_right = AVL_EMPTY;
298 new_node->avl_height = 1;
299 *nodeplace = new_node;
300 cromfs_avl_rebalance(stack_ptr,stack_count);
301 }
302
cromfs_avl_find(avl_key_t key,struct cromfs_avl_struct * ptree)303 static struct cromfs_avl_struct* cromfs_avl_find(avl_key_t key, struct cromfs_avl_struct* ptree)
304 {
305 for (;;)
306 {
307 if (ptree == AVL_EMPTY)
308 {
309 return (struct cromfs_avl_struct *)0;
310 }
311 if (key == ptree->avl_key)
312 {
313 break;
314 }
315 if (key < ptree->avl_key)
316 {
317 ptree = ptree->avl_left;
318 }
319 else
320 {
321 ptree = ptree->avl_right;
322 }
323 }
324 return ptree;
325 }
326
327 /**********************************/
328
cromfs_read_bytes(cromfs_info * ci,uint32_t pos,void * buf,uint32_t size)329 static uint32_t cromfs_read_bytes(cromfs_info *ci, uint32_t pos, void *buf, uint32_t size)
330 {
331 if (pos >= ci->partition_size || pos + size > ci->partition_size)
332 {
333 return 0;
334 }
335 return ci->read_bytes(ci, pos, buf, size);
336 }
337
cromfs_noblk_read_bytes(cromfs_info * ci,uint32_t pos,void * buf,uint32_t size)338 static uint32_t cromfs_noblk_read_bytes(cromfs_info *ci, uint32_t pos, void *buf, uint32_t size)
339 {
340 uint32_t ret = 0;
341
342 ret = rt_device_read(ci->device, pos, buf, size);
343 if (ret != size)
344 {
345 return 0;
346 }
347 else
348 {
349 return ret;
350 }
351 }
352
cromfs_data_read_bytes(cromfs_info * ci,uint32_t pos,void * buf,uint32_t size)353 static uint32_t cromfs_data_read_bytes(cromfs_info *ci, uint32_t pos, void *buf, uint32_t size)
354 {
355 uint32_t ret = 0;
356 uint8_t *data = (uint8_t *)ci->data;
357
358 if (data)
359 {
360 memcpy(buf, data + pos, size);
361 ret = size;
362 }
363
364 return ret;
365 }
366
cromfs_blk_read_bytes(cromfs_info * ci,uint32_t pos,void * buf,uint32_t size)367 static uint32_t cromfs_blk_read_bytes(cromfs_info *ci, uint32_t pos, void *buf, uint32_t size)
368 {
369 uint32_t ret = 0;
370 uint32_t size_bak = size;
371 uint32_t start_blk = 0;
372 uint32_t end_blk = 0;
373 uint32_t off_s = 0;
374 uint32_t sector_nr = 0;
375 uint8_t *block_buff = NULL;
376 uint32_t ret_len = 0;
377
378 if (!size || !buf)
379 {
380 return 0;
381 }
382 block_buff = (uint8_t *)malloc(2 * ci->bytes_per_sector);
383 if (!block_buff)
384 {
385 return 0;
386 }
387 start_blk = pos / ci->bytes_per_sector;
388 off_s = pos % ci->bytes_per_sector;
389 end_blk = (pos + size - 1) / ci->bytes_per_sector;
390
391 sector_nr = end_blk - start_blk;
392 if (sector_nr < 2)
393 {
394 ret_len = rt_device_read(ci->device, start_blk, block_buff, sector_nr + 1);
395 if (ret_len != sector_nr + 1)
396 {
397 goto end;
398 }
399 memcpy(buf, block_buff + off_s, size);
400 }
401 else
402 {
403 ret_len = rt_device_read(ci->device, start_blk, block_buff, 1);
404 if (ret_len != 1)
405 {
406 goto end;
407 }
408 memcpy(buf, block_buff + off_s, ci->bytes_per_sector - off_s);
409 off_s = (ci->bytes_per_sector - off_s);
410 size -= off_s;
411 sector_nr--;
412 start_blk++;
413 if (sector_nr)
414 {
415 ret_len = rt_device_read(ci->device, start_blk, (char*)buf + off_s, sector_nr);
416 if (ret_len != sector_nr)
417 {
418 goto end;
419 }
420 start_blk += sector_nr;
421 off_s += (sector_nr * ci->bytes_per_sector);
422 size -= (sector_nr * ci->bytes_per_sector);
423 }
424 ret_len = rt_device_read(ci->device, start_blk, block_buff, 1);
425 if (ret_len != 1)
426 {
427 goto end;
428 }
429 memcpy((char*)buf + off_s, block_buff, size);
430 }
431 ret = size_bak;
432 end:
433 free(block_buff);
434 return ret;
435 }
436
437 /**********************************/
438
cromfs_dirent_cache_get(cromfs_info * ci,uint32_t pos,uint32_t size)439 static uint8_t *cromfs_dirent_cache_get(cromfs_info *ci, uint32_t pos, uint32_t size)
440 {
441 rt_list_t *l = NULL;
442 cromfs_dirent_cache *dir = NULL;
443 uint32_t len = 0;
444
445 /* find */
446 for (l = ci->cromfs_dirent_cache_head.next; l != &ci->cromfs_dirent_cache_head; l = l->next)
447 {
448 dir = (cromfs_dirent_cache *)l;
449 if (dir->partition_pos == pos)
450 {
451 RT_ASSERT(dir->size == size);
452 rt_list_remove(l);
453 rt_list_insert_after(&ci->cromfs_dirent_cache_head, l);
454 return dir->buff;
455 }
456 }
457 /* not found */
458 if (ci->cromfs_dirent_cache_nr >= CROMFS_DIRENT_CACHE_SIZE)
459 {
460 l = ci->cromfs_dirent_cache_head.prev;
461 dir = (cromfs_dirent_cache *)l;
462 rt_list_remove(l);
463 free(dir->buff);
464 free(dir);
465 ci->cromfs_dirent_cache_nr--;
466 }
467 dir = (cromfs_dirent_cache *)malloc(sizeof *dir);
468 if (!dir)
469 {
470 return NULL;
471 }
472 dir->buff = (uint8_t *)malloc(size);
473 if (!dir->buff)
474 {
475 free(dir);
476 return NULL;
477 }
478 len = cromfs_read_bytes(ci, pos, dir->buff, size);
479 if (len != size)
480 {
481 free(dir->buff);
482 free(dir);
483 return NULL;
484 }
485 rt_list_insert_after(&ci->cromfs_dirent_cache_head, (rt_list_t *)dir);
486 ci->cromfs_dirent_cache_nr++;
487 dir->partition_pos = pos;
488 dir->size = size;
489 return dir->buff;
490 }
491
cromfs_dirent_cache_destroy(cromfs_info * ci)492 static void cromfs_dirent_cache_destroy(cromfs_info *ci)
493 {
494 rt_list_t *l = NULL;
495 cromfs_dirent_cache *dir = NULL;
496
497 while ((l = ci->cromfs_dirent_cache_head.next) != &ci->cromfs_dirent_cache_head)
498 {
499 rt_list_remove(l);
500 dir = (cromfs_dirent_cache *)l;
501 free(dir->buff);
502 free(dir);
503 ci->cromfs_dirent_cache_nr--;
504 }
505 }
506
507 /**********************************/
508
509 #ifdef RT_USING_PAGECACHE
510 static ssize_t dfs_cromfs_page_read(struct dfs_file *file, struct dfs_page *page);
511
512 static struct dfs_aspace_ops dfs_cromfs_aspace_ops =
513 {
514 .read = dfs_cromfs_page_read
515 };
516 #endif
517
dfs_cromfs_mount(struct dfs_mnt * mnt,unsigned long rwflag,const void * data)518 static int dfs_cromfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
519 {
520 struct rt_device_blk_geometry geometry;
521 uint32_t len = 0;
522 cromfs_info *ci = NULL;
523
524 ci = (cromfs_info *)malloc(sizeof *ci);
525 if (!ci)
526 {
527 return -ENOMEM;
528 }
529
530 memset(ci, 0, sizeof *ci);
531 ci->device = mnt->dev_id;
532 ci->partition_size = UINT32_MAX;
533
534 if (ci->device)
535 {
536 rt_err_t ret = rt_device_open(ci->device, RT_DEVICE_OFLAG_RDONLY);
537 if (ret != RT_EOK)
538 {
539 free(ci);
540 return ret;
541 }
542
543 if (ci->device->type == RT_Device_Class_Block)
544 {
545 rt_device_control(ci->device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
546 ci->bytes_per_sector = geometry.bytes_per_sector;
547 ci->read_bytes = cromfs_blk_read_bytes;
548 }
549 else
550 {
551 ci->read_bytes = cromfs_noblk_read_bytes;
552 }
553 }
554 else if (data)
555 {
556 ci->data = data;
557 ci->read_bytes = cromfs_data_read_bytes;
558 }
559 else
560 {
561 free(ci);
562 return -RT_EIO;
563 }
564
565 len = cromfs_read_bytes(ci, 0, &ci->part_info, sizeof ci->part_info);
566 if (len != sizeof ci->part_info ||
567 memcmp(ci->part_info.magic, CROMFS_MAGIC, sizeof ci->part_info.magic) != 0)
568 {
569 free(ci);
570 return -RT_ERROR;
571 }
572 ci->partition_size = ci->part_info.partition_size;
573 mnt->data = ci;
574
575 rt_mutex_init(&ci->lock, "crom", RT_IPC_FLAG_FIFO);
576 ci->cromfs_avl_root = NULL;
577
578 rt_list_init(&ci->cromfs_dirent_cache_head);
579 ci->cromfs_dirent_cache_nr = 0;
580
581 return RT_EOK;
582 }
583
dfs_cromfs_unmount(struct dfs_mnt * mnt)584 static int dfs_cromfs_unmount(struct dfs_mnt *mnt)
585 {
586 rt_err_t result = RT_EOK;
587 cromfs_info *ci = NULL;
588
589 ci = (cromfs_info *)mnt->data;
590
591 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
592 if (result != RT_EOK)
593 {
594 return -RT_ERROR;
595 }
596
597 cromfs_dirent_cache_destroy(ci);
598
599 while (ci->cromfs_avl_root)
600 {
601 struct cromfs_avl_struct *node;
602 file_info *fi = NULL;
603
604 node = ci->cromfs_avl_root;
605 fi = node->fi;
606 cromfs_avl_remove(node, &ci->cromfs_avl_root);
607 free(node);
608 if (fi->buff)
609 {
610 free(fi->buff);
611 }
612 free(fi);
613 }
614
615 if (ci->device)
616 {
617 rt_device_close(ci->device);
618 }
619
620 rt_mutex_detach(&ci->lock);
621
622 free(ci);
623
624 return RT_EOK;
625 }
626
cromfs_lookup(cromfs_info * ci,const char * path,int * file_type,uint32_t * size,uint32_t * osize)627 static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* file_type, uint32_t *size, uint32_t *osize)
628 {
629 uint32_t cur_size = 0, cur_pos = 0, cur_osize = 0;
630 const char *subpath = NULL, *subpath_end = NULL;
631 void *di_mem = NULL;
632 int _file_type = 0;
633
634 if (path[0] == '\0')
635 {
636 return CROMFS_POS_ERROR;
637 }
638
639 cur_size = ci->part_info.root_dir_size;
640 cur_osize = 0;
641 cur_pos = ci->part_info.root_dir_pos;
642 _file_type = CROMFS_DIRENT_ATTR_DIR;
643
644 subpath_end = path;
645 while (1)
646 {
647 cromfs_dirent_item *di_iter = NULL;
648 int found = 0;
649
650 /* skip /// */
651 while (*subpath_end && *subpath_end == '/')
652 {
653 subpath_end++;
654 }
655 subpath = subpath_end;
656 while ((*subpath_end != '/') && *subpath_end)
657 {
658 subpath_end++;
659 }
660 if (*subpath == '\0')
661 {
662 break;
663 }
664
665 /* if not dir or empty dir, error */
666 if (_file_type != CROMFS_DIRENT_ATTR_DIR || !cur_size)
667 {
668 return CROMFS_POS_ERROR;
669 }
670
671 /* find subpath */
672 di_mem = cromfs_dirent_cache_get(ci, cur_pos, cur_size);
673 if (!di_mem)
674 {
675 return CROMFS_POS_ERROR;
676 }
677
678 found = 0;
679 di_iter = (cromfs_dirent_item *)di_mem;
680 while (1)
681 {
682 uint32_t name_len = subpath_end - subpath;
683 uint32_t name_block = 0;
684
685 if (di_iter->dirent.name_size == name_len)
686 {
687 if (memcmp(di_iter->dirent.name, subpath, name_len) == 0)
688 {
689 found = 1;
690 cur_size = di_iter->dirent.file_size;
691 cur_osize = di_iter->dirent.file_origin_size;
692 cur_pos = di_iter->dirent.parition_pos;
693 if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_FILE)
694 {
695 _file_type = CROMFS_DIRENT_ATTR_FILE;
696 }
697 else if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_DIR)
698 {
699 _file_type = CROMFS_DIRENT_ATTR_DIR;
700 }
701 else if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_SYMLINK)
702 {
703 _file_type = CROMFS_DIRENT_ATTR_SYMLINK;
704 }
705 else
706 {
707 RT_ASSERT(0);
708 }
709 break;
710 }
711 }
712 name_block = (di_iter->dirent.name_size + CROMFS_ALIGN_SIZE_MASK) >> CROMFS_ALIGN_SIZE_BIT;
713 di_iter += (1 + name_block);
714 if ((uint32_t)(intptr_t)di_iter - (uint32_t)(intptr_t)di_mem >= cur_size)
715 {
716 break;
717 }
718 }
719 if (!found)
720 {
721 return CROMFS_POS_ERROR;
722 }
723 }
724 *size = cur_size;
725 *osize = cur_osize;
726 *file_type = _file_type;
727 return cur_pos;
728 }
729
__dfs_cromfs_lookup(cromfs_info * ci,const char * path,int * file_type,uint32_t * size,uint32_t * osize)730 static uint32_t __dfs_cromfs_lookup(cromfs_info *ci, const char *path, int* file_type, uint32_t *size, uint32_t *osize)
731 {
732 rt_err_t result = RT_EOK;
733 uint32_t ret = 0;
734
735 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
736 if (result != RT_EOK)
737 {
738 return CROMFS_POS_ERROR;
739 }
740 ret = cromfs_lookup(ci, path, file_type, size, osize);
741 rt_mutex_release(&ci->lock);
742 return ret;
743 }
744
fill_file_data(file_info * fi)745 static int fill_file_data(file_info *fi)
746 {
747 int ret = -1;
748 cromfs_info *ci = NULL;
749 void *compressed_file_buff = NULL;
750 uLongf size = 0, osize = 0;
751
752 if (!fi->data_valid)
753 {
754 RT_ASSERT(fi->buff != NULL);
755
756 ci = fi->ci;
757 osize = fi->size;
758 size = fi->partition_size;
759
760 compressed_file_buff = (void *)malloc(size);
761 if (!compressed_file_buff)
762 {
763 goto end;
764 }
765 if (cromfs_read_bytes(ci, fi->partition_pos, compressed_file_buff, size) != size)
766 {
767 goto end;
768 }
769 if (uncompress((uint8_t *)fi->buff, (uLongf *)&osize, (uint8_t *)compressed_file_buff, size) != Z_OK)
770 {
771 goto end;
772 }
773 fi->data_valid = 1;
774 }
775 ret = 0;
776 end:
777 if (compressed_file_buff)
778 {
779 free(compressed_file_buff);
780 }
781 return ret;
782 }
783
dfs_cromfs_read(struct dfs_file * file,void * buf,size_t count,off_t * pos)784 static ssize_t dfs_cromfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
785 {
786 rt_err_t result = RT_EOK;
787 file_info *fi = NULL;
788 cromfs_info *ci = NULL;
789 ssize_t length = 0;
790
791 ci = (cromfs_info *)file->dentry->mnt->data;
792 fi = (file_info *)file->vnode->data;
793
794 if ((off_t)count < (off_t)file->vnode->size - *pos)
795 {
796 length = count;
797 }
798 else
799 {
800 length = (off_t)file->vnode->size - *pos;
801 }
802
803 if (length > 0)
804 {
805 RT_ASSERT(fi->size != 0);
806
807 if (fi->buff)
808 {
809 int fill_ret = 0;
810
811 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
812 if (result != RT_EOK)
813 {
814 return 0;
815 }
816 fill_ret = fill_file_data(fi);
817 rt_mutex_release(&ci->lock);
818 if (fill_ret < 0)
819 {
820 return 0;
821 }
822
823 memcpy(buf, fi->buff + *pos, length);
824 }
825 else
826 {
827 void *di_mem = NULL;
828
829 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
830 if (result != RT_EOK)
831 {
832 return 0;
833 }
834 di_mem = cromfs_dirent_cache_get(ci, fi->partition_pos, fi->size);
835 if (di_mem)
836 {
837 memcpy(buf, (char*)di_mem + *pos, length);
838 }
839 rt_mutex_release(&ci->lock);
840 if (!di_mem)
841 {
842 return 0;
843 }
844 }
845 /* update file current position */
846 *pos += length;
847 }
848
849 return length;
850 }
851
get_file_info(cromfs_info * ci,uint32_t partition_pos,int inc_ref)852 static file_info *get_file_info(cromfs_info *ci, uint32_t partition_pos, int inc_ref)
853 {
854 struct cromfs_avl_struct* node = cromfs_avl_find(partition_pos, ci->cromfs_avl_root);
855
856 if (node)
857 {
858 if (inc_ref)
859 {
860 node->fi->ref++;
861 }
862 return node->fi;
863 }
864 return NULL;
865 }
866
inset_file_info(cromfs_info * ci,uint32_t partition_pos,int file_type,uint32_t size,uint32_t osize)867 static file_info *inset_file_info(cromfs_info *ci, uint32_t partition_pos, int file_type, uint32_t size, uint32_t osize)
868 {
869 file_info *fi = NULL;
870 void *file_buff = NULL;
871 struct cromfs_avl_struct *node = NULL;
872
873 fi = (file_info *)malloc(sizeof *fi);
874 if (!fi)
875 {
876 goto err;
877 }
878 fi->partition_pos = partition_pos;
879 fi->ci = ci;
880 if (file_type == CROMFS_DIRENT_ATTR_DIR)
881 {
882 fi->size = size;
883 }
884 else
885 {
886 fi->size = osize;
887 fi->partition_size = size;
888 fi->data_valid = 0;
889 if (osize)
890 {
891 file_buff = (void *)malloc(osize);
892 if (!file_buff)
893 {
894 goto err;
895 }
896 }
897 }
898 fi->buff = file_buff;
899 fi->ref = 1;
900
901 node = (struct cromfs_avl_struct *)malloc(sizeof *node);
902 if (!node)
903 {
904 goto err;
905 }
906 node->avl_key = partition_pos;
907 node->fi = fi;
908 cromfs_avl_insert(node, &ci->cromfs_avl_root);
909 return fi;
910 err:
911 if (file_buff)
912 {
913 free(file_buff);
914 }
915 if (fi)
916 {
917 free(fi);
918 }
919 return NULL;
920 }
921
deref_file_info(cromfs_info * ci,uint32_t partition_pos)922 static void deref_file_info(cromfs_info *ci, uint32_t partition_pos)
923 {
924 struct cromfs_avl_struct* node = cromfs_avl_find(partition_pos, ci->cromfs_avl_root);
925 file_info *fi = NULL;
926
927 if (node)
928 {
929 node->fi->ref--;
930 if (node->fi->ref == 0)
931 {
932 fi = node->fi;
933 cromfs_avl_remove(node, &ci->cromfs_avl_root);
934 free(node);
935 if (fi->buff)
936 {
937 free(fi->buff);
938 }
939 free(fi);
940 }
941 }
942 }
943
dfs_cromfs_close(struct dfs_file * file)944 static int dfs_cromfs_close(struct dfs_file *file)
945 {
946 file_info *fi = NULL;
947 cromfs_info *ci = NULL;
948 rt_err_t result = 0;
949
950 RT_ASSERT(file->vnode->ref_count > 0);
951 if (file->vnode->ref_count > 1)
952 {
953 return 0;
954 }
955
956 fi = (file_info *)file->vnode->data;
957 ci = (cromfs_info *)file->dentry->mnt->data;
958
959 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
960 if (result != RT_EOK)
961 {
962 return -RT_ERROR;
963 }
964 deref_file_info(ci, fi->partition_pos);
965 rt_mutex_release(&ci->lock);
966 file->vnode->data = NULL;
967 return RT_EOK;
968 }
969
dfs_cromfs_open(struct dfs_file * file)970 static int dfs_cromfs_open(struct dfs_file *file)
971 {
972 int ret = 0;
973 file_info *fi = NULL;
974 cromfs_info *ci = NULL;
975 uint32_t file_pos = 0;
976 uint32_t size = 0, osize = 0;
977 int file_type = 0;
978 rt_err_t result = RT_EOK;
979
980 if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
981 {
982 return -EINVAL;
983 }
984
985 RT_ASSERT(file->vnode->ref_count > 0);
986 if (file->vnode->ref_count > 1)
987 {
988 if (file->vnode->type == FT_DIRECTORY
989 && !(file->flags & O_DIRECTORY))
990 {
991 return -ENOENT;
992 }
993 file->fpos = 0;
994 return 0;
995 }
996
997 ci = (cromfs_info *)file->dentry->mnt->data;
998
999 file_pos = __dfs_cromfs_lookup(ci, file->dentry->pathname, &file_type, &size, &osize);
1000 if (file_pos == CROMFS_POS_ERROR)
1001 {
1002 ret = -ENOENT;
1003 goto end;
1004 }
1005
1006 /* entry is a directory file type */
1007 if (file_type == CROMFS_DIRENT_ATTR_DIR)
1008 {
1009 if (!(file->flags & O_DIRECTORY))
1010 {
1011 ret = -ENOENT;
1012 goto end;
1013 }
1014 file->vnode->type = FT_DIRECTORY;
1015 }
1016 else if (file_type == CROMFS_DIRENT_ATTR_SYMLINK)
1017 {
1018 file->vnode->type = FT_SYMLINK;
1019 }
1020 else
1021 {
1022 /* entry is a file, but open it as a directory */
1023 if (file->flags & O_DIRECTORY)
1024 {
1025 ret = -ENOENT;
1026 goto end;
1027 }
1028 file->vnode->type = FT_REGULAR;
1029 }
1030
1031 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
1032 if (result != RT_EOK)
1033 {
1034 ret = -EINTR;
1035 goto end;
1036 }
1037
1038 fi = get_file_info(ci, file_pos, 1);
1039 if (!fi)
1040 {
1041 fi = inset_file_info(ci, file_pos, file_type, size, osize);
1042 }
1043 rt_mutex_release(&ci->lock);
1044 if (!fi)
1045 {
1046 ret = -ENOENT;
1047 goto end;
1048 }
1049
1050 file->vnode->data = fi;
1051 if (file_type)
1052 {
1053 file->vnode->size = size;
1054 }
1055 else
1056 {
1057 file->vnode->size = osize;
1058 }
1059 file->fpos = 0;
1060
1061 ret = RT_EOK;
1062 end:
1063 return ret;
1064 }
1065
dfs_cromfs_stat(struct dfs_dentry * dentry,struct stat * st)1066 static int dfs_cromfs_stat(struct dfs_dentry *dentry, struct stat *st)
1067 {
1068 uint32_t size = 0, osize = 0;
1069 int file_type = 0;
1070 cromfs_info *ci = NULL;
1071 uint32_t file_pos = 0;
1072
1073 ci = (cromfs_info *)dentry->mnt->data;
1074
1075 file_pos = __dfs_cromfs_lookup(ci, dentry->pathname, &file_type, &size, &osize);
1076 if (file_pos == CROMFS_POS_ERROR)
1077 {
1078 return -ENOENT;
1079 }
1080
1081 st->st_dev = 0;
1082 st->st_mode = S_IFREG | (0777);
1083
1084 if (file_type == CROMFS_DIRENT_ATTR_DIR)
1085 {
1086 st->st_mode &= ~S_IFREG;
1087 st->st_mode |= S_IFDIR;
1088 st->st_size = size;
1089 }
1090 else if(file_type == CROMFS_DIRENT_ATTR_SYMLINK)
1091 {
1092 st->st_mode &= ~S_IFREG;
1093 st->st_mode |= S_IFLNK;
1094 st->st_size = osize;
1095 }
1096 else
1097 {
1098 #ifdef RT_USING_PAGECACHE
1099 st->st_size = (dentry->vnode && dentry->vnode->aspace) ? dentry->vnode->size : osize;
1100 #else
1101 st->st_size = osize;
1102 #endif
1103 }
1104
1105 st->st_mtime = 0;
1106
1107 return RT_EOK;
1108 }
1109
dfs_cromfs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)1110 static int dfs_cromfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
1111 {
1112 uint32_t index = 0;
1113 uint8_t *name = NULL;
1114 struct dirent *d = NULL;
1115 file_info *fi = NULL;
1116 cromfs_info *ci = NULL;
1117 cromfs_dirent_item *dirent = NULL, *sub_dirent = NULL;
1118 void *di_mem = NULL;
1119 rt_err_t result = RT_EOK;
1120
1121 fi = (file_info *)file->vnode->data;
1122 ci = fi->ci;
1123
1124 RT_ASSERT(fi->buff == NULL);
1125
1126 if (!fi->size)
1127 {
1128 return -EINVAL;
1129 }
1130
1131 dirent = (cromfs_dirent_item *)malloc(fi->size);
1132 if (!dirent)
1133 {
1134 return -ENOMEM;
1135 }
1136
1137 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
1138 if (result != RT_EOK)
1139 {
1140 free(dirent);
1141 return -EINTR;
1142 }
1143 di_mem = cromfs_dirent_cache_get(ci, fi->partition_pos, fi->size);
1144 if (di_mem)
1145 {
1146 memcpy(dirent, di_mem, fi->size);
1147 }
1148 rt_mutex_release(&ci->lock);
1149 if (!di_mem)
1150 {
1151 free(dirent);
1152 return -ENOMEM;
1153 }
1154
1155 /* make integer count */
1156 count = (count / sizeof(struct dirent));
1157 if (count == 0)
1158 {
1159 free(dirent);
1160 return -EINVAL;
1161 }
1162
1163 for (index = 0; index < count && file->fpos < file->vnode->size; index++)
1164 {
1165 uint32_t name_size = 0;
1166
1167 d = dirp + index;
1168 sub_dirent = &dirent[file->fpos >> CROMFS_ALIGN_SIZE_BIT];
1169 name = sub_dirent->dirent.name;
1170
1171 /* fill dirent */
1172 if (sub_dirent->dirent.attr == CROMFS_DIRENT_ATTR_DIR)
1173 {
1174 d->d_type = DT_DIR;
1175 }
1176 else
1177 {
1178 d->d_type = DT_REG;
1179 }
1180
1181 d->d_namlen = sub_dirent->dirent.name_size;
1182 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
1183 memcpy(d->d_name, (char *)name, sub_dirent->dirent.name_size);
1184 d->d_name[sub_dirent->dirent.name_size] = '\0';
1185
1186 name_size = (sub_dirent->dirent.name_size + CROMFS_ALIGN_SIZE_MASK) & ~CROMFS_ALIGN_SIZE_MASK;
1187 /* move to next position */
1188 file->fpos += (name_size + sizeof *sub_dirent);
1189 }
1190
1191 free(dirent);
1192
1193 return index * sizeof(struct dirent);
1194 }
1195
dfs_cromfs_lookup(struct dfs_dentry * dentry)1196 static struct dfs_vnode *dfs_cromfs_lookup (struct dfs_dentry *dentry)
1197 {
1198 struct dfs_vnode *vnode = RT_NULL;
1199 cromfs_info *ci = NULL;
1200
1201 RT_ASSERT(dentry != RT_NULL);
1202 RT_ASSERT(dentry->mnt != RT_NULL);
1203
1204 ci = (cromfs_info *)dentry->mnt->data;
1205 if (ci)
1206 {
1207 uint32_t size = 0, osize = 0;
1208 int file_type = 0;
1209 uint32_t file_pos = __dfs_cromfs_lookup(ci, dentry->pathname, &file_type, &size, &osize);
1210
1211 if (file_pos != CROMFS_POS_ERROR)
1212 {
1213 vnode = dfs_vnode_create();
1214 if (vnode)
1215 {
1216 vnode->nlink = 1;
1217
1218 if (file_type == CROMFS_DIRENT_ATTR_DIR)
1219 {
1220 vnode->mode = S_IFDIR | (0777);
1221 vnode->type = FT_DIRECTORY;
1222 vnode->size = size;
1223 }
1224 else if (file_type == CROMFS_DIRENT_ATTR_SYMLINK)
1225 {
1226 vnode->mode = S_IFLNK | (0777);
1227 vnode->type = FT_SYMLINK;
1228 vnode->size = osize;
1229 }
1230 else
1231 {
1232 vnode->mode = S_IFREG | (0777);
1233 vnode->type = FT_REGULAR;
1234 vnode->size = osize;
1235 #ifdef RT_USING_PAGECACHE
1236 vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_cromfs_aspace_ops);
1237 #endif
1238 }
1239
1240 vnode->mnt = dentry->mnt;
1241 }
1242 }
1243 }
1244
1245 return vnode;
1246 }
1247
dfs_cromfs_free_vnode(struct dfs_vnode * vnode)1248 static int dfs_cromfs_free_vnode(struct dfs_vnode *vnode)
1249 {
1250 return 0;
1251 }
1252
cromfs_readlink(cromfs_info * ci,char * path,char * buf,int len)1253 static int cromfs_readlink(cromfs_info *ci, char *path, char *buf, int len)
1254 {
1255 int ret = 0;
1256 file_info *fi = NULL;
1257 uint32_t file_pos = 0;
1258 int file_type = 0;
1259 uint32_t size = 0, osize = 0;
1260 rt_err_t result = RT_EOK;
1261
1262 file_pos = __dfs_cromfs_lookup(ci, path, &file_type, &size, &osize);
1263 if (file_pos == CROMFS_POS_ERROR)
1264 {
1265 ret = -ENOENT;
1266 goto end1;
1267 }
1268
1269 result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
1270 if (result != RT_EOK)
1271 {
1272 ret = -EINTR;
1273 goto end;
1274 }
1275
1276 fi = get_file_info(ci, file_pos, 1);
1277 if (!fi)
1278 {
1279 fi = inset_file_info(ci, file_pos, file_type, size, osize);
1280 }
1281 rt_mutex_release(&ci->lock);
1282 if (!fi)
1283 {
1284 ret = -ENOENT;
1285 goto end;
1286 }
1287
1288 if (len > 0)
1289 {
1290 RT_ASSERT(fi->size != 0);
1291 RT_ASSERT(fi->buff);
1292
1293 int fill_ret = 0;
1294 fill_ret = fill_file_data(fi);
1295 if (fill_ret < 0)
1296 {
1297 ret = -ENOENT;
1298 deref_file_info(ci, fi->partition_pos);
1299 goto end;
1300 }
1301 len = len - 1;
1302 osize = osize < len ? osize : len;
1303 memcpy(buf, fi->buff, osize);
1304 }
1305
1306 if (ret == 0)
1307 {
1308 buf[osize] = '\0';
1309 ret = osize;
1310 }
1311
1312 deref_file_info(ci, fi->partition_pos);
1313 end:
1314 rt_mutex_release(&ci->lock);
1315 end1:
1316 return ret;
1317 }
1318
1319 #ifdef RT_USING_PAGECACHE
dfs_cromfs_page_read(struct dfs_file * file,struct dfs_page * page)1320 static ssize_t dfs_cromfs_page_read(struct dfs_file *file, struct dfs_page *page)
1321 {
1322 int ret = -EINVAL;
1323
1324 if (page->page)
1325 {
1326 off_t fpos = page->fpos;
1327 ret = dfs_cromfs_read(file, page->page, page->size, &fpos);
1328 }
1329
1330 return ret;
1331 }
1332 #endif
1333
dfs_cromfs_readlink(struct dfs_dentry * dentry,char * buf,int len)1334 static int dfs_cromfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
1335 {
1336 cromfs_info *ci = NULL;
1337
1338 if (dentry && buf)
1339 {
1340 ci = (cromfs_info *)dentry->mnt->data;
1341 return cromfs_readlink(ci, dentry->pathname, buf, len);
1342 }
1343
1344 return -EBADF;
1345 }
1346
1347 static const struct dfs_file_ops _crom_fops =
1348 {
1349 .open = dfs_cromfs_open,
1350 .close = dfs_cromfs_close,
1351 .lseek = generic_dfs_lseek,
1352 .read = dfs_cromfs_read,
1353 .getdents = dfs_cromfs_getdents,
1354 };
1355
1356 static const struct dfs_filesystem_ops _cromfs_ops =
1357 {
1358 .name = "crom",
1359 .flags = 0,
1360 .default_fops = &_crom_fops,
1361 .mount = dfs_cromfs_mount,
1362 .umount = dfs_cromfs_unmount,
1363
1364 .readlink = dfs_cromfs_readlink,
1365
1366 .stat = dfs_cromfs_stat,
1367 .lookup = dfs_cromfs_lookup,
1368 .free_vnode = dfs_cromfs_free_vnode
1369 };
1370
1371 static struct dfs_filesystem_type _cromfs =
1372 {
1373 .fs_ops = &_cromfs_ops,
1374 };
1375
dfs_cromfs_init(void)1376 int dfs_cromfs_init(void)
1377 {
1378 /* register crom file system */
1379 dfs_register(&_cromfs);
1380 return 0;
1381 }
1382 INIT_COMPONENT_EXPORT(dfs_cromfs_init);
1383