• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/romfs/fs_romfs.c
3  *
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.  The
7  * ASF licenses this file to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance with the
9  * License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
16  * License for the specific language governing permissions and limitations
17  * under the License.
18  *
19  ****************************************************************************/
20 
21 /****************************************************************************
22  * Included Files
23  ****************************************************************************/
24 
25 #include <sys/types.h>
26 #include <sys/statfs.h>
27 #include <sys/stat.h>
28 
29 #include <stdint.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <assert.h>
37 #include <errno.h>
38 
39 #include "fs_romfs.h"
40 
41 #include "los_tables.h"
42 #include "user_copy.h"
43 #include "los_vm_filemap.h"
44 
45 #ifdef LOSCFG_FS_ROMFS
46 
47 /* forward define */
48 struct VnodeOps g_romfsVops;
49 struct file_operations_vfs g_romfsFops;
50 
51 /****************************************************************************
52  * Name: romfs_lookup
53  ****************************************************************************/
54 
romfs_lookup(struct Vnode * parentVnode,const char * path,int len,struct Vnode ** ppVnode)55 int romfs_lookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **ppVnode)
56 {
57   int ret;
58   struct Vnode *newVnode = NULL;
59   struct romfs_dirinfo_s *dirinfo = NULL;
60   struct romfs_dirinfo_s *parent_dirinfo = NULL;
61   struct romfs_mountpt_s *rm = NULL;
62   struct romfs_file_s    *rf = NULL;
63 
64   /* Get mountpoint private data from the inode reference from the file
65    * structure
66    */
67 
68   rm = (struct romfs_mountpt_s *)parentVnode->originMount->data;
69 
70   /* Check if the mount is still healthy */
71 
72   romfs_semtake(rm);
73   ret = romfs_checkmount(rm);
74   if (ret != OK)
75     {
76       PRINTK("ERROR: romfs_checkmount failed: %d\n", ret);
77       goto errout_with_semaphore;
78     }
79 
80   parent_dirinfo = (struct romfs_dirinfo_s *)parentVnode->data;
81   /* Initialize the directory info structure */
82 
83   dirinfo = (struct romfs_dirinfo_s *)zalloc(sizeof(struct romfs_dirinfo_s));
84   if (!dirinfo)
85     {
86       ret = -ENOMEM;
87       PRINTK("ERROR: Failed to allocate dirinfo structure, error: %d\n", -ret);
88       goto errout_with_semaphore;
89     }
90 
91   /* Locate the directory entry for this path */
92 
93   ret = romfs_searchdir(rm, path, len, parent_dirinfo->rd_dir.fr_firstoffset, dirinfo);
94   if (ret < 0)
95     {
96       goto errout_with_semaphore;
97     }
98 
99   /* The full path exists -- but is the final component a file
100    * or a directory?  Or some other Unix file type that is not
101    * appropriate in this contex.
102    *
103    * REVISIT: This logic should follow hard/soft link file
104    * types.  At present, it returns the ENXIO.
105    */
106 
107   if (!IS_DIRECTORY(dirinfo->rd_next) && !IS_FILE(dirinfo->rd_next))
108     {
109       /* ENXIO indicates "The named file is a character special or
110        * block special file, and the device associated with this
111        * special file does not exist."
112        *
113        * Here we also return ENXIO if the file is not a directory
114        * or a regular file.
115        */
116 
117       ret = -ENXIO;
118       PRINTK("ERROR: '%s' is a special file\n", path);
119       goto errout_with_semaphore;
120     }
121 
122   if (IS_DIRECTORY(dirinfo->rd_next))
123     {
124       ret = VnodeAlloc(&g_romfsVops, &newVnode);
125       if (ret != 0)
126         {
127           PRINTK("%s-%d: can't alloc vnode, error: %d\n", __FUNCTION__, __LINE__, ret);
128           goto errout_with_semaphore;
129         }
130       newVnode->type   = VNODE_TYPE_DIR;
131       newVnode->parent = parentVnode;
132       newVnode->fop    = &g_romfsFops;
133       newVnode->data   = dirinfo;
134       newVnode->originMount = parentVnode->originMount;
135       newVnode->uid    = parentVnode->uid;
136       newVnode->gid    = parentVnode->gid;
137       newVnode->mode   = parentVnode->mode | (S_IFDIR | S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP |
138                      S_IRUSR | S_IXUSR);
139     }
140   else
141     {
142       rf = (struct romfs_file_s *)zalloc(sizeof(struct romfs_file_s));
143       if (!rf)
144         {
145           ret = -ENOMEM;
146           PRINTK("ERROR: Failed to allocate private data: %d\n", ret);
147           goto errout_with_semaphore;
148         }
149 
150       /* Initialize the file private data (only need to initialize
151       * non-zero elements)
152       */
153 
154       rf->rf_size = dirinfo->rd_size;
155       rf->rf_type = (uint8_t)(dirinfo->rd_next & RFNEXT_ALLMODEMASK);
156 
157       /* Get the start of the file data */
158 
159       ret = romfs_datastart(rm, dirinfo->rd_dir.fr_curroffset,
160                             &rf->rf_startoffset);
161       if (ret < 0)
162         {
163           PRINTK("ERROR: Failed to locate start of file data: %d\n", ret);
164           goto errout_with_mem;
165         }
166 
167       /* Then insert the new instance into the mountpoint structure.
168       * It needs to be there (1) to handle error conditions that effect
169       * all files, and (2) to inform the umount logic that we are busy
170       * (but a simple reference count could have done that).
171       */
172 
173       rf->rf_next = rm->rm_head;
174       rm->rm_head = rf->rf_next;
175 
176       ret = VnodeAlloc(&g_romfsVops, &newVnode);
177       if (ret != 0)
178         {
179           PRINTK("%s-%d: can't alloc vnode, error: %d\n", __FUNCTION__, __LINE__, ret);
180           goto errout_with_mem;
181         }
182 
183       newVnode->originMount = parentVnode->originMount;
184       newVnode->type   = VNODE_TYPE_REG;
185       newVnode->parent = parentVnode;
186       newVnode->fop    = &g_romfsFops;
187       newVnode->data   = rf;
188       newVnode->uid    = parentVnode->uid;
189       newVnode->gid    = parentVnode->gid;
190       newVnode->mode   = S_IFREG | S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRUSR | S_IXUSR;
191 
192       free(dirinfo);
193     }
194 
195   *ppVnode = newVnode;
196 
197   romfs_semgive(rm);
198   return OK;
199 
200   /* Error exits */
201 
202 errout_with_mem:
203   free(rf);
204 
205 errout_with_semaphore:
206   romfs_semgive(rm);
207   return ret;
208 }
209 
210 /****************************************************************************
211  * Name: romfs_close
212  ****************************************************************************/
213 
romfs_close(struct file * filep)214 int romfs_close(struct file *filep)
215 {
216   return 0;
217 }
218 
romfs_reclaim(struct Vnode * vp)219 int romfs_reclaim(struct Vnode *vp)
220 {
221   struct romfs_file_s *rf = vp->data;
222   if (rf->rf_buffer)
223     {
224       free(rf->rf_buffer);
225     }
226 
227   /* Then free the file structure itself. */
228 
229   free(rf);
230   vp->data = NULL;
231 
232   return 0;
233 }
234 
235 /****************************************************************************
236  * Name: romfs_read
237  ****************************************************************************/
238 
romfs_read(struct file * filep,char * buffer,size_t buflen)239 static ssize_t romfs_read(struct file *filep, char *buffer,
240                           size_t buflen)
241 {
242   struct romfs_mountpt_s *rm = NULL;
243   struct romfs_file_s    *rf = NULL;
244   uint32_t                    offset;
245   size_t                      bytesleft;
246   int                         ret;
247 
248   /* Recover our private data from the struct file instance */
249 
250   rf = (struct romfs_file_s *)filep->f_vnode->data;
251   rm = (struct romfs_mountpt_s *)filep->f_vnode->originMount->data;
252 
253   /* Make sure that the mount is still healthy */
254 
255   romfs_semtake(rm);
256   ret = romfs_checkmount(rm);
257   if (ret != OK)
258     {
259       PRINTK("ERROR: romfs_checkmount failed: %d\n", ret);
260       goto errout_with_semaphore;
261     }
262 
263   /* Get the number of bytes left in the file */
264 
265   bytesleft = rf->rf_size - filep->f_pos;
266 
267   /* Truncate read count so that it does not exceed the number
268    * of bytes left in the file.
269    */
270 
271   if (buflen > bytesleft)
272     {
273       buflen = bytesleft;
274     }
275 
276   offset = rf->rf_startoffset + filep->f_pos;
277   LOS_CopyFromKernel(buffer, buflen, &rm->rm_buffer[offset], buflen);
278   filep->f_pos += buflen;
279 
280   romfs_semgive(rm);
281   return buflen;
282 
283 errout_with_semaphore:
284   romfs_semgive(rm);
285   return ret;
286 }
287 
288 /****************************************************************************
289  * Name: romfs_readpage
290  ****************************************************************************/
291 
romfs_readpage(struct Vnode * vnode,char * buffer,off_t off)292 static ssize_t romfs_readpage(struct Vnode *vnode, char *buffer, off_t off)
293 {
294   size_t    bytesleft;
295   int       ret = 0;
296   int       buflen = PAGE_SIZE;
297   struct romfs_mountpt_s *rm = NULL;
298   struct romfs_file_s    *rf = NULL;
299 
300   /* Recover our private data from the struct file instance */
301 
302   rf = (struct romfs_file_s *)vnode->data;
303   rm = (struct romfs_mountpt_s *)vnode->originMount->data;
304 
305   /* Make sure that the mount is still healthy */
306 
307   romfs_semtake(rm);
308   ret = romfs_checkmount(rm);
309   if (ret != OK)
310     {
311       PRINTK("ERROR: romfs_checkmount failed: %d\n", ret);
312       goto errout_with_semaphore;
313     }
314 
315   if (off >= rf->rf_size)
316     {
317       ret = -ERANGE;
318       PRINTK("ERROR: readpage out of range, ret: %d.\n", ret);
319       goto errout_with_semaphore;
320     }
321 
322   /* Get the number of bytes left in the file */
323 
324   bytesleft = rf->rf_size - off;
325 
326   /* Truncate read count so that it does not exceed the number
327    * of bytes left in the file.
328    */
329 
330   if (buflen > bytesleft)
331     {
332       buflen = bytesleft;
333     }
334 
335   off = rf->rf_startoffset + off;
336   LOS_CopyFromKernel(buffer, buflen, &rm->rm_buffer[off], buflen);
337 
338   romfs_semgive(rm);
339   return buflen;
340 
341 errout_with_semaphore:
342   romfs_semgive(rm);
343   return ret;
344 }
345 
346 /****************************************************************************
347  * Name: romfs_seek
348  ****************************************************************************/
349 
romfs_seek(struct file * filep,off_t offset,int whence)350 off_t romfs_seek(struct file *filep, off_t offset, int whence)
351 {
352   struct romfs_file_s    *rf = NULL;
353   loff_t                 position;
354 
355   /* Recover our private data from the struct file instance */
356 
357   rf = (struct romfs_file_s *)filep->f_vnode->data;
358   position = filep->f_pos;
359 
360   /* Map the offset according to the whence option */
361 
362   switch (whence)
363     {
364     case SEEK_SET: /* The offset is set to offset bytes. */
365         position = offset;
366         break;
367 
368     case SEEK_CUR: /* The offset is set to its current location plus
369                     * offset bytes. */
370 
371         position += offset;
372         break;
373 
374     case SEEK_END: /* The offset is set to the size of the file plus
375                     * offset bytes. */
376 
377         position = offset + rf->rf_size;
378         break;
379 
380     default:
381         PRINTK("ERROR: Whence is invalid: %d\n", whence);
382         return -EINVAL;
383     }
384 
385   /* Limit positions to the end of the file. */
386 
387   if (position > rf->rf_size)
388     {
389       /* Otherwise, the position is limited to the file size */
390 
391       position = rf->rf_size;
392     }
393 
394   if (position < 0)
395     {
396       return -EINVAL;
397     }
398   return position;
399 }
400 
401 /****************************************************************************
402  * Name: romfs_seek64
403  ****************************************************************************/
404 
romfs_seek64(struct file * filep,loff_t offset,int whence)405 loff_t romfs_seek64(struct file *filep, loff_t offset, int whence)
406 {
407   return (loff_t)romfs_seek(filep, (off_t)offset, whence);
408 }
409 
410 /****************************************************************************
411  * Name: romfs_ioctl
412  ****************************************************************************/
413 
romfs_ioctl(struct file * filep,int cmd,unsigned long arg)414 static int romfs_ioctl(struct file *filep, int cmd, unsigned long arg)
415 {
416   return -ENOSYS;
417 }
418 
419 /****************************************************************************
420  * Name: romfs_opendir
421  *
422  * Description:
423  *   Open a directory for read access
424  *
425  ****************************************************************************/
426 
romfs_opendir(struct Vnode * vp,struct fs_dirent_s * dir)427 int romfs_opendir(struct Vnode *vp, struct fs_dirent_s *dir)
428 {
429   int ret;
430   struct romfs_mountpt_s *rm = NULL;
431   struct romfs_dirinfo_s *dirinfo = NULL;
432   struct fs_romfsdir_s   *ptr = NULL;
433 
434   /* Recover our private data from the vnode instance */
435 
436   rm = (struct romfs_mountpt_s *)vp->originMount->data;
437 
438   /* Make sure that the mount is still healthy */
439 
440   romfs_semtake(rm);
441   ret = romfs_checkmount(rm);
442   if (ret != OK)
443     {
444       PRINTK("ERROR: romfs_checkmount failed: %d\n", ret);
445       goto errout_with_semaphore;
446     }
447 
448   ptr = (struct fs_romfsdir_s *)zalloc(sizeof(struct fs_romfsdir_s));
449   if (ptr == NULL)
450     {
451       ret = -ENOMEM;
452       PRINTK("ERROR: zalloc error for romfsdir. error: %d\n", ret);
453       goto errout_with_semaphore;
454     }
455 
456   dirinfo = (struct romfs_dirinfo_s *)vp->data;
457   memcpy(ptr, &dirinfo->rd_dir, sizeof(struct fs_romfsdir_s));
458   dir->u.fs_dir = (fs_dir_s *)ptr;
459 
460   romfs_semgive(rm);
461   return OK;
462 
463 errout_with_semaphore:
464   romfs_semgive(rm);
465   return ret;
466 }
467 
468 /****************************************************************************
469  * Name: romfs_closedir
470  *
471  * Description:
472  *   Close a directory for read access
473  *
474  ****************************************************************************/
475 
romfs_closedir(struct Vnode * vp,struct fs_dirent_s * dir)476 int romfs_closedir(struct Vnode *vp, struct fs_dirent_s *dir)
477 {
478   struct fs_romfsdir_s *ptr = NULL;
479 
480   ptr = (struct fs_romfsdir_s *)dir->u.fs_dir;
481   if (ptr == NULL)
482     {
483       PRINTK("ERROR: romfs_closedir failed, fs_romfsdir_s is NULL.\n");
484       return -EINVAL;
485     }
486   free(ptr);
487   dir->u.fs_dir = NULL;
488   return 0;
489 }
490 
491 /****************************************************************************
492  * Name: romfs_readdir
493  *
494  * Description: Read the next directory entry
495  *
496  ****************************************************************************/
497 
romfs_readdir(struct Vnode * vp,struct fs_dirent_s * dir)498 static int romfs_readdir(struct Vnode *vp, struct fs_dirent_s *dir)
499 {
500   struct romfs_mountpt_s *rm = NULL;
501   struct fs_romfsdir_s   *romfsdir = NULL;
502   uint32_t                    linkoffset;
503   uint32_t                    next;
504   uint32_t                    info;
505   uint32_t                    size;
506   int                         ret;
507   int                         i = 0;
508 
509   /* Recover our private data from the vnode instance */
510 
511   rm = (struct romfs_mountpt_s *)vp->originMount->data;
512 
513   /* Make sure that the mount is still healthy */
514 
515   romfs_semtake(rm);
516   ret = romfs_checkmount(rm);
517   if (ret != OK)
518     {
519       PRINTK("ERROR: omfs_checkmount failed: %d\n", ret);
520       goto errout_with_semaphore;
521     }
522 
523   romfsdir = (struct fs_romfsdir_s *)dir->u.fs_dir;
524   /* Loop, skipping over unsupported items in the file system */
525 
526   while (i < dir->read_cnt)
527     {
528       /* Have we reached the end of the directory */
529 
530       if (!romfsdir->fr_curroffset)
531         {
532           /* We signal the end of the directory by returning the
533            * special error -ENOENT
534            */
535 
536           ret = -ENOENT;
537           break;
538         }
539 
540       /* Parse the directory entry */
541 
542       ret = romfs_parsedirentry(rm, romfsdir->fr_curroffset, &linkoffset,
543                                 &next, &info, &size);
544       if (ret < 0)
545         {
546           PRINTK("ERROR: romfs_parsedirentry failed: %d\n", ret);
547           goto errout_with_semaphore;
548         }
549 
550       /* Save the filename */
551 
552       ret = romfs_parsefilename(rm, (uint32_t)romfsdir->fr_curroffset, dir->fd_dir[i].d_name);
553       if (ret < 0)
554         {
555           PRINTK("ERROR: romfs_parsefilename failed: %d\n", ret);
556           goto errout_with_semaphore;
557         }
558 
559       /* Set up the next directory entry offset */
560 
561       romfsdir->fr_curroffset = (off_t)next & RFNEXT_OFFSETMASK;
562 
563       if (!strcmp(dir->fd_dir[i].d_name, ".") || !strcmp(dir->fd_dir[i].d_name, ".."))
564         {
565           continue;
566         }
567 
568       /* Check the file type */
569 
570       if (IS_DIRECTORY(next))
571         {
572           dir->fd_dir[i].d_type = DT_DIR;
573         }
574       else if (IS_FILE(next))
575         {
576           dir->fd_dir[i].d_type = DT_REG;
577         }
578 
579       dir->fd_position++;
580       dir->fd_dir[i].d_off = dir->fd_position;
581       dir->fd_dir[i].d_reclen = (uint16_t)sizeof(struct dirent);
582 
583       i++;
584     }
585   romfs_semgive(rm);
586   return i;
587 
588 errout_with_semaphore:
589   romfs_semgive(rm);
590   return ret;
591 }
592 
593 /****************************************************************************
594  * Name: romfs_rewindir
595  *
596  * Description: Reset directory read to the first entry
597  *
598  ****************************************************************************/
599 
romfs_rewinddir(struct Vnode * vp,struct fs_dirent_s * dir)600 static int romfs_rewinddir(struct Vnode *vp, struct fs_dirent_s *dir)
601 {
602   int ret;
603   struct romfs_mountpt_s *rm = NULL;
604   struct fs_romfsdir_s   *romfsdir = NULL;
605 
606   /* Recover our private data from the vnode instance */
607 
608   rm = (struct romfs_mountpt_s *)vp->originMount->data;
609 
610   /* Make sure that the mount is still healthy */
611 
612   romfs_semtake(rm);
613   ret = romfs_checkmount(rm);
614   if (ret == OK)
615     {
616       romfsdir = (struct fs_romfsdir_s *)dir->u.fs_dir;
617       romfsdir->fr_curroffset = romfsdir->fr_firstoffset;
618     }
619 
620   romfs_semgive(rm);
621   return ret;
622 }
623 
624 /****************************************************************************
625  * Name: romfs_bind
626  *
627  * Description: This implements a portion of the mount operation. This
628  *  function allocates and initializes the mountpoint private data and
629  *  binds the blockdriver inode to the filesystem private data.  The final
630  *  binding of the private data (containing the blockdriver) to the
631  *  mountpoint is performed by mount().
632  *
633  ****************************************************************************/
634 
romfs_bind(struct Mount * mnt,struct Vnode * blkDriver,const void * data)635 int romfs_bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
636 {
637   struct romfs_mountpt_s *rm = NULL;
638   struct romfs_dirinfo_s *dirinfo = NULL;
639   struct Vnode *pv = NULL;
640   int ret;
641 
642   rm = (struct romfs_mountpt_s *)zalloc(sizeof(struct romfs_mountpt_s));
643   if (!rm)
644     {
645       PRINTK("ERROR: Failed to allocate mountpoint structure, error: %d\n", -ENOMEM);
646       return -ENOMEM;
647     }
648 
649   /* Initialize the allocated mountpt state structure.  The filesystem is
650    * responsible for one reference ont the blkdriver inode and does not
651    * have to addref() here (but does have to release in ubind().
652    */
653 
654   (void)sem_init(&rm->rm_sem, 0, 0);   /* Initialize the semaphore that controls access */
655 
656   /* Get the hardware configuration and setup buffering appropriately */
657 
658   rm->rm_buffer = (uint8_t *)data;
659   ret = romfs_hwconfigure(rm);
660   if (ret)
661     {
662       PRINTK("ERROR: romfs_hwconfigure failed: %d\n", ret);
663       goto errout_with_sem;
664     }
665 
666   /* Then complete the mount by getting the ROMFS configuratrion from
667    * the ROMF header
668    */
669 
670   ret = romfs_fsconfigure(rm);
671   if (ret < 0)
672     {
673       PRINTK("ERROR: romfs_fsconfigure failed: %d\n", ret);
674       goto errout_with_buffer;
675     }
676 
677   dirinfo = (struct romfs_dirinfo_s *)zalloc(sizeof(struct romfs_dirinfo_s));
678   if (!dirinfo)
679     {
680       PRINTK("ERROR: Failed to allocate dirinfo structure, error: %d\n", -ENOMEM);
681       goto errout_with_buffer;
682     }
683 
684   dirinfo->rd_dir.fr_firstoffset = rm->rm_rootoffset;
685   dirinfo->rd_dir.fr_curroffset  = rm->rm_rootoffset;
686   dirinfo->rd_next               = RFNEXT_DIRECTORY;
687   dirinfo->rd_size               = 0;
688 
689   /* Mounted! */
690 
691   ret = VnodeAlloc(&g_romfsVops, &pv);
692   if (ret)
693     {
694       goto errout_with_dirinfo;
695     }
696 
697   pv->type = VNODE_TYPE_DIR;
698   pv->data = dirinfo;
699   pv->originMount = mnt;
700   pv->fop = &g_romfsFops;
701   pv->uid = mnt->vnodeBeCovered->uid;
702   pv->gid = mnt->vnodeBeCovered->gid;
703   pv->mode = S_IFDIR | S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRUSR | S_IXUSR;
704   mnt->data = rm;
705   mnt->vnodeCovered = pv;
706 
707   romfs_semgive(rm);
708   return OK;
709 
710 errout_with_dirinfo:
711   free(dirinfo);
712 
713 errout_with_buffer:
714   free(rm->rm_buffer);
715 
716 errout_with_sem:
717   (void)sem_destroy(&rm->rm_sem);
718   free(rm);
719   return ret;
720 }
721 
722 /****************************************************************************
723  * Name: romfs_unbind
724  *
725  * Description: This implements the filesystem portion of the umount
726  *   operation.
727  *
728  ****************************************************************************/
729 
romfs_unbind(struct Mount * mnt,struct Vnode ** blkDriver)730 static int romfs_unbind(struct Mount *mnt, struct Vnode **blkDriver)
731 {
732   struct romfs_mountpt_s *rm = (struct romfs_mountpt_s *)mnt->data;
733 
734   if (!rm)
735     {
736       return -EINVAL;
737     }
738 
739   /* VFS can assure the mountpoint can be umounted. */
740 
741   romfs_semtake(rm);
742   /* Release the mountpoint private data */
743 
744   if (rm->rm_buffer)
745     {
746       free(rm->rm_buffer);
747     }
748 
749   (void)sem_destroy(&rm->rm_sem);
750   free(rm);
751   return OK;
752 }
753 
754 /****************************************************************************
755  * Name: romfs_statfs
756  *
757  * Description: Return filesystem statistics
758  *
759  ****************************************************************************/
760 
romfs_statfs(struct Mount * mnt,struct statfs * buf)761 static int romfs_statfs(struct Mount *mnt, struct statfs *buf)
762 {
763   struct romfs_mountpt_s *rm;
764   int ret;
765 
766   rm = (struct romfs_mountpt_s *)mnt->data;
767 
768   /* Check if the mount is still healthy */
769 
770   romfs_semtake(rm);
771   ret = romfs_checkmount(rm);
772   if (ret < 0)
773     {
774       PRINTK("ERROR: romfs_checkmount failed: %d\n", ret);
775       goto errout_with_semaphore;
776     }
777 
778   /* Fill in the statfs info */
779 
780   memset(buf, 0, sizeof(struct statfs));
781   buf->f_type    = ROMFS_MAGIC;
782 
783   /* We will claim that the optimal transfer size is the size of one sector */
784 
785   buf->f_bsize   = rm->rm_hwsectorsize;
786 
787   /* Everything else follows in units of sectors */
788 
789   buf->f_blocks  = SEC_NSECTORS(rm, rm->rm_volsize + SEC_NDXMASK(rm));
790   buf->f_bfree   = 0;
791   buf->f_bavail  = rm->rm_volsize;
792   buf->f_namelen = NAME_MAX;
793 
794   romfs_semgive(rm);
795   return OK;
796 
797 errout_with_semaphore:
798   romfs_semgive(rm);
799   return ret;
800 }
801 
802 /****************************************************************************
803  * Name: romfs_stat
804  *
805  * Description: Return information about a file or directory
806  *
807  ****************************************************************************/
808 
romfs_stat(struct Vnode * vp,struct stat * buf)809 static int romfs_stat(struct Vnode *vp, struct stat *buf)
810 {
811   struct romfs_mountpt_s *rm = NULL;
812   struct romfs_dirinfo_s *dirinfo = NULL;
813   struct romfs_file_s    *rf = NULL;
814   int ret;
815 
816   rm = (struct romfs_mountpt_s *)vp->originMount->data;
817 
818   /* Check if the mount is still healthy */
819 
820   romfs_semtake(rm);
821   ret = romfs_checkmount(rm);
822   if (ret != OK)
823     {
824       PRINTK("ERROR: romfs_checkmount failed: %d\n", ret);
825       goto errout_with_semaphore;
826     }
827 
828   if (vp->type == VNODE_TYPE_DIR)
829     {
830       dirinfo = (struct romfs_dirinfo_s *)vp->data;
831       buf->st_mode = vp->mode;
832       buf->st_size = dirinfo->rd_size;
833     }
834   else if (vp->type == VNODE_TYPE_REG)
835     {
836       rf = (struct romfs_file_s *)vp->data;
837       buf->st_mode = vp->mode;
838       buf->st_size = rf->rf_size;
839     }
840   else
841     {
842       PRINTK("ERROR: Unsupported file type: %d\n", vp->type);
843       ret = -EINVAL;
844       goto errout_with_semaphore;
845     }
846 
847   buf->st_blksize = rm->rm_hwsectorsize;
848   buf->st_dev     = 0;
849   buf->st_ino     = 0;
850   buf->st_nlink   = 0;
851   buf->st_uid     = vp->uid;
852   buf->st_gid     = vp->gid;
853   buf->st_atime   = 0;
854   buf->st_mtime   = 0;
855   buf->st_ctime   = 0;
856 
857 errout_with_semaphore:
858   romfs_semgive(rm);
859   return ret;
860 }
861 
862 const struct MountOps romfs_operations =
863 {
864   .Mount = romfs_bind,
865   .Unmount = romfs_unbind,
866   .Statfs = romfs_statfs,
867 };
868 
869 struct VnodeOps g_romfsVops =
870 {
871   .Lookup = romfs_lookup,
872   .Create = NULL,
873   .ReadPage = romfs_readpage,
874   .WritePage = NULL,
875   .Rename = NULL,
876   .Mkdir = NULL,
877   .Getattr = romfs_stat,
878   .Opendir = romfs_opendir,
879   .Readdir = romfs_readdir,
880   .Closedir = romfs_closedir,
881   .Rewinddir = romfs_rewinddir,
882   .Unlink = NULL,
883   .Rmdir = NULL,
884   .Chattr = NULL,
885   .Reclaim = romfs_reclaim,
886   .Truncate = NULL,
887   .Truncate64 = NULL,
888 };
889 
890 struct file_operations_vfs g_romfsFops =
891 {
892   .read = romfs_read,
893   .write = NULL,
894   .mmap = OsVfsFileMmap,
895   .seek = romfs_seek,
896   .ioctl = romfs_ioctl,
897   .close = romfs_close,
898   .fsync = NULL,
899 };
900 
901 FSMAP_ENTRY(romfs_fsmap, "romfs", romfs_operations, FALSE, FALSE);
902 
903 #endif
904