|
|
1.1 root 1: /*
2: * /packages/grubfs-files
3: *
4: * grub vfs
5: *
6: * Copyright (C) 2004 Stefan Reinauer
7: * Copyright (C) 2004 Samuel Rydh
8: * Copyright (C) 2010 Mark Cave-Ayland
9: *
10: * inspired by HFS code from Samuel Rydh
11: *
12: * This program is free software; you can redistribute it and/or
13: * modify it under the terms of the GNU General Public License
14: * as published by the Free Software Foundation
15: *
16: */
17:
18: #include "config.h"
19: #include "libopenbios/bindings.h"
20: #include "fs/fs.h"
21: #include "filesys.h"
22: #include "glue.h"
23: #include "libc/diskio.h"
24: #include "libc/vsprintf.h"
25:
26: extern void grubfs_init( void );
27:
28: /************************************************************************/
29: /* grub GLOBALS (horrible... but difficult to fix) */
30: /************************************************************************/
31:
32: /* the grub drivers want these: */
33: int filepos;
34: int filemax;
35: grub_error_t errnum;
36: char FSYS_BUF[FSYS_BUFLEN];
37:
38: /* these are not even used by us, instead
39: * the grub fs drivers want them:
40: */
41: int fsmax;
42: void (*disk_read_hook) (int, int, int);
43: void (*disk_read_func) (int, int, int);
44:
45:
46: /************************************************************************/
47: /* filsystem table */
48: /************************************************************************/
49:
50: typedef struct fsys_entry {
51: const char *name;
52: int (*mount_func) (void);
53: int (*read_func) (char *buf, int len);
54: int (*dir_func) (char *dirname);
55: void (*close_func) (void);
56: int (*embed_func) (int *start_sector, int needed_sectors);
57: } fsys_entry_t;
58:
59: static const struct fsys_entry fsys_table[] = {
60: # ifdef CONFIG_FSYS_FAT
61: {"fat", fat_mount, fat_read, fat_dir, NULL, NULL},
62: # endif
63: # ifdef CONFIG_FSYS_EXT2FS
64: {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, NULL, NULL},
65: # endif
66: # ifdef CONFIG_FSYS_MINIX
67: {"minix", minix_mount, minix_read, minix_dir, NULL, NULL},
68: # endif
69: # ifdef CONFIG_FSYS_REISERFS
70: {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, NULL, reiserfs_embed},
71: # endif
72: # ifdef CONFIG_FSYS_JFS
73: {"jfs", jfs_mount, jfs_read, jfs_dir, NULL, jfs_embed},
74: # endif
75: # ifdef CONFIG_FSYS_XFS
76: {"xfs", xfs_mount, xfs_read, xfs_dir, NULL, NULL},
77: # endif
78: # ifdef CONFIG_FSYS_UFS
79: {"ufs", ufs_mount, ufs_read, ufs_dir, NULL, ufs_embed},
80: # endif
81: # ifdef CONFIG_FSYS_ISO9660
82: {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, NULL, NULL},
83: # endif
84: # ifdef CONFIG_FSYS_NTFS
85: {"ntfs", ntfs_mount, ntfs_read, ntfs_dir, NULL, NULL},
86: # endif
87: # ifdef CONFIG_FSYS_AFFS
88: {"affs", affs_mount, affs_read, affs_dir, NULL, NULL},
89: # endif
90: };
91:
92: /* We don't provide a file search mechanism (yet) */
93: typedef struct {
94: unsigned long pos;
95: unsigned long len;
96: const char *path;
97: } grubfile_t;
98:
99: typedef struct {
100: const struct fsys_entry *fsys;
101: grubfile_t *fd;
102: int dev_fd;
103: long long offset; /* Offset added onto each device read; should only ever be non-zero
104: when probing a partition for a filesystem */
105: } grubfs_t;
106:
107: typedef struct {
108: grubfs_t *gfs;
109: } grubfs_info_t;
110:
111: /* Static block and global pointer required for I/O glue */
112: static grubfs_t dummy_fs;
113: static grubfs_t *curfs = &dummy_fs;
114:
115: DECLARE_NODE( grubfs, 0, sizeof(grubfs_info_t), "+/packages/grubfs-files" );
116:
117:
118: /************************************************************************/
119: /* I/O glue (called by grub source) */
120: /************************************************************************/
121:
122: int
123: devread( unsigned long sector, unsigned long byte_offset,
124: unsigned long byte_len, void *buf )
125: {
126: long long offs = (long long)sector * 512 + byte_offset;
127:
128: #ifdef CONFIG_DEBUG_FS
129: //printk("devread s=%x buf=%x, fd=%x\n",sector, buf, curfs->dev_fd);
130: #endif
131:
132: if( !curfs ) {
133: #ifdef CONFIG_DEBUG_FS
134: printk("devread: fsys == NULL!\n");
135: #endif
136: return -1;
137: }
138:
139: if( seek_io(curfs->dev_fd, offs + curfs->offset) ) {
140: #ifdef CONFIG_DEBUG_FS
141: printk("seek failure\n");
142: #endif
143: return -1;
144: }
145: return (read_io(curfs->dev_fd, buf, byte_len) == byte_len) ? 1:0;
146: }
147:
148: int
149: file_read( void *buf, unsigned long len )
150: {
151: if (filepos < 0 || filepos > filemax)
152: filepos = filemax;
153: if (len > filemax-filepos)
154: len = filemax - filepos;
155: errnum = 0;
156: return curfs->fsys->read_func( buf, len );
157: }
158:
159:
160: /************************************************************************/
161: /* Standard package methods */
162: /************************************************************************/
163:
164: /* ( -- success? ) */
165: static void
166: grubfs_files_open( grubfs_info_t *mi )
167: {
168: int fd, i;
169: char *path = my_args_copy();
170: char *s;
171:
172: fd = open_ih( my_parent() );
173: if ( fd == -1 ) {
174: free( path );
175: RET( 0 );
176: }
177:
178: mi->gfs = &dummy_fs;
179:
180: for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
181: #ifdef CONFIG_DEBUG_FS
182: printk("Trying %s\n", fsys_table[i].name);
183: #endif
184: if (fsys_table[i].mount_func()) {
185: const fsys_entry_t *fsys = &fsys_table[i];
186: #ifdef CONFIG_DEBUG_FS
187: printk("Mounted %s\n", fsys->name);
188: #endif
189: mi->gfs = malloc(sizeof(grubfs_t));
190: mi->gfs->fsys = fsys;
191: mi->gfs->dev_fd = fd;
192: mi->gfs->offset = 0;
193:
194: s = path;
195: while (*s) {
196: if(*s=='\\') *s='/';
197: s++;
198: }
199: #ifdef CONFIG_DEBUG_FS
200: printk("Path=%s\n",path);
201: #endif
202: if (!mi->gfs->fsys->dir_func((char *) path)) {
203: forth_printf("File not found\n");
204: RET( 0 );
205: }
206:
207: mi->gfs->fd = malloc(sizeof(grubfile_t));
208: mi->gfs->fd->pos = filepos;
209: mi->gfs->fd->len = filemax;
210: mi->gfs->fd->path = strdup(path);
211:
212: RET( -1 );
213: }
214: }
215: #ifdef CONFIG_DEBUG_FS
216: printk("Unknown filesystem type\n");
217: #endif
218:
219: RET( 0 );
220: }
221:
222: /* ( -- ) */
223: static void
224: grubfs_files_close( grubfs_info_t *mi )
225: {
226: grubfile_t *gf = mi->gfs->fd;
227:
228: if (gf->path)
229: free((void *)(gf->path));
230: free(gf);
231:
232: filepos = 0;
233: filemax = 0;
234: }
235:
236: /* ( buf len -- actlen ) */
237: static void
238: grubfs_files_read( grubfs_info_t *mi )
239: {
240: int count = POP();
241: char *buf = (char *)cell2pointer(POP());
242:
243: grubfile_t *file = mi->gfs->fd;
244: int ret;
245:
246: filepos = file->pos;
247: filemax = file->len;
248:
249: if (count > filemax - filepos)
250: count = filemax - filepos;
251:
252: ret = mi->gfs->fsys->read_func(buf, count);
253:
254: file->pos = filepos;
255:
256: RET( ret );
257: }
258:
259: /* ( pos.d -- status ) */
260: static void
261: grubfs_files_seek( grubfs_info_t *mi )
262: {
263: long long pos = DPOP();
264: int offs = (int)pos;
265: int whence = SEEK_SET;
266:
267: grubfile_t *file = mi->gfs->fd;
268: unsigned long newpos;
269:
270: switch( whence ) {
271: case SEEK_END:
272: if (offs < 0 && (unsigned long) -offs > file->len)
273: newpos = 0;
274: else
275: newpos = file->len + offs;
276: break;
277: default:
278: case SEEK_SET:
279: newpos = (offs < 0) ? 0 : offs;
280: break;
281: }
282:
283: if (newpos > file->len)
284: newpos = file->len;
285:
286: file->pos = newpos;
287:
288: if (newpos)
289: RET( -1 );
290: else
291: RET( 0 );
292: }
293:
294: /* ( addr -- size ) */
295: static void
296: grubfs_files_load( grubfs_info_t *mi )
297: {
298: char *buf = (char *)cell2pointer(POP());
299: int count, ret;
300:
301: grubfile_t *file = mi->gfs->fd;
302: count = file->len;
303:
304: ret = mi->gfs->fsys->read_func(buf, count);
305: file->pos = filepos;
306:
307: RET( ret );
308: }
309:
310: /* ( -- cstr ) */
311: static void
312: grubfs_files_get_path( grubfs_info_t *mi )
313: {
314: grubfile_t *file = mi->gfs->fd;
315: const char *path = file->path;
316:
317: RET( pointer2cell(strdup(path)) );
318: }
319:
320: /* ( -- cstr ) */
321: static void
322: grubfs_files_get_fstype( grubfs_info_t *mi )
323: {
324: grubfs_t *gfs = mi->gfs;
325:
326: PUSH( pointer2cell(strdup(gfs->fsys->name)) );
327: }
328:
329:
330: /* static method, ( pos.d ih -- flag? ) */
331: static void
332: grubfs_files_probe( grubfs_info_t *dummy )
333: {
334: ihandle_t ih = POP_ih();
335: long long offs = DPOP();
336: int i;
337:
338: curfs->dev_fd = open_ih(ih);
339: if (curfs->dev_fd == -1) {
340: RET( -1 );
341: }
342: curfs->offset = offs;
343:
344: for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
345: #ifdef CONFIG_DEBUG_FS
346: printk("Probing for %s\n", fsys_table[i].name);
347: #endif
348: if (fsys_table[i].mount_func()) {
349: RET( -1 );
350: }
351: }
352:
353: #ifdef CONFIG_DEBUG_FS
354: printk("Unknown filesystem type\n");
355: #endif
356:
357: close_io(curfs->dev_fd);
358:
359: RET ( 0 );
360: }
361:
362: /* static method, ( pathstr len ihandle -- ) */
363: static void
364: grubfs_files_dir( grubfs_info_t *dummy )
365: {
366: forth_printf("dir method not implemented for grubfs filesystem\n");
367: POP();
368: POP();
369: POP();
370: }
371:
372: static void
373: grubfs_initializer( grubfs_info_t *dummy )
374: {
375: fword("register-fs-package");
376: }
377:
378: NODE_METHODS( grubfs ) = {
379: { "probe", grubfs_files_probe },
380: { "open", grubfs_files_open },
381: { "close", grubfs_files_close },
382: { "read", grubfs_files_read },
383: { "seek", grubfs_files_seek },
384: { "load", grubfs_files_load },
385: { "dir", grubfs_files_dir },
386:
387: /* special */
388: { "get-path", grubfs_files_get_path },
389: { "get-fstype", grubfs_files_get_fstype },
390:
391: { NULL, grubfs_initializer },
392: };
393:
394: void
395: grubfs_init( void )
396: {
397: REGISTER_NODE( grubfs );
398: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.