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