Virtual File System Library

VFSlib es una librería que he desarrollado para Wii/GC y que permite realizar tareas de E/S bajo una interfaz unificada. En otras palabras, para el usuario de VFSlib leer archivos de una tarjeta SD o leerlos de Internet no supone ninguna diferencia, ya que las funciones que usa son las mismas en ambos casos.

Las funciones de VFSlib son compatibles con las funciones stdio de manejo de streams de ANSI C. Sólo son específicas de VFSlib aquellas operaciones no definidas en stdio, como por ejemplo las relativas a directorios.

Con la primera versión (0.1a) se puede acceder al lector SD de Wii y a archivos disponibles en Internet via HTTP. Algunos usos que se me ocurren son hacer un navegador web o cargar roms en los emuladores mediante streamming desde el PC... Más adelante iré añadiendo soporte para FTP, GeckoSD y lo que se me vaya ocurriendo.

Podeis bajar el código fuente y una incipiente documentación en mi blog.

Saludos!
Me recuerda mucho al KIO, al sistema que se usa en KDE... esta lib va a ser muy útil [sonrisa]
PNGU... VFSlib... tus libs facilitarán mucho la programación futura de aplicaciones [carcajad]
joder lo del streaming tiene que estar bien, solo que abria que implementarlo en las distintas aplicaciones que hay ya, una pregunta, cuando he mirado el codigo fuente del ejemplo y hace referencia a un archivo de texto alojado en googlepages, pero no necesitas algun codio para acceder al wifi de wii?? o en su caso al adaptador?? esque nose como puede apuntar a ese archivo sin tocar el wifi en el codigo (o ke estoy cegato perdio y no lo he visto [tomaaa] )


te lo agradecia si me contestaras


saludos....



p.d. gran aporte [oki]
hola, me interesa mucho la pregunta de "caballeroalba", me gustaria escuchar como funciona!

el resto es una de esas cosas, que mas o menos entendio, pero no comprendo como lo hacen, exelente trabajo!!!!

muy bueno!!

gracias!!

