Author: laurent
Date: 2009-11-22 11:21:43 +0100 (Sun, 22 Nov 2009)
New Revision: 633
Modified:
trunk/openbios-devel/fs/hfs/hfs_fs.c
Log:
Implements dir method for HFS filesystem.
0 > dir cd:\
393216 2009-02-15 17:11:17 .disk\
131072 2009-02-15 17:10:53 css\
984 2009-02-07 19:35:37 dedication.txt
65536 2009-02-15 17:11:18 dists\
1966080 2009-02-15 17:11:18 doc\
65536 2009-02-15 17:10:54 etc\
458752 2009-02-15 17:11:18 install\
45447 2009-02-15 17:11:17 md5sum.txt
917504 2009-02-15 17:10:53 pics\
65536 2009-02-15 17:11:18 pool\
131072 2009-02-15 17:11:18 ppc\
8921 2009-02-15 17:11:17 README.html
119979 2009-02-14 20:52:19 README.mirrors.html
60194 2009-02-14 20:52:19 README.mirrors.txt
379 2009-02-15 17:10:54 README.source
5468 2009-02-15 17:11:17 README.txt
Signed-off-by: Laurent Vivier <Laurent(a)vivier.eu>
Modified: trunk/openbios-devel/fs/hfs/hfs_fs.c
===================================================================
--- trunk/openbios-devel/fs/hfs/hfs_fs.c 2009-11-22 10:07:23 UTC (rev 632)
+++ trunk/openbios-devel/fs/hfs/hfs_fs.c 2009-11-22 10:21:43 UTC (rev 633)
@@ -16,6 +16,7 @@
#include "openbios/config.h"
#include "openbios/fs.h"
+#include "libc/vsprintf.h"
#include "libhfs.h"
#define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */
@@ -27,6 +28,13 @@
#define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
#define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
+typedef struct {
+ enum { FILE, DIR } type;
+ union {
+ hfsdir *dir;
+ hfsfile *file;
+ };
+} hfscommon;
/************************************************************************/
@@ -142,15 +150,22 @@
static void
file_close( file_desc_t *fd )
{
- hfsfile *file = (hfsfile*)fd;
- hfs_close( file );
+ hfscommon *common = (hfscommon*)fd;
+ if (common->type == FILE)
+ hfs_close( common->file );
+ else if (common->type == DIR)
+ hfs_closedir( common->dir );
+ free(common);
}
static int
file_lseek( file_desc_t *fd, off_t offs, int whence )
{
- hfsfile *file = (hfsfile*)fd;
+ hfscommon *common = (hfscommon*)fd;
+ if (common->type != FILE)
+ return -1;
+
switch( whence ) {
case SEEK_CUR:
whence = HFS_SEEK_CUR;
@@ -164,27 +179,32 @@
break;
}
- return hfs_seek( file, offs, whence );
+ return hfs_seek( common->file, offs, whence );
}
static int
file_read( file_desc_t *fd, void *buf, size_t count )
{
- hfsfile *file = (hfsfile*)fd;
- return hfs_read( file, buf, count );
+ hfscommon *common = (hfscommon*)fd;
+ if (common->type != FILE)
+ return -1;
+ return hfs_read( common->file, buf, count );
}
static char *
get_path( file_desc_t *fd, char *retbuf, int len )
{
char buf[256], buf2[256];
+ hfscommon *common = (hfscommon*)fd;
hfsvol *vol = hfs_getvol( NULL );
- hfsfile *file = (hfsfile*)fd;
hfsdirent ent;
int start, ns;
ulong id;
- hfs_fstat( file, &ent );
+ if (common->type != FILE)
+ return NULL;
+
+ hfs_fstat( common->file, &ent );
start = sizeof(buf) - strlen(ent.name) - 1;
if( start <= 0 )
return NULL;
@@ -215,28 +235,51 @@
static file_desc_t *
-open_path( fs_ops_t *fs, const char *path )
+open_path( fs_ops_t *fs, const char *fullpath )
{
hfsvol *vol = (hfsvol*)fs->fs_data;
const char *s;
char buf[256];
+ hfscommon *common;
+ char *path = strdup(fullpath);
if( !strncmp(path, "\\\\", 2) ) {
hfsvolent ent;
/* \\ is an alias for the (blessed) system folder */
- if( hfs_vstat(vol, &ent) < 0 || hfs_setcwd(vol, ent.blessed) )
+ if( hfs_vstat(vol, &ent) < 0 || hfs_setcwd(vol, ent.blessed) ) {
+ free(path);
return NULL;
+ }
path += 2;
} else {
hfs_chdir( vol, ":" );
}
+ common = malloc(sizeof(*common));
+ if (!common) {
+ free(path);
+ return NULL;
+ }
+
+ if (strcmp(path, "\\") == 0) {
+ /* root directory is in fact ":" */
+ common->dir = hfs_opendir(vol, ":");
+ common->type = DIR;
+ free(path);
+ return (file_desc_t*)common;
+ }
+
+ if (path[strlen(path) - 1] == '\\') {
+ path[strlen(path) - 1] = 0;
+ }
+
for( path-- ;; ) {
int n;
s = ++path;
- if( !(path=strchr(s, '\\')) )
+ path = strchr(s, '\\');
+ if( !path || !path[1])
break;
n = MIN( sizeof(buf)-1, (path-s) );
if( !n )
@@ -244,8 +287,11 @@
strncpy( buf, s, n );
buf[n] = 0;
- if( hfs_chdir(vol, buf) )
+ if( hfs_chdir(vol, buf) ) {
+ free(common);
+ free(path);
return NULL;
+ }
}
/* support the ':filetype' syntax */
@@ -260,23 +306,43 @@
hfs_dirinfo( vol, &id, buf );
hfs_setcwd( vol, id );
- if( !(dir=hfs_opendir(vol, buf)) )
+ if( !(dir=hfs_opendir(vol, buf)) ) {
+ free(common);
+ free(path);
return NULL;
+ }
hfs_setcwd( vol, oldid );
while( !hfs_readdir(dir, &ent) ) {
if( ent.flags & HFS_ISDIR )
continue;
if( !strncmp(s, ent.u.file.type, 4) ) {
- ret = (file_desc_t*)hfs_open( vol, ent.name );
+ common->type = FILE;
+ common->file = hfs_open( vol, ent.name );
+ ret = (file_desc_t*)common;
break;
}
}
hfs_closedir( dir );
+ free(path);
return ret;
}
- return (file_desc_t*)hfs_open( vol, s );
+ common->dir = hfs_opendir(vol, s);
+ if (!common->dir) {
+ common->file = hfs_open( vol, s );
+ if (common->file == NULL) {
+ free(common);
+ free(path);
+ return NULL;
+ }
+ common->type = FILE;
+ free(path);
+ return (file_desc_t*)common;
+ }
+ common->type = DIR;
+ free(path);
+ return (file_desc_t*)common;
}
static void
@@ -288,6 +354,75 @@
/* callers responsibility to call free(fs) */
}
+static const int days_month[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const int days_month_leap[12] =
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static inline int is_leap(int year)
+{
+ return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
+}
+
+static void
+print_date(time_t sec)
+{
+ unsigned int second, minute, hour, month, day, year;
+ int current;
+ const int *days;
+
+ second = sec % 60;
+ sec /= 60;
+
+ minute = sec % 60;
+ sec /= 60;
+
+ hour = sec % 24;
+ sec /= 24;
+
+ year = sec * 100 / 36525;
+ sec -= year * 36525 / 100;
+ year += 1970;
+
+ days = is_leap(year) ? days_month_leap : days_month;
+
+ current = 0;
+ month = 0;
+ while (month < 12) {
+ if (sec <= current + days[month]) {
+ break;
+ }
+ current += days[month];
+ month++;
+ }
+ month++;
+
+ day = sec - current + 1;
+
+ forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
+ year, month, day, hour, minute, second);
+}
+
+static void
+dir_fs( file_desc_t *fd )
+{
+ hfscommon *common = (hfscommon*)fd;
+ hfsdirent ent;
+
+ if (common->type != DIR)
+ return;
+
+ forth_printf("\n");
+ while( !hfs_readdir(common->dir, &ent) ) {
+ forth_printf("% 10d ", ent.u.file.dsize);
+ print_date(ent.mddate);
+ if( ent.flags & HFS_ISDIR )
+ forth_printf("%s\\\n", ent.name);
+ else
+ forth_printf("%s\n", ent.name);
+ }
+}
+
static const char *
get_fstype( fs_ops_t *fs )
{
@@ -295,6 +430,7 @@
}
static const fs_ops_t hfs_ops = {
+ .dir = dir_fs,
.close_fs = close_fs,
.open_path = open_path,
.search_rom = search_rom,