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