Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / ext2 / ext2_fs.c
1 /*
2  *      /packages/ext2-files 
3  *
4  * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info>
5  * (c) 2010 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
6  *
7  * This file has been copied from EMILE, http://emile.sf.net
8  *
9  */
10
11 #include "config.h"
12 #include "libopenbios/bindings.h"
13 #include "libext2.h"
14 #include "ext2_utils.h"
15 #include "fs/fs.h"
16 #include "libc/vsprintf.h"
17 #include "libc/diskio.h"
18
19 extern void     ext2_init( void );
20
21 typedef struct {
22         enum { FILE, DIR } type;
23         union {
24                 ext2_FILE *file;
25                 ext2_DIR *dir;
26         };
27 } ext2_COMMON;
28
29 typedef struct {
30         ext2_VOLUME *volume;
31         ext2_COMMON *common;
32 } ext2_info_t;
33
34 DECLARE_NODE( ext2, 0, sizeof(ext2_info_t), "+/packages/ext2-files" );
35
36
37 static const int days_month[12] =
38         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
39 static const int days_month_leap[12] =
40         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
41
42 static inline int is_leap(int year)
43 {
44         return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
45 }
46
47 static void
48 print_date(time_t sec)
49 {
50         unsigned int second, minute, hour, month, day, year;
51         int current;
52         const int *days;
53
54         second = sec % 60;
55         sec /= 60;
56
57         minute = sec % 60;
58         sec /= 60;
59
60         hour = sec % 24;
61         sec /= 24;
62
63         year = sec * 100 / 36525;
64         sec -= year * 36525 / 100;
65         year += 1970;
66
67         days = is_leap(year) ?  days_month_leap : days_month;
68
69         current = 0;
70         month = 0;
71         while (month < 12) {
72                 if (sec <= current + days[month]) {
73                         break;
74                 }
75                 current += days[month];
76                 month++;
77         }
78         month++;
79
80         day = sec - current + 1;
81
82         forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
83                      year, month, day, hour, minute, second);
84 }
85
86
87 /************************************************************************/
88 /*      Standard package methods                                        */
89 /************************************************************************/
90
91 /* ( -- success? ) */
92 static void
93 ext2_files_open( ext2_info_t *mi )
94 {
95         int fd;
96         char *path = my_args_copy();
97
98         fd = open_ih( my_parent() );
99         if ( fd == -1 ) {
100                 free( path );
101                 RET( 0 );
102         }
103
104         mi->volume = ext2_mount(fd);
105         if (!mi->volume) {
106                 RET( 0 );
107         }
108
109         mi->common = (ext2_COMMON*)malloc(sizeof(ext2_COMMON));
110         if (mi->common == NULL)
111                 RET( 0 );
112
113         mi->common->dir = ext2_opendir(mi->volume, path);
114         if (mi->common->dir == NULL) {
115                 mi->common->file = ext2_open(mi->volume, path);
116                 if (mi->common->file == NULL) {
117                         free(mi->common);
118                         RET( 0 );
119                 }
120                 mi->common->type = FILE;
121                 RET( -1 );
122         }
123         mi->common->type = DIR;
124         RET( -1 );
125 }
126
127 /* ( -- ) */
128 static void
129 ext2_files_close( ext2_info_t *mi )
130 {
131         ext2_COMMON *common = mi->common;
132
133         if (common->type == FILE)
134                 ext2_close(common->file);
135         else if (common->type == DIR)
136                 ext2_closedir(common->dir);
137         free(common);
138
139         ext2_umount(mi->volume);
140 }
141
142 /* ( buf len -- actlen ) */
143 static void
144 ext2_files_read( ext2_info_t *mi )
145 {
146         int count = POP();
147         char *buf = (char *)cell2pointer(POP());
148
149         ext2_COMMON *common = mi->common;
150         if (common->type != FILE)
151                 RET( -1 );
152
153         RET ( ext2_read( common->file, buf, count ) );
154 }
155
156 /* ( pos.d -- status ) */
157 static void
158 ext2_files_seek( ext2_info_t *mi )
159 {
160         long long pos = DPOP();
161         int offs = (int)pos;
162         int whence = SEEK_SET;
163         int ret;
164         ext2_COMMON *common = mi->common;
165
166         if (common->type != FILE)
167                 RET( -1 );
168
169         ret = ext2_lseek(common->file, offs, whence);
170         if (ret)
171                 RET( -1 );
172         else
173                 RET( 0 );
174 }
175
176 /* ( addr -- size ) */
177 static void
178 ext2_files_load( ext2_info_t *mi )
179 {
180         char *buf = (char *)cell2pointer(POP());
181         int count;
182
183         ext2_COMMON *common = mi->common;
184         if (common->type != FILE)
185                 RET( -1 );
186
187         /* Seek to the end in order to get the file size */
188         ext2_lseek(common->file, 0, SEEK_END);
189         count = common->file->offset;
190         ext2_lseek(common->file, 0, SEEK_SET);
191
192         RET ( ext2_read( common->file, buf, count ) );
193 }
194
195 /* ( -- cstr ) */
196 static void
197 ext2_files_get_path( ext2_info_t *mi )
198 {
199         ext2_COMMON *common = mi->common;
200
201         if (common->type != FILE)
202                 RET( 0 );
203
204         RET( pointer2cell(strdup(common->file->path)) );
205 }
206
207 /* ( -- cstr ) */
208 static void
209 ext2_files_get_fstype( ext2_info_t *mi )
210 {
211         PUSH( pointer2cell(strdup("ext2")) );
212 }
213
214 /* static method, ( pathstr len ihandle -- ) */
215 static void
216 ext2_files_dir( ext2_info_t *dummy )
217 {
218         ext2_COMMON *common;
219         ext2_VOLUME *volume;
220         struct ext2_dir_entry_2 *entry;
221         struct ext2_inode inode;
222         int fd;
223
224         ihandle_t ih = POP();
225         char *path = pop_fstr_copy();
226
227         fd = open_ih( ih );
228         if ( fd == -1 ) {
229                 free( path );
230                 return;
231         }
232
233         volume = ext2_mount(fd);
234         if (!volume) {
235                 return;
236         }
237
238         common = (ext2_COMMON*)malloc(sizeof(ext2_COMMON));
239         common->dir = ext2_opendir(volume, path);
240
241         forth_printf("\n");
242         while ( (entry = ext2_readdir(common->dir)) ) {
243                 ext2_get_inode(common->dir->volume, entry->inode, &inode);
244                 forth_printf("% 10d ", inode.i_size);
245                 print_date(inode.i_mtime);
246                 if (S_ISDIR(inode.i_mode))
247                         forth_printf("%s\\\n", entry->name);
248                 else
249                         forth_printf("%s\n", entry->name);
250         }
251
252         ext2_closedir( common->dir );
253         ext2_umount( volume );
254
255         close_io( fd );
256
257         free( common );
258         free( path );
259 }
260
261 /* static method, ( pos.d ih -- flag? ) */
262 static void
263 ext2_files_probe( ext2_info_t *dummy )
264 {
265         ihandle_t ih = POP_ih();
266         long long offs = DPOP();
267         int fd, ret = 0;
268
269         fd = open_ih(ih);
270         if (fd >= 0) {
271                 if (ext2_probe(fd, offs)) {
272                         ret = -1;
273                 }
274                 close_io(fd);
275         } else {
276                 ret = -1;
277         }
278
279         RET (ret);
280 }
281
282
283 static void
284 ext2_initializer( ext2_info_t *dummy )
285 {
286         fword("register-fs-package");
287 }
288
289 NODE_METHODS( ext2 ) = {
290         { "probe",      ext2_files_probe        },
291         { "open",       ext2_files_open         },
292         { "close",      ext2_files_close        },
293         { "read",       ext2_files_read         },
294         { "seek",       ext2_files_seek         },
295         { "load",       ext2_files_load         },
296         { "dir",        ext2_files_dir          },
297
298         /* special */
299         { "get-path",   ext2_files_get_path     },
300         { "get-fstype", ext2_files_get_fstype   },
301
302         { NULL,         ext2_initializer        },
303 };
304
305 void
306 ext2_init( void )
307 {
308         REGISTER_NODE( ext2 );
309 }