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