Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / grubfs / grubfs_fs.c
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 }