eliglu
En realidad no tiene mucho misterio: La función VFS_fopen parsea la url de entrada para saber si el archivo está en la SD (wsd://) o en el web (http://). Si se da este último caso llama a las funciones de acceso al adaptador wifi. Lo mejor es que mireis el código fuente de VFS_fopen que está en "source/vfs/vfs_fopen.c".

Hay que tener en cuenta que las funciones de acceso al adaptador wifi se han añadido hace muy pocos días y sólo están disponibles en la versión CVS de libogc. La mayoría las ha escrito bushing y son básicamente llamadas a funciones del IOS, que al parecer proporciona una interfaz de conexión basada en sockets. Hay que darle las gracias una vez más a la gran N por ceñirse a los estándares [plas] [plas] [plas]
frontier escribió:En realidad no tiene mucho misterio: La función VFS_fopen parsea la url de entrada para saber si el archivo está en la SD (wsd://) o en el web (http://). Si se da este último caso llama a las funciones de acceso al adaptador wifi. Lo mejor es que mireis el código fuente de VFS_fopen que está en "source/vfs/vfs_fopen.c".

Wow!... ya imagino cargar Roms desde un servidor web:
Snes9x online library:
Games available on web library:
>> Castlevania (Download & Play it!)
   Super Mario World
   Punch-Out!!
   etc, etc, etc

Soñar no cuesta nada [tomaaa] !
devkitpro ya tiene un sistema para esto, se llama devoptab y en su última versión CVS con libfat ya soporta el acceso a SD, tanto frontal como Gecko, entre otras cosas. Simplemente hay que inicializar el libfat y luego se accede por fopen(), fread(), etc. Está todo integrado con la newlib.

Lo suyo sería montar el soporte HTTP como un devoptab mas, en lugar de escribir otra capa encima.
Era de esperar que me copiasen la idea [fumando]

Ya en serio, he estado urgando un poco en la página del devkitpro y no encuentro ninguna referencia a devoptab. Y google tampoco es que me haya sacado de dudas... ¿Me podrías indicar algún sitio donde esté documentado/explicado el susodicho invento? Es que antes de tirar tres semanas de trabajo me gustaría saber bien en que consiste la alternativa.


Una duda: ¿Las funciones que trae libogc para acceder al SDgecko se consideran obsoletas ahora que también se puede acceder con devoptab?
Es lo que tiene el devkitpro, que le hace falta una cantidad de documentacion importante... lo mejor será que te mires el código fuente de libfat, para que veas como se "enchufa" al sistema devoptab. Está en el CVS de devkitpro. Resumiendo, provees una estructura que tiene punteros a todas las funciones de tu "driver" (abrir, cerrar, leer, escribir, seek, leer directorio, etc), y también especificas cuanto espacio de almacenamiento te hace falta por cada descriptor abierto, cosas así. Luego registrar esa estructura y queda disponible tu driver para cualquiera que use la libc estandar (fopen(), fread(), etc).
Muchas gracias, lo voy a estudiar con detenimiento. A priori parece una alternativa perfectamente válida a mi librería y con la ventaja de estar integrada en devkitpro.

Sólo hay una pega que le veo a este sistema: Muchas operaciones importantes como crear y borrar directorios, saber el espacio total y libre de una unidad, etc, no están definidas en stdio. Imagino que se habrá buscado una solución...
Estas son las funciones definidas:

typedef struct {
        const char *name;
        int     structSize;
        int (*open_r)(struct _reent *r, void *fileStruct, const char *path,int flags,int mode);
        int (*close_r)(struct _reent *r,int fd);
        int (*write_r)(struct _reent *r,int fd,const char *ptr,int len);
        int (*read_r)(struct _reent *r,int fd,char *ptr,int len);
        int (*seek_r)(struct _reent *r,int fd,int pos,int dir);
        int (*fstat_r)(struct _reent *r,int fd,struct stat *st);
        int (*stat_r)(struct _reent *r,const char *file,struct stat *st);
        int (*link_r)(struct _reent *r,const char *existing, const char  *newLink);
        int (*unlink_r)(struct _reent *r,const char *name);
        int (*chdir_r)(struct _reent *r,const char *name);

        int (*rename_r) (struct _reent *r, const char *oldName, const char *newName);
        int (*mkdir_r) (struct _reent *r, const char *path, int mode);

        int dirStateSize;
        DIR_ITER* (*diropen_r)(struct _reent *r, DIR_ITER *dirState, const char *path);
        int (*dirreset_r)(struct _reent *r, DIR_ITER *dirState);
        int (*dirnext_r)(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
        int (*dirclose_r)(struct _reent *r, DIR_ITER *dirState);
        int (*statvfs_r) (struct _reent *r, const char *path, struct statvfs *buf);
} devoptab_t;


Vamos, que no solo es STDIO, sino que incluye funciones para renombrar, crear directorios, leer directorios, y statvfs que devuelve estadísticas sobre el sistema de archivos (espacio disponible, etc). En este caso, rmdir se implementa en forma de unlink (es decir se borran archivos y directorios con la misma llamada).

Por si te preguntas lo que es struct _reent, es una estructura que te permite trabajar con multithreading limpiamente. Por ejemplo, contiene una copia de errno para cada thread, que es el uso mas común (p.e. se usaría r->_errno = ENOENT; para indicar que un archivo no existe, en lugar de errno = ENOENT;)

También debo comentar, y esto es un pelín chanchullo, que realmente lo que se te pasa como "fd" a close, write, seek, etc no es mas que el void *fileStruct (así que hay que castearlo a un puntero), y que el FD que devuelvas desde el open() no importa (simplemente has de devolver -1 para error y cualquier numero positivo como OK - la gente suele devolver fileStruct), porque realmente todo queda abstraído al nivel de devoptab y el usuario trabaja con FDs en una tabla maestra - los devices trabajan directamente con la estructura fileStruct, que puede tener el tamaño que quieras (indicado en structSize) y el sistema automáticamente se encarga de hacer el malloc() y el free().
La scene de Wii se pone muy interesante.

Que pena no disponer de tiempo libre para trastear y contribuir :(
marcansoft escribió:Estas son las funciones definidas:

typedef struct {
        const char *name;
        int     structSize;
        int (*open_r)(struct _reent *r, void *fileStruct, const char *path,int flags,int mode);
        int (*close_r)(struct _reent *r,int fd);
        int (*write_r)(struct _reent *r,int fd,const char *ptr,int len);
        int (*read_r)(struct _reent *r,int fd,char *ptr,int len);
        int (*seek_r)(struct _reent *r,int fd,int pos,int dir);
        int (*fstat_r)(struct _reent *r,int fd,struct stat *st);
        int (*stat_r)(struct _reent *r,const char *file,struct stat *st);
        int (*link_r)(struct _reent *r,const char *existing, const char  *newLink);
        int (*unlink_r)(struct _reent *r,const char *name);
        int (*chdir_r)(struct _reent *r,const char *name);

        int (*rename_r) (struct _reent *r, const char *oldName, const char *newName);
        int (*mkdir_r) (struct _reent *r, const char *path, int mode);

        int dirStateSize;
        DIR_ITER* (*diropen_r)(struct _reent *r, DIR_ITER *dirState, const char *path);
        int (*dirreset_r)(struct _reent *r, DIR_ITER *dirState);
        int (*dirnext_r)(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
        int (*dirclose_r)(struct _reent *r, DIR_ITER *dirState);
        int (*statvfs_r) (struct _reent *r, const char *path, struct statvfs *buf);
} devoptab_t;


Vamos, que no solo es STDIO, sino que incluye funciones para renombrar, crear directorios, leer directorios, y statvfs que devuelve estadísticas sobre el sistema de archivos (espacio disponible, etc). En este caso, rmdir se implementa en forma de unlink (es decir se borran archivos y directorios con la misma llamada).

Por si te preguntas lo que es struct _reent, es una estructura que te permite trabajar con multithreading limpiamente. Por ejemplo, contiene una copia de errno para cada thread, que es el uso mas común (p.e. se usaría r->_errno = ENOENT; para indicar que un archivo no existe, en lugar de errno = ENOENT;)

También debo comentar, y esto es un pelín chanchullo, que realmente lo que se te pasa como "fd" a close, write, seek, etc no es mas que el void *fileStruct (así que hay que castearlo a un puntero), y que el FD que devuelvas desde el open() no importa (simplemente has de devolver -1 para error y cualquier numero positivo como OK - la gente suele devolver fileStruct), porque realmente todo queda abstraído al nivel de devoptab y el usuario trabaja con FDs en una tabla maestra - los devices trabajan directamente con la estructura fileStruct, que puede tener el tamaño que quieras (indicado en structSize) y el sistema automáticamente se encarga de hacer el malloc() y el free().


Gracias por la explicación, me ha sido muy util para entender el source de libfat :)

Hasta ahora he conseguido registrar mi propio device, aunque de momento sólo he creado las funciones que se llaman al invocar a fopen y fclose. Aparte del chanchullillo ese de usar los punteros a fileStruct a modo de descriptores de fichero parece un sistema muy bien pensado. Definitivamente abandono mi librería para dedicarme a crear devices devoptab para http y ftp.

Por cierto, no consigo compilar el perfil wii-release de la versión CVS de libfat que he obtenido esta misma tarde. Me sale que no se encuentra el identificador "__system_argv". Supongo que será porque el port aún está a medio cocinar...

Y ya para terminar: ¿Está disponible en algún lado el source de devkitppc r15? Es que me gustaría indagar más a fondo como trabaja devoptab, sobre todo quisiera echarle un ojo a "iosupport.c".

Ale, a seguir con lo mío :p
Necesitas el ultimo toolchain devkitppc (lo que viene a ser r15) compilado desde fuentes (bajate el modulo buildscripts del CVS, y luego sh build-devkit.sh), y la ultima libogc, para poder compilar libfat correctamente.

r15 debería salir ya pronto, en unos días ;)

También estoy poniendo info y algunos paquetes para descargar en una pagina que estoy montando de scene de wii. Está un poco verde, pero iré poniendo info mas util: http://www.entuwii.net/foro/viewtopic.php?f=6&t=4
Está muy bien la página, hacía falta un foro orientado a programadores de wii/gc en español. Yo ya me he registrado antes de que me quiten el nick [+risas]

He seguido tus instrucciones de allí para compilar la versión CVS de devkitppc pero me he encontrado con algunos escollos. El primero y más obvio es que la orden para compilar es "sh build-devkit.sh" y no "sh build-devkit-sh". El segundo, también bastante trivial, es que hay una llamada a "exit" al principio de "build-devkit.sh" que hay que comentar para que el script continúe. Supongo que será una forma de disuadir a quien no sepa escribir el carácter "#" :-?

El tercero ya es más grave. Despues de descargar automáticamente las binutils, gcc y newlib via wget me aparece que no se encuentra "libogc-src-20080515.tar.bz2". Lo he comprobado y, efectivamente, en sourceforge no hay ni rastro de ese archivo. El problema es que sourceforge.net me redirecciona a puzzle.dl.sourceforge.net, y éste otra vez al primero... La única solución que se me ha ocurrido es bajar la versión CVS y comprimirla yo mismo en .tar.bz2...

EDIT: Al bajarme el CVS de libogc de hoy mismo me he encontrado con que le han metido las wiiuse :-? ¿No se suponía que estas libs tenían bugs que, entre otras cosas, impedían acceder al lector SD? ¿Los habrán arreglado ya?
Jajaja, que cabrón el wintermute. Lo del punto, evidentemente, mea culpa - arreglado. Lo del exit, es que se mosquea cuando la gente instala software "beta" y luego se queja. He añadido una nota al post. Como la libogc para r15 todavía no existe, en efecto te toca bajar el CVS. Pero para el build-devkit.sh, lo mas facil es que metas un tar.bz2 vacío, una versión vieja de libogc, o algo así, y luego simplemente lo reemplaces todo por la última versión compilada a mano (de libogc y libfat). Cuando salga r15 será todo mucho mas simple.

Las wiiuse se han modificado mucho y se están acercando a ser perfectamente estables. Realmente el problema era también buena parte del backend lwbt de libogc. En cualquier caso, lo que hay en libogc ahora es mas o menos estable, aunque algunos fallos quedan (por eso no ha salido r15 todavía). Se recomienda usar el wrapper wpad.c de libogc, que abstrae los temas de threading de wiiuse.
15 respuestas