New io/packaging system.
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1035 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
+2
-1
@@ -28,6 +28,7 @@ uqm_INSTALL_LIBDIR="@INSTALL_LIBDIR@"
|
||||
# Non-exported files only where build.vars is explicitely included.
|
||||
uqm_SOUNDMODULE="@SOUNDMODULE@"
|
||||
uqm_HAVE_OPENGL="@HAVE_OPENGL@"
|
||||
uqm_USE_ZIP_IO="@USE_ZIP_IO@"
|
||||
WINDRES="@WINDRES@"
|
||||
export uqm_SOUNDMODULE uqm_HAVE_OPENGL WINDRES
|
||||
export uqm_SOUNDMODULE uqm_HAVE_OPENGL uqm_USE_ZIP_IO WINDRES
|
||||
|
||||
|
||||
@@ -38,11 +38,12 @@ define_have_header getopt.h
|
||||
|
||||
|
||||
# Describe the menu:
|
||||
MENU_main_ITEMS="debug graphics sound install_path"
|
||||
MENU_main_ITEMS="debug graphics sound ioformat install_path"
|
||||
MENU_main_TITLE="Main menu"
|
||||
MENU_main_ITEM_debug_TYPE=CHOICE
|
||||
MENU_main_ITEM_graphics_TYPE=CHOICE
|
||||
MENU_main_ITEM_sound_TYPE=CHOICE
|
||||
MENU_main_ITEM_ioformat_TYPE=CHOICE
|
||||
MENU_main_ITEM_link_TYPE=CHOICE
|
||||
MENU_main_ITEM_install_path_TYPE=MENU
|
||||
|
||||
@@ -134,6 +135,19 @@ sound_openal_action() {
|
||||
}
|
||||
CHOICE_sound_DEFAULT=mixsdl
|
||||
|
||||
CHOICE_ioformat_OPTIONS="stdio stdio_zip"
|
||||
CHOICE_ioformat_TITLE="Supported file i/o methods"
|
||||
CHOICE_ioformat_OPTION_stdio_TITLE="Only direct file i/o"
|
||||
CHOICE_ioformat_OPTION_stdio_zip_TITLE="Direct & .zip file i/o"
|
||||
CHOICE_ioformat_OPTION_stdio_zip_PRECOND="have_library zlib"
|
||||
CHOICE_ioformat_OPTION_stdio_zip_ACTION="ioformat_stdio_zip_action"
|
||||
ioformat_stdio_zip_action() {
|
||||
CFLAGS="$CFLAGS -DHAVE_ZIP=1"
|
||||
USE_ZIP_IO=1
|
||||
use_library zlib
|
||||
}
|
||||
CHOICE_ioformat_DEFAULT=stdio_zip
|
||||
|
||||
# Making static binaries is more complicated than this.
|
||||
# For now, it will have to be done by hand.
|
||||
#CHOICE_link_OPTIONS="static dynamic"
|
||||
@@ -185,6 +199,7 @@ substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES
|
||||
|
||||
# Make build.vars from build.vars.in, substituting variables.
|
||||
SUBSTITUTE_VARS="CFLAGS LDFLAGS MAKE DEBUG SOUNDMODULE HAVE_OPENGL \
|
||||
USE_ZIP_IO \
|
||||
INSTALL_LIBDIR INSTALL_BINDIR WINDRES"
|
||||
SUBSTITUTE_FILES="build.vars"
|
||||
substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES
|
||||
|
||||
@@ -125,3 +125,8 @@ case "$OSNAME" in
|
||||
esac
|
||||
LIB_vorbisfile_VERSION=""
|
||||
|
||||
LIB_zlib_NAME="zlib"
|
||||
LIB_zlib_CFLAGS=""
|
||||
LIB_zlib_LDFLAGS=""
|
||||
LIB_zlib_VERSION=""
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /D "HAVE_ZIP" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@@ -50,7 +50,7 @@ BSC32=bscmake.exe
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../uqm.exe"
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib zlib.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../uqm.exe"
|
||||
|
||||
!ELSEIF "$(CFG)" == "UrQuanMasters - Win32 Debug"
|
||||
|
||||
@@ -66,7 +66,7 @@ LINK32=link.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "DEBUG_TRACK_SEM" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /FR /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "DEBUG_TRACK_SEM" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /D "HAVE_ZIP" /FR /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@@ -74,7 +74,7 @@ BSC32=bscmake.exe
|
||||
# ADD BSC32 /nologo /o"UrQuanMasters.bsc"
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../uqmdebug.exe" /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib zlib.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../uqmdebug.exe" /pdbtype:sept
|
||||
# SUBTRACT LINK32 /nodefaultlib
|
||||
|
||||
!ENDIF
|
||||
@@ -220,6 +220,14 @@ SOURCE=..\sc2code\libs\graphics\sdl\rndzoom.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\graphics\sdl\sdluio.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\graphics\sdl\sdluio.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\graphics\sdl\sdl_common.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@@ -814,8 +822,188 @@ SOURCE=..\sc2code\libs\timelib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\vidlib.h
|
||||
SOURCE=..\sc2code\libs\uio.h
|
||||
# End Source File
|
||||
# Begin Group "uio"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\charhashtable.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\charhashtable.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\debug.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\debug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\defaultfs.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\defaultfs.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\fileblock.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\fileblock.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\fstypes.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\fstypes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\gphys.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\gphys.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\hashtable.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\hashtable.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\io.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\io.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\ioaux.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\ioaux.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\iointrn.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\match.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\match.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\mem.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\memdebug.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\memdebug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\mount.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\mount.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\mounttree.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\mounttree.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\paths.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\paths.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\physical.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\physical.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\uiostream.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\uiostream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\types.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\uioport.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\uioutils.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\uioutils.h
|
||||
# End Source File
|
||||
# Begin Group "stdio"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\stdio\stdio.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\stdio\stdio.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "zip"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\zip\zip.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\uio\zip\zip.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Group
|
||||
# End Group
|
||||
# Begin Group "comm"
|
||||
|
||||
|
||||
+132
-14
@@ -22,11 +22,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "port.h"
|
||||
#include "libs/graphics/gfx_common.h"
|
||||
#include "compiler.h"
|
||||
#include "options.h"
|
||||
#include "file.h"
|
||||
#include "config.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
int optWhichMusic = OPT_3DO;
|
||||
int optWhichCoarseScan = OPT_3DO;
|
||||
@@ -35,61 +38,176 @@ int optWhichFonts = OPT_PC;
|
||||
int optSmoothScroll = OPT_PC;
|
||||
int optMeleeScale = TFB_SCALE_TRILINEAR;
|
||||
|
||||
char *configDir, *saveDir, *meleeDir;
|
||||
BOOLEAN optSubtitles = TRUE;
|
||||
BOOLEAN optStereoSFX = FALSE;
|
||||
uio_DirHandle *contentDir;
|
||||
uio_DirHandle *configDir;
|
||||
uio_DirHandle *saveDir;
|
||||
uio_DirHandle *meleeDir;
|
||||
|
||||
extern uio_Repository *repository;
|
||||
extern uio_DirHandle *rootDir;
|
||||
|
||||
|
||||
static void mountContentDir (uio_Repository *repository,
|
||||
const char *contentPath);
|
||||
|
||||
void
|
||||
prepareContentDir (char *contentDirName)
|
||||
{
|
||||
const char *testfile = "version";
|
||||
char cwd[PATH_MAX];
|
||||
|
||||
if (!fileExists (testfile))
|
||||
{
|
||||
if ((chdir (contentDirName) || !fileExists (testfile)) &&
|
||||
(chdir ("content") || !fileExists (testfile)) &&
|
||||
(chdir ("../../content") || !fileExists (testfile))) {
|
||||
fprintf (stderr, "Fatal error: content not available, running from wrong dir?\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) {
|
||||
fprintf (stderr, "Fatal error: Could not get the current "
|
||||
"directory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
mountContentDir (repository, cwd);
|
||||
}
|
||||
|
||||
void
|
||||
prepareConfigDir (void) {
|
||||
configDir = malloc (PATH_MAX - 13);
|
||||
if (expandPath (configDir, PATH_MAX - 13, CONFIGDIR) == -1)
|
||||
char buf[PATH_MAX];
|
||||
static uio_AutoMount *autoMount[] = { NULL };
|
||||
uio_MountHandle *contentHandle;
|
||||
|
||||
if (expandPath (buf, PATH_MAX - 13, CONFIGDIR) == -1)
|
||||
{
|
||||
// Doesn't have to be fatal, but might mess up things when saving
|
||||
// config files.
|
||||
fprintf (stderr, "Fatal error: Invalid path to config files.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
configDir = realloc (configDir, strlen (configDir) + 1);
|
||||
|
||||
// Create the path upto the config dir, if not already existing.
|
||||
if (mkdirhier (configDir) == -1)
|
||||
if (mkdirhier (buf) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
contentHandle = uio_mountDir (repository, "/",
|
||||
uio_FSTYPE_STDIO, NULL, NULL, buf, autoMount,
|
||||
uio_MOUNT_TOP, NULL);
|
||||
if (contentHandle == NULL) {
|
||||
fprintf (stderr, "Fatal error: Couldn't mount content dir: %s\n",
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
configDir = uio_openDir (repository, "/", 0);
|
||||
if (configDir == NULL) {
|
||||
fprintf (stderr, "Fatal error: Could not open config dir: %s\n",
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
prepareSaveDir (void) {
|
||||
saveDir = malloc (PATH_MAX - 13);
|
||||
if (expandPath (saveDir, PATH_MAX - 13, SAVEDIR) == -1)
|
||||
char buf[PATH_MAX];
|
||||
if (expandPath (buf, PATH_MAX - 13, SAVEDIR) == -1)
|
||||
{
|
||||
// Doesn't have to be fatal, but might mess up things when saving
|
||||
// config files.
|
||||
fprintf (stderr, "Fatal error: Invalid path to config files.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
saveDir = realloc (saveDir, strlen (saveDir) + 1);
|
||||
|
||||
// Create the path upto the save dir, if not already existing.
|
||||
if (mkdirhier (saveDir) == -1)
|
||||
if (mkdirhier (buf) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
//#ifdef DEBUG
|
||||
fprintf(stderr, "Saved games are kept in %s.\n", saveDir);
|
||||
fprintf(stderr, "Saved games are kept in %s.\n", buf);
|
||||
//#endif
|
||||
|
||||
saveDir = uio_openDirRelative (configDir, "save", 0);
|
||||
if (saveDir == NULL) {
|
||||
fprintf (stderr, "Fatal error: Could not open save dir: %s\n",
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
prepareMeleeDir (void) {
|
||||
meleeDir = malloc (PATH_MAX - 13);
|
||||
if (expandPath (meleeDir, PATH_MAX - 13, MELEEDIR) == -1)
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (expandPath (buf, PATH_MAX - 13, MELEEDIR) == -1)
|
||||
{
|
||||
// Doesn't have to be fatal, but might mess up things when saving
|
||||
// config files.
|
||||
fprintf (stderr, "Fatal error: Invalid path to config files.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
meleeDir = realloc (meleeDir, strlen (meleeDir) + 1);
|
||||
|
||||
// Create the path upto the save dir, if not already existing.
|
||||
if (mkdirhier (meleeDir) == -1)
|
||||
if (mkdirhier (buf) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
meleeDir = uio_openDirRelative (configDir, "teams", 0);
|
||||
if (meleeDir == NULL) {
|
||||
fprintf (stderr, "Fatal error: Could not open melee teams dir: %s\n",
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mountContentDir (uio_Repository *repository, const char *contentPath) {
|
||||
uio_MountHandle *contentHandle;
|
||||
uio_DirHandle *packagesDir;
|
||||
static uio_AutoMount *autoMount[] = { NULL };
|
||||
|
||||
contentHandle = uio_mountDir (repository, "/",
|
||||
uio_FSTYPE_STDIO, NULL, NULL, contentPath, autoMount,
|
||||
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
if (contentHandle == NULL) {
|
||||
fprintf (stderr, "Fatal error: Couldn't mount content dir: %s\n",
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
contentDir = uio_openDir (repository, "/", 0);
|
||||
if (contentDir == NULL) {
|
||||
fprintf (stderr, "Fatal error: Could not open content dir: %s\n",
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
packagesDir = uio_openDir (repository, "/packages", 0);
|
||||
if (packagesDir == NULL) {
|
||||
// No packages dir means no packages to load.
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
uio_DirList *dirList;
|
||||
|
||||
dirList = uio_getDirList(packagesDir, "", ".zip", match_MATCH_SUFFIX);
|
||||
if (dirList != NULL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dirList->numNames; i++) {
|
||||
if (uio_mountDir (repository, "/", uio_FSTYPE_ZIP,
|
||||
packagesDir, dirList->names[i], "/", autoMount,
|
||||
uio_MOUNT_BELOW | uio_MOUNT_RDONLY,
|
||||
contentHandle) == NULL) {
|
||||
fprintf(stderr, "Warning: Could not mount '%s': %s.\n",
|
||||
dirList->names[i], strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
uio_freeDirList (dirList);
|
||||
}
|
||||
uio_closeDir(packagesDir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+8
-3
@@ -22,6 +22,9 @@
|
||||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
#define OPT_3DO 0x01
|
||||
#define OPT_PC 0x02
|
||||
#define OPT_ALL 0xFF
|
||||
@@ -36,10 +39,12 @@ extern int optMeleeScale;
|
||||
extern BOOLEAN optSubtitles;
|
||||
extern BOOLEAN optStereoSFX;
|
||||
|
||||
extern char *configDir;
|
||||
extern char *meleeDir;
|
||||
extern char *saveDir;
|
||||
extern uio_DirHandle *contentDir;
|
||||
extern uio_DirHandle *configDir;
|
||||
extern uio_DirHandle *saveDir;
|
||||
extern uio_DirHandle *meleeDir;
|
||||
|
||||
void prepareContentDir (char *contentDirName);
|
||||
void prepareConfigDir(void);
|
||||
void prepareMeleeDir(void);
|
||||
void prepareSaveDir(void);
|
||||
|
||||
@@ -16,5 +16,51 @@
|
||||
char *strupr (char *str);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
# include <stdlib.h>
|
||||
# define PATH_MAX _MAX_PATH
|
||||
# define NAME_MAX _MAX_FNAME
|
||||
// _MAX_DIR and FILENAME_MAX could also be candidates.
|
||||
// If anyone can tell me which one matches NAME_MAX, please
|
||||
// tell me. - SvdB
|
||||
#else
|
||||
/* PATH_MAX is per POSIX defined in <limits.h> */
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
# include <io.h>
|
||||
typedef int ssize_t;
|
||||
typedef unsigned short mode_t;
|
||||
# define access _access
|
||||
# define F_OK 0
|
||||
# define W_OK 2
|
||||
# define R_OK 4
|
||||
# include <direct.h>
|
||||
# define open _open
|
||||
# define mkdir _mkdir
|
||||
# define read _read
|
||||
# define rmdir _rmdir
|
||||
//# define fstat _fstat
|
||||
# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
|
||||
# define S_IRWXU (S_IREAD | S_IWRITE | S_IEXEC)
|
||||
# define S_IRWXG 0
|
||||
# define S_IRWXO 0
|
||||
# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISREG(mode) (((mode) & _S_IFMT) == _S_IFREG)
|
||||
# define write _write
|
||||
//# define stat _stat
|
||||
# define unlink _unlink
|
||||
#elif defined (__MINGW32__)
|
||||
typedef int ssize_t;
|
||||
typedef unsigned short mode_t;
|
||||
# define S_IRWXU (S_IREAD | S_IWRITE | S_IEXEC)
|
||||
# define S_IRWXG 0
|
||||
# define S_IRWXO 0
|
||||
# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISREG(mode) (((mode) & _S_IFMT) == _S_IFREG)
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#endif /* _PORT_H */
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ OpenJournal (void)
|
||||
else
|
||||
#endif /* CREATE_JOURNAL */
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
if (fp = res_OpenResFile ("starcon.jnl", "rb"))
|
||||
{
|
||||
@@ -114,7 +114,7 @@ CloseJournal (void)
|
||||
{
|
||||
if (journal_fh)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
cclose (journal_fh);
|
||||
journal_fh = 0;
|
||||
|
||||
@@ -35,7 +35,7 @@ LoadCodeResFile (PSTR pStr)
|
||||
}
|
||||
|
||||
static MEM_HANDLE
|
||||
GetCodeResData (FILE *fp, DWORD length)
|
||||
GetCodeResData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
enum
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ InitGroupInfo (BOOLEAN FirstTime)
|
||||
{
|
||||
PVOID fp;
|
||||
|
||||
fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb");
|
||||
fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb");
|
||||
if (fp)
|
||||
{
|
||||
GROUP_HEADER GH;
|
||||
@@ -49,8 +49,7 @@ InitGroupInfo (BOOLEAN FirstTime)
|
||||
res_CloseResFile (fp);
|
||||
}
|
||||
|
||||
if (FirstTime && (fp = res_OpenResFile (tempFilePath (DEFGRPINFO_FILE),
|
||||
"wb")))
|
||||
if (FirstTime && (fp = res_OpenResFile (tempDir, DEFGRPINFO_FILE, "wb")))
|
||||
{
|
||||
PutResFileChar (0, fp);
|
||||
|
||||
@@ -349,8 +348,8 @@ GetGroupInfo (DWORD offset, BYTE which_group)
|
||||
{
|
||||
PVOID fp;
|
||||
|
||||
fp = res_OpenResFile (tempFilePath (
|
||||
offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE),
|
||||
fp = res_OpenResFile (tempDir,
|
||||
offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE,
|
||||
"r+b");
|
||||
if (fp)
|
||||
{
|
||||
@@ -387,7 +386,7 @@ GetGroupInfo (DWORD offset, BYTE which_group)
|
||||
fprintf (stderr, "GetGroupInfo: battle groups out of date %u/%u/%u!\n",
|
||||
month_index, day_index, year_index);
|
||||
#endif /* DEBUG */
|
||||
fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb");
|
||||
fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb");
|
||||
GH.NumGroups = 0;
|
||||
GH.star_index = (COUNT)~0;
|
||||
GH.GroupOffset[0] = 0;
|
||||
@@ -616,8 +615,8 @@ PutGroupInfo (DWORD offset, BYTE which_group)
|
||||
{
|
||||
PVOID fp;
|
||||
|
||||
fp = res_OpenResFile (tempFilePath (
|
||||
offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE),
|
||||
fp = res_OpenResFile (tempDir,
|
||||
offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE,
|
||||
"r+b");
|
||||
if (fp)
|
||||
{
|
||||
|
||||
@@ -16,13 +16,19 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "starcon.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
FRAME stars_in_space,
|
||||
asteroid[NUM_VIEWS],
|
||||
blast[NUM_VIEWS],
|
||||
explosion[NUM_VIEWS];
|
||||
|
||||
uio_Repository *repository;
|
||||
uio_DirHandle *rootDir;
|
||||
|
||||
|
||||
BOOLEAN
|
||||
load_animation (PFRAME pixarray, DWORD big_res, DWORD med_res, DWORD
|
||||
sml_res)
|
||||
@@ -268,3 +274,26 @@ InitGlobData (void)
|
||||
(GLOBAL (GameClock)).clock_sem = CreateSemaphore(0, "Clock");
|
||||
}
|
||||
|
||||
int
|
||||
initIO (void)
|
||||
{
|
||||
uio_init ();
|
||||
repository = uio_openRepository (0);
|
||||
|
||||
rootDir = uio_openDir(repository, "/", 0);
|
||||
if (rootDir == NULL) {
|
||||
fprintf(stderr, "Could not open '/' dir.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
uninitIO (void)
|
||||
{
|
||||
uio_closeDir (rootDir);
|
||||
uio_closeRepository (repository);
|
||||
uio_unInit ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
uqm_SUBDIRS="decomp file graphics input math memory resource sound strings
|
||||
task threads time video"
|
||||
task threads time uio video"
|
||||
|
||||
@@ -335,7 +335,7 @@ _encode_cleanup (void)
|
||||
_lpCurCodeDesc->StreamIndex += 4;
|
||||
/* rewind */
|
||||
if (_lpCurCodeDesc->StreamType == FILE_STREAM)
|
||||
SeekResFile ((FILE *)_Stream,
|
||||
SeekResFile ((uio_Stream *)_Stream,
|
||||
-(int)_lpCurCodeDesc->StreamIndex, SEEK_CUR);
|
||||
else /* _lpCurCodeDesc->StreamType == MEMORY_STREAM */
|
||||
_Stream = (PBYTE)((BYTE *)_Stream
|
||||
|
||||
@@ -69,10 +69,10 @@ typedef struct
|
||||
typedef LZHCODE_DESC *PLZHCODE_DESC;
|
||||
|
||||
#define InChar() (_StreamType == FILE_STREAM ? \
|
||||
GetResFileChar ((FILE *)_Stream) : \
|
||||
GetResFileChar ((uio_Stream *)_Stream) : \
|
||||
(int)*_Stream++)
|
||||
#define OutChar(c) (_StreamType == FILE_STREAM ? \
|
||||
PutResFileChar ((c), (FILE *)_Stream) : \
|
||||
PutResFileChar ((c), (uio_Stream *)_Stream) : \
|
||||
(*_Stream++ = (BYTE)(c)))
|
||||
|
||||
|
||||
|
||||
@@ -18,50 +18,17 @@
|
||||
|
||||
#ifndef _FILE_H
|
||||
|
||||
/* Make sure we have PATH_MAX */
|
||||
#ifdef WIN32
|
||||
# include <stdlib.h>
|
||||
# define PATH_MAX _MAX_PATH
|
||||
#else
|
||||
/* PATH_MAX is per POSIX defined in <limits.h> */
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
# include <io.h>
|
||||
# define access _access
|
||||
# define F_OK 0
|
||||
# define W_OK 2
|
||||
# define R_OK 4
|
||||
# include <direct.h>
|
||||
# define open _open
|
||||
# define mkdir _mkdir
|
||||
# define read _read
|
||||
# define rmdir _rmdir
|
||||
# define ssize_t int
|
||||
# define fstat _fstat
|
||||
# define S_IRWXU (S_IREAD | S_IWRITE | S_IEXEC)
|
||||
# define S_IRWXG 0
|
||||
# define S_IRWXO 0
|
||||
# define write _write
|
||||
# define stat _stat
|
||||
# define unlink _unlink
|
||||
#elif defined (__MINGW32__)
|
||||
# define ssize_t int
|
||||
# define S_IRWXU (S_IREAD | S_IWRITE | S_IEXEC)
|
||||
# define S_IRWXG 0
|
||||
# define S_IRWXO 0
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "port.h"
|
||||
|
||||
// for BOOLEAN
|
||||
#include "compiler.h"
|
||||
// for bool
|
||||
#include "types.h"
|
||||
|
||||
// from temp.h
|
||||
#include "libs/uio.h"
|
||||
void initTempDir (void);
|
||||
void unInitTempDir (void);
|
||||
char *tempFilePath (const char *filename);
|
||||
|
||||
extern uio_DirHandle *tempDir;
|
||||
|
||||
// from dirs.h
|
||||
int mkdirhier (const char *path);
|
||||
@@ -70,8 +37,10 @@ int createDirectory (const char *dir, int mode);
|
||||
int expandPath (char *dest, size_t len, const char *src);
|
||||
|
||||
// from files.h
|
||||
int copyFile (const char *srcName, const char *newName);
|
||||
BOOLEAN fileExists (const char *name);
|
||||
int copyFile (uio_DirHandle *srcDir, const char *srcName,
|
||||
uio_DirHandle *dstDir, const char *newName);
|
||||
bool fileExists (const char *name);
|
||||
bool fileExists2(uio_DirHandle *dir, const char *fileName);
|
||||
|
||||
|
||||
#endif /* _FILE_H */
|
||||
|
||||
@@ -22,20 +22,34 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "port.h"
|
||||
#include "uio.h"
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "filintrn.h"
|
||||
#include "misc.h"
|
||||
|
||||
static int copyError(int srcFd, int dstFd, const char *unlinkPath,
|
||||
uint8 *buf);
|
||||
static int copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
|
||||
uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf);
|
||||
|
||||
BOOLEAN
|
||||
bool
|
||||
fileExists (const char *name)
|
||||
{
|
||||
return access (name, F_OK) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
fileExists2(uio_DirHandle *dir, const char *fileName)
|
||||
{
|
||||
uio_Stream *stream;
|
||||
|
||||
stream = uio_fopen (dir, fileName, "rb");
|
||||
if (stream == NULL)
|
||||
return 0;
|
||||
|
||||
uio_fclose (stream);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a file with path srcName to a file with name newName.
|
||||
* If the destination already exists, the operation fails.
|
||||
@@ -48,49 +62,59 @@ fileExists (const char *name)
|
||||
* remove the copy.
|
||||
*/
|
||||
int
|
||||
copyFile (const char *srcName, const char *newName)
|
||||
copyFile (uio_DirHandle *srcDir, const char *srcName,
|
||||
uio_DirHandle *dstDir, const char *newName)
|
||||
{
|
||||
int src, dst;
|
||||
uio_Handle *src, *dst;
|
||||
struct stat sb;
|
||||
#define BUFSIZE 65536
|
||||
uint8 *buf, *bufPtr;
|
||||
ssize_t numInBuf, numWritten;
|
||||
|
||||
src = open (srcName, O_RDONLY);
|
||||
if (src == -1)
|
||||
src = uio_open (srcDir, srcName, O_RDONLY
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, 0);
|
||||
if (src == NULL)
|
||||
return -1;
|
||||
|
||||
if (fstat (src, &sb) == -1)
|
||||
return copyError (src, -1, NULL, NULL);
|
||||
if (uio_fstat (src, &sb) == -1)
|
||||
return copyError (src, NULL, NULL, NULL, NULL);
|
||||
|
||||
dst = open (newName, O_WRONLY | O_CREAT | O_EXCL,
|
||||
sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
|
||||
if (dst == -1)
|
||||
return copyError (src, -1, NULL, NULL);
|
||||
dst = uio_open (dstDir, newName, O_WRONLY | O_CREAT | O_EXCL
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
|
||||
if (dst == NULL)
|
||||
return copyError (src, NULL, NULL, NULL, NULL);
|
||||
|
||||
buf = HMalloc(BUFSIZE);
|
||||
// This was originally a statically allocated buffer,
|
||||
// but as this function might be run from a thread with
|
||||
// a small Stack, this is better.
|
||||
while (1) {
|
||||
numInBuf = read (src, buf, BUFSIZE);
|
||||
while (1)
|
||||
{
|
||||
numInBuf = uio_read (src, buf, BUFSIZE);
|
||||
if (numInBuf == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return copyError (src, dst, newName, buf);
|
||||
return copyError (src, dst, dstDir, newName, buf);
|
||||
}
|
||||
if (numInBuf == 0)
|
||||
break;
|
||||
|
||||
bufPtr = buf;
|
||||
do {
|
||||
numWritten = write (dst, bufPtr, numInBuf);
|
||||
do
|
||||
{
|
||||
numWritten = uio_write (dst, bufPtr, numInBuf);
|
||||
if (numWritten == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return copyError (src, dst, newName, buf);
|
||||
return copyError (src, dst, dstDir, newName, buf);
|
||||
}
|
||||
numInBuf -= numWritten;
|
||||
bufPtr += numWritten;
|
||||
@@ -98,22 +122,23 @@ copyFile (const char *srcName, const char *newName)
|
||||
}
|
||||
|
||||
HFree(buf);
|
||||
close(src);
|
||||
close(dst);
|
||||
uio_close(src);
|
||||
uio_close(dst);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes srcFd if it's not -1.
|
||||
* Closes dstFd if it's not -1.
|
||||
* Removes unlinkpath if it's not NULL.
|
||||
* Closes srcHandle if it's not -1.
|
||||
* Closes dstHandle if it's not -1.
|
||||
* Removes unlinkpath from the unlinkHandle dir if it's not NULL.
|
||||
* Frees 'buf' if not NULL.
|
||||
* Always returns -1.
|
||||
* errno is what was before the call.
|
||||
*/
|
||||
static int
|
||||
copyError(int srcFd, int dstFd, const char *unlinkPath, uint8 *buf)
|
||||
copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
|
||||
uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf)
|
||||
{
|
||||
int savedErrno;
|
||||
|
||||
@@ -123,14 +148,14 @@ copyError(int srcFd, int dstFd, const char *unlinkPath, uint8 *buf)
|
||||
fprintf (stderr, "Error while copying: %s\n", strerror (errno))
|
||||
#endif
|
||||
|
||||
if (srcFd >= 0)
|
||||
close (srcFd);
|
||||
if (srcHandle != NULL)
|
||||
uio_close (srcHandle);
|
||||
|
||||
if (dstFd >= 0)
|
||||
close (dstFd);
|
||||
if (dstHandle != NULL)
|
||||
uio_close (dstHandle);
|
||||
|
||||
if (unlinkPath != NULL)
|
||||
unlink (unlinkPath);
|
||||
uio_unlink (unlinkHandle, unlinkPath);
|
||||
|
||||
if (buf != NULL)
|
||||
HFree(buf);
|
||||
|
||||
@@ -30,12 +30,13 @@
|
||||
#include "libs/compiler.h"
|
||||
#include "misc.h"
|
||||
|
||||
static char *tempDir;
|
||||
static char *tempDirName;
|
||||
uio_DirHandle *tempDir;
|
||||
|
||||
static void
|
||||
removeTempDir (void)
|
||||
{
|
||||
rmdir (tempDir);
|
||||
rmdir (tempDirName);
|
||||
}
|
||||
|
||||
// Try if the null-terminated path 'dir' to a directory is valid
|
||||
@@ -53,6 +54,9 @@ tryTempDir (char *buf, size_t buflen, const char *dir)
|
||||
if (dir == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (dir[0] == '\0')
|
||||
return EINVAL;
|
||||
|
||||
len = strlen (dir);
|
||||
haveSlash = (dir[len - 1] == '/'
|
||||
#ifdef WIN32
|
||||
@@ -63,6 +67,17 @@ tryTempDir (char *buf, size_t buflen, const char *dir)
|
||||
return ENAMETOOLONG;
|
||||
|
||||
strcpy (buf, dir);
|
||||
#if 0
|
||||
//def WIN32
|
||||
{
|
||||
char *bufPtr;
|
||||
for (bufPtr = buf; *bufPtr != '\0'; bufPtr++)
|
||||
{
|
||||
if (*bufPtr == '\\')
|
||||
*bufPtr = '/';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!haveSlash)
|
||||
{
|
||||
buf[len] = '/';
|
||||
@@ -71,15 +86,18 @@ tryTempDir (char *buf, size_t buflen, const char *dir)
|
||||
}
|
||||
if (access (buf, R_OK | W_OK) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
getTempDir (char *buf, size_t buflen) {
|
||||
char cwd[PATH_MAX];
|
||||
|
||||
if (tryTempDir (buf, buflen, getenv("TMP")) &&
|
||||
tryTempDir (buf, buflen, getenv("TEMP")) &&
|
||||
tryTempDir (buf, buflen, "/tmp/") &&
|
||||
tryTempDir (buf, buflen, "./"))
|
||||
tryTempDir (buf, buflen, getcwd (cwd, sizeof cwd)))
|
||||
{
|
||||
fprintf (stderr, "Fatal Error: Cannot find a suitable location "
|
||||
"to store temporary files.\n");
|
||||
@@ -87,6 +105,35 @@ getTempDir (char *buf, size_t buflen) {
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the global var 'tempDir'
|
||||
static int
|
||||
mountTempDir(const char *name) {
|
||||
static uio_AutoMount *autoMount[] = { NULL };
|
||||
uio_MountHandle *tempHandle;
|
||||
extern uio_Repository *repository;
|
||||
|
||||
tempHandle = uio_mountDir (repository, "/tmp/",
|
||||
uio_FSTYPE_STDIO, NULL, NULL, name, autoMount,
|
||||
uio_MOUNT_TOP, NULL);
|
||||
if (tempHandle == NULL) {
|
||||
int saveErrno = errno;
|
||||
fprintf (stderr, "Fatal error: Couldn't mount temp dir '%s': "
|
||||
"%s\n", name, strerror (errno));
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tempDir = uio_openDir (repository, "/", 0);
|
||||
if (tempDir == NULL) {
|
||||
int saveErrno = errno;
|
||||
fprintf (stderr, "Fatal error: Could not open temp dir: %s\n",
|
||||
strerror (errno));
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NUM_TEMP_RETRIES 16
|
||||
// Number of files to try to open before giving up.
|
||||
void
|
||||
@@ -95,27 +142,29 @@ initTempDir (void) {
|
||||
DWORD num;
|
||||
int i;
|
||||
char *tempPtr;
|
||||
// Pointer to the location in the tempDir string where the
|
||||
// Pointer to the location in the tempDirName string where the
|
||||
// path to the temp dir ends and the dir starts.
|
||||
|
||||
tempDir = HMalloc (PATH_MAX);
|
||||
getTempDir (tempDir, PATH_MAX - 21);
|
||||
tempDirName = HMalloc (PATH_MAX);
|
||||
getTempDir (tempDirName, PATH_MAX - 21);
|
||||
// reserve 8 chars for dirname, 1 for slash, and 12 for filename
|
||||
len = strlen(tempDir);
|
||||
len = strlen(tempDirName);
|
||||
|
||||
num = ((DWORD) time (NULL));
|
||||
// num = GetTimeCounter () % 0xffffffff;
|
||||
tempPtr = tempDir + len;
|
||||
tempPtr = tempDirName + len;
|
||||
i = NUM_TEMP_RETRIES;
|
||||
while (i--)
|
||||
{
|
||||
sprintf (tempPtr, "%08lx", num + i);
|
||||
if (createDirectory (tempDir, 0700) == -1)
|
||||
if (createDirectory (tempDirName, 0700) == -1)
|
||||
continue;
|
||||
|
||||
// Success, we've got a temp dir.
|
||||
tempDir = HRealloc (tempDir, len + 9);
|
||||
tempDirName = HRealloc (tempDirName, len + 9);
|
||||
atexit (removeTempDir);
|
||||
if (mountTempDir (tempDirName) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -127,7 +176,7 @@ initTempDir (void) {
|
||||
|
||||
void
|
||||
unInitTempDir (void) {
|
||||
// nothing at the moment.
|
||||
uio_closeDir(tempDir);
|
||||
// the removing of the dir is handled via atexit
|
||||
}
|
||||
|
||||
@@ -137,10 +186,11 @@ char *
|
||||
tempFilePath (const char *filename) {
|
||||
static char file[PATH_MAX];
|
||||
|
||||
if (snprintf(file, PATH_MAX, "%s/%s", tempDir, filename) == -1) {
|
||||
if (snprintf (file, PATH_MAX, "%s/%s", tempDirName, filename) == -1) {
|
||||
fprintf (stderr, "Path to temp file too long.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ extern DRAWABLE _request_drawable (COUNT NumFrames, DRAWABLE_TYPE
|
||||
extern INTERSECT_CODE _clip_line (PRECT pClipRect, PBRESENHAM_LINE
|
||||
pLine);
|
||||
|
||||
extern MEM_HANDLE _GetCelData (FILE *fp, DWORD length);
|
||||
extern MEM_HANDLE _GetCelData (uio_Stream *fp, DWORD length);
|
||||
extern BOOLEAN _ReleaseCelData (MEM_HANDLE handle);
|
||||
|
||||
typedef PPRIMITIVE PRIMITIVEPTR;
|
||||
|
||||
@@ -17,20 +17,21 @@
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
#include "options.h"
|
||||
|
||||
extern char *_cur_resfile_name;
|
||||
|
||||
DWORD
|
||||
LoadCelFile (PVOID pStr)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
// FIXME: this theoretically needs a mechanism to prevent races
|
||||
if (_cur_resfile_name)
|
||||
// something else is loading resources atm
|
||||
return 0;
|
||||
|
||||
if ((fp = res_OpenResFile (pStr, "rb")) != NULL)
|
||||
if ((fp = res_OpenResFile (contentDir, pStr, "rb")) != NULL)
|
||||
{
|
||||
MEM_HANDLE hData;
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ typedef FONT_DESC *PFONT_DESC;
|
||||
|
||||
extern FONTPTR _CurFontPtr;
|
||||
|
||||
extern MEM_HANDLE _GetFontData (FILE *fp, DWORD length);
|
||||
extern MEM_HANDLE _GetFontData (uio_Stream *fp, DWORD length);
|
||||
extern BOOLEAN _ReleaseFontData (MEM_HANDLE handle);
|
||||
|
||||
#endif /* _FONT_H */
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "port.h"
|
||||
#include "sdl_common.h"
|
||||
#include "primitives.h"
|
||||
#include "sdluio.h"
|
||||
#include "libs/file.h"
|
||||
#include "options.h"
|
||||
|
||||
typedef struct anidata
|
||||
{
|
||||
@@ -415,11 +419,8 @@ Uint32 frame_mapRGBA (FRAMEPTR FramePtr,Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
||||
}
|
||||
|
||||
MEM_HANDLE
|
||||
_GetCelData (FILE *fp, DWORD length)
|
||||
_GetCelData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int omode;
|
||||
#endif
|
||||
int cel_ct, n;
|
||||
DWORD opos;
|
||||
char CurrentLine[1024], filename[1024];
|
||||
@@ -428,7 +429,7 @@ _GetCelData (FILE *fp, DWORD length)
|
||||
AniData ani[MAX_CELS];
|
||||
DRAWABLE Drawable;
|
||||
|
||||
opos = ftell (fp);
|
||||
opos = uio_ftell (fp);
|
||||
|
||||
{
|
||||
char *s1, *s2;
|
||||
@@ -446,37 +447,38 @@ _GetCelData (FILE *fp, DWORD length)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
omode = _setmode (fileno (fp), O_TEXT);
|
||||
#endif
|
||||
cel_ct = 0;
|
||||
while (fgets (CurrentLine, sizeof (CurrentLine), fp) && cel_ct < MAX_CELS)
|
||||
while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) && cel_ct < MAX_CELS)
|
||||
{
|
||||
/*char fnamestr[1000];
|
||||
sscanf(CurrentLine, "%s", fnamestr);
|
||||
fprintf (stderr, "imgload %s\n",fnamestr);*/
|
||||
|
||||
sscanf (CurrentLine, "%s %d %d %d %d", &filename[n],
|
||||
&ani[cel_ct].transparent_color, &ani[cel_ct].colormap_index,
|
||||
&ani[cel_ct].hotspot_x, &ani[cel_ct].hotspot_y);
|
||||
|
||||
if ((img[cel_ct] = IMG_Load (filename)) && img[cel_ct]->w > 0 &&
|
||||
img[cel_ct]->h > 0 && img[cel_ct]->format->BitsPerPixel >= 8)
|
||||
img[cel_ct] = sdluio_loadImage (contentDir, filename);
|
||||
if (img[cel_ct] == NULL)
|
||||
{
|
||||
++cel_ct;
|
||||
const char *err;
|
||||
|
||||
err = SDL_GetError();
|
||||
fprintf (stderr, "_GetCelData: Unable to load image!\n");
|
||||
if (err != NULL)
|
||||
fprintf (stderr, "SDL reports: %s\n", err);
|
||||
SDL_FreeSurface (img[cel_ct]);
|
||||
}
|
||||
else if (img[cel_ct])
|
||||
else if (img[cel_ct]->w < 0 || img[cel_ct]->h < 0 ||
|
||||
img[cel_ct]->format->BitsPerPixel < 8)
|
||||
{
|
||||
fprintf (stderr, "_GetCelData: Bad file!\n");
|
||||
SDL_FreeSurface (img[cel_ct]);
|
||||
}
|
||||
else
|
||||
{
|
||||
++cel_ct;
|
||||
}
|
||||
|
||||
if ((int)ftell (fp) - (int)opos >= (int)length)
|
||||
if ((int)uio_ftell (fp) - (int)opos >= (int)length)
|
||||
break;
|
||||
}
|
||||
#ifdef WIN32
|
||||
_setmode (fileno (fp), omode);
|
||||
#endif
|
||||
|
||||
Drawable = 0;
|
||||
if (cel_ct && (Drawable = AllocDrawable (cel_ct)))
|
||||
@@ -555,7 +557,7 @@ _ReleaseCelData (MEM_HANDLE handle)
|
||||
}
|
||||
|
||||
MEM_HANDLE
|
||||
_GetFontData (FILE *fp, DWORD length)
|
||||
_GetFontData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
DWORD cel_ct;
|
||||
COUNT num_entries;
|
||||
@@ -564,14 +566,15 @@ _GetFontData (FILE *fp, DWORD length)
|
||||
BOOLEAN found_chars;
|
||||
#define MAX_CELS 256
|
||||
SDL_Surface *img[MAX_CELS] = { 0 };
|
||||
char pattern[1024];
|
||||
char pattern[PATH_MAX];
|
||||
|
||||
if (_cur_resfile_name == 0)
|
||||
return (0);
|
||||
sprintf (pattern, "%s/*.*", _cur_resfile_name);
|
||||
|
||||
found_chars = FALSE;
|
||||
FontDir = CaptureDirEntryTable (LoadDirEntryTable (pattern, &num_entries));
|
||||
FontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir,
|
||||
_cur_resfile_name, ".", match_MATCH_SUBSTRING,
|
||||
&num_entries));
|
||||
while (num_entries--)
|
||||
{
|
||||
char *char_name;
|
||||
@@ -581,7 +584,7 @@ _GetFontData (FILE *fp, DWORD length)
|
||||
&& cel_ct >= FIRST_CHAR
|
||||
&& img[cel_ct -= FIRST_CHAR] == 0
|
||||
&& sprintf (pattern, "%s/%s", _cur_resfile_name, char_name)
|
||||
&& (img[cel_ct] = IMG_Load (pattern)))
|
||||
&& (img[cel_ct] = sdluio_loadImage (contentDir, pattern)))
|
||||
{
|
||||
if (img[cel_ct]->w > 0
|
||||
&& img[cel_ct]->h > 0
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
uqm_CFILES="3do_blt.c 3do_funcs.c 3do_getbody.c dcqueue.c opengl.c
|
||||
primitives.c pure.c rndzoom.c sdl_common.c
|
||||
canvas.c bbox.c 2xscalers.c"
|
||||
canvas.c bbox.c 2xscalers.c sdluio.c"
|
||||
|
||||
@@ -44,7 +44,7 @@ int GfxFlags = 0;
|
||||
|
||||
static TFB_Palette palette[256];
|
||||
|
||||
#define FPS_PERIOD 1000
|
||||
#define FPS_PERIOD 100
|
||||
int RenderedFrames = 0;
|
||||
|
||||
void
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "sdluio.h"
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include "SDL.h"
|
||||
#include "SDL_image.h"
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_rwops.h"
|
||||
#include "libs/misc.h"
|
||||
|
||||
static SDL_RWops *sdluio_makeRWops (uio_Stream *stream);
|
||||
|
||||
#if 0
|
||||
// For use for initialisation, using structure assignment.
|
||||
static SDL_RWops sdluio_templateRWops =
|
||||
{
|
||||
.seek = sdluio_seek,
|
||||
.read = sdluio_read,
|
||||
.write = sdluio_write,
|
||||
.close = sdluio_close,
|
||||
};
|
||||
#endif
|
||||
|
||||
SDL_Surface *
|
||||
sdluio_loadImage (uio_DirHandle *dir, const char *fileName) {
|
||||
uio_Stream *stream;
|
||||
SDL_RWops *rwops;
|
||||
SDL_Surface *result;
|
||||
|
||||
stream = uio_fopen (dir, fileName, "rb");
|
||||
if (stream == NULL)
|
||||
{
|
||||
SDL_SetError ("Couldn't open %s", fileName);
|
||||
return NULL;
|
||||
}
|
||||
rwops = sdluio_makeRWops (stream);
|
||||
result = IMG_Load_RW (rwops, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sdluio_seek (SDL_RWops *context, int offset, int whence) {
|
||||
if (uio_fseek ((uio_Stream *) context->hidden.unknown.data1, offset,
|
||||
whence) == -1)
|
||||
{
|
||||
SDL_SetError ("Error seeking in uio_Stream");
|
||||
return -1;
|
||||
}
|
||||
return uio_ftell ((uio_Stream *) context->hidden.unknown.data1);
|
||||
}
|
||||
|
||||
int
|
||||
sdluio_read (SDL_RWops *context, void *ptr, int size, int maxnum) {
|
||||
size_t numRead;
|
||||
|
||||
numRead = uio_fread (ptr, (size_t) size, (size_t) maxnum,
|
||||
(uio_Stream *) context->hidden.unknown.data1);
|
||||
if (numRead == 0 && uio_ferror ((uio_Stream *)
|
||||
context->hidden.unknown.data1))
|
||||
{
|
||||
SDL_SetError ("Error reading from uio_Stream");
|
||||
return 0;
|
||||
}
|
||||
return (int) numRead;
|
||||
}
|
||||
|
||||
int
|
||||
sdluio_write (SDL_RWops *context, const void *ptr, int size, int num) {
|
||||
size_t numWritten;
|
||||
|
||||
numWritten = uio_fwrite (ptr, (size_t) size, (size_t) num,
|
||||
(uio_Stream *) context->hidden.unknown.data1);
|
||||
if (numWritten == 0 && uio_ferror ((uio_Stream *)
|
||||
context->hidden.unknown.data1))
|
||||
{
|
||||
SDL_SetError ("Error writing to uio_Stream");
|
||||
return 0;
|
||||
}
|
||||
return (size_t) numWritten;
|
||||
}
|
||||
|
||||
int
|
||||
sdluio_close (SDL_RWops *context) {
|
||||
int result;
|
||||
|
||||
result = uio_fclose ((uio_Stream *) context->hidden.unknown.data1);
|
||||
HFree (context);
|
||||
return result;
|
||||
}
|
||||
|
||||
static SDL_RWops *
|
||||
sdluio_makeRWops (uio_Stream *stream) {
|
||||
SDL_RWops *result;
|
||||
|
||||
result = HMalloc (sizeof (SDL_RWops));
|
||||
#if 0
|
||||
*(struct SDL_RWops *) result = sdluio_templateRWops;
|
||||
// structure assignment
|
||||
#endif
|
||||
result->seek = sdluio_seek;
|
||||
result->read = sdluio_read;
|
||||
result->write = sdluio_write;
|
||||
result->close = sdluio_close;
|
||||
result->hidden.unknown.data1 = (void *) stream;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef _SDLUIO_H
|
||||
#define _SDLUIO_H
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include "SDL.h"
|
||||
#include "SDL_rwops.h"
|
||||
|
||||
SDL_Surface *sdluio_loadImage (uio_DirHandle *dir, const char *fileName);
|
||||
int sdluio_seek (SDL_RWops *context, int offset, int whence);
|
||||
int sdluio_read (SDL_RWops *context, void *ptr, int size, int maxnum);
|
||||
int sdluio_write (SDL_RWops *context, const void *ptr, int size, int num);
|
||||
int sdluio_close (SDL_RWops *context);
|
||||
|
||||
|
||||
#endif /* _SDLUIO_H */
|
||||
|
||||
@@ -76,47 +76,47 @@ static VControl_NameBinding control_names[] = {
|
||||
|
||||
static void
|
||||
initKeyConfig(void) {
|
||||
char userFile[PATH_MAX]; /* System-wide key config */
|
||||
int cb;
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
int errors;
|
||||
|
||||
cb = snprintf (userFile, PATH_MAX, "%skeys.cfg", configDir);
|
||||
assert (cb != -1);
|
||||
// Verified before: strlen (configDir) <= PATH_MAX - 13
|
||||
|
||||
if (fileExists (userFile)) {
|
||||
fp = res_OpenResFile (userFile, "rt");
|
||||
} else {
|
||||
if (copyFile ("starcon.key", userFile) == -1)
|
||||
fp = res_OpenResFile (configDir, "keys.cfg", "rt");
|
||||
if (fp == NULL)
|
||||
{
|
||||
if (copyFile (contentDir, "starcon.key",
|
||||
configDir, "keys.cfg") == -1)
|
||||
{
|
||||
fprintf(stderr, "Warning: Could not copy default key config "
|
||||
"to %s: %s.\n", userFile, strerror (errno));
|
||||
"to user config dir: %s.\n", strerror (errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Copying default key config file to %s.\n",
|
||||
userFile);
|
||||
fprintf(stderr, "Copying default key config file to user "
|
||||
"config dir.\n");
|
||||
}
|
||||
fp = res_OpenResFile ("starcon.key", "rt");
|
||||
fp = res_OpenResFile (contentDir, "starcon.key", "rt");
|
||||
}
|
||||
errors = VControl_ReadConfiguration (fp);
|
||||
res_CloseResFile (fp);
|
||||
if (errors)
|
||||
{
|
||||
fprintf (stderr, "%d errors encountered in key configuration file.\n", errors);
|
||||
fprintf (stderr, "%d errors encountered in key configuration "
|
||||
"file.\n", errors);
|
||||
/* This code should go away in 0.3; it's just
|
||||
* to force people to upgrade and forestall a
|
||||
* bunch of "none of my keys work anymore" bugs.
|
||||
*/
|
||||
if (errors > 5)
|
||||
{
|
||||
fprintf (stderr, "Hey! you haven't updated your keys.cfg to use the new system, have you?\nDelete %s and try again.\n", userFile);
|
||||
fprintf (stderr, "If you've done that and it STILL doesn't work, make sure your content/starcon.key is up to date.\n");
|
||||
fprintf (stderr, "Hey! you haven't updated your keys.cfg to "
|
||||
"use the new system, have you?\nDelete keys.cfg and "
|
||||
"try again.\n");
|
||||
fprintf (stderr, "If you've done that and it STILL doesn't "
|
||||
"work, make sure your content/starcon.key is up to"
|
||||
"date.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Repair your %s file to continue.\n", userFile);
|
||||
fprintf (stderr, "Repair your keys.cfg file to continue.\n");
|
||||
}
|
||||
|
||||
exit (1);
|
||||
|
||||
@@ -906,18 +906,18 @@ _next_token (parse_state *state)
|
||||
}
|
||||
|
||||
static void
|
||||
_next_line (parse_state *state, FILE *in)
|
||||
_next_line (parse_state *state, uio_Stream *in)
|
||||
{
|
||||
int i, ch = 0;
|
||||
state->linenum++;
|
||||
for (i = 0; i < LINE_SIZE-1; i++)
|
||||
{
|
||||
if (feof (in))
|
||||
if (uio_feof (in))
|
||||
{
|
||||
break;
|
||||
}
|
||||
ch = fgetc (in);
|
||||
if (ch == '#' || ch == '\n' || ch == -1)
|
||||
ch = uio_fgetc (in);
|
||||
if (ch == '#' || ch == '\n' || ch == EOF)
|
||||
{
|
||||
/* If this line is blank or all commented, include some
|
||||
* whitespace. This lets us detect EOF as a completely
|
||||
@@ -933,9 +933,9 @@ _next_line (parse_state *state, FILE *in)
|
||||
}
|
||||
state->line[i] = '\0';
|
||||
/* Skip to end of line */
|
||||
while (ch != '\n' && !feof (in))
|
||||
while (ch != '\n' && !uio_feof (in))
|
||||
{
|
||||
ch = fgetc (in);
|
||||
ch = uio_fgetc (in);
|
||||
}
|
||||
state->token[0] = 0;
|
||||
state->index = 0;
|
||||
@@ -1180,7 +1180,7 @@ _parse_config_line (parse_state *state)
|
||||
}
|
||||
|
||||
int
|
||||
VControl_ReadConfiguration (FILE *in)
|
||||
VControl_ReadConfiguration (uio_Stream *in)
|
||||
{
|
||||
parse_state ps;
|
||||
int errors;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#ifndef _VCONTROL_H_
|
||||
#define _VCONTROL_H_
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
/* Initialization routines */
|
||||
void VControl_Init (void);
|
||||
@@ -51,6 +53,6 @@ void VControl_RegisterNameTable (VControl_NameBinding *table);
|
||||
/* Dump a configuration file corresponding to the current bindings and names. */
|
||||
void VControl_Dump (FILE *out);
|
||||
/* Read a configuration file. Returns number of errors encountered. */
|
||||
int VControl_ReadConfiguration (FILE *in);
|
||||
int VControl_ReadConfiguration (uio_Stream *in);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
#ifndef _RESLIB_H
|
||||
#define _RESLIB_H
|
||||
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
#include "port.h"
|
||||
#include "memlib.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
typedef DWORD RESOURCE;
|
||||
typedef RESOURCE *PRESOURCE;
|
||||
@@ -49,24 +51,25 @@ typedef COUNT RES_PACKAGE;
|
||||
((RESOURCE)(i) << TYPE_BITS) | \
|
||||
((RESOURCE)(t)))
|
||||
|
||||
extern FILE *res_OpenResFile (PVOID filename, const char *mode);
|
||||
extern int ReadResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp);
|
||||
extern int WriteResFile (PVOID lpBuf, COUNT size, COUNT count, FILE
|
||||
*fp);
|
||||
extern int GetResFileChar (FILE *fp);
|
||||
extern int PutResFileChar (char ch, FILE *fp);
|
||||
extern long SeekResFile (FILE *fp, long offset, int whence);
|
||||
extern long TellResFile (FILE *fp);
|
||||
extern long LengthResFile (FILE *fp);
|
||||
extern BOOLEAN res_CloseResFile (FILE *fp);
|
||||
extern BOOLEAN DeleteResFile (PVOID filename);
|
||||
extern uio_Stream *res_OpenResFile (uio_DirHandle *dir, const char *filename,
|
||||
const char *mode);
|
||||
extern int ReadResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp);
|
||||
extern int WriteResFile (PVOID lpBuf, COUNT size, COUNT count,
|
||||
uio_Stream *fp);
|
||||
extern int GetResFileChar (uio_Stream *fp);
|
||||
extern int PutResFileChar (char ch, uio_Stream *fp);
|
||||
extern long SeekResFile (uio_Stream *fp, long offset, int whence);
|
||||
extern long TellResFile (uio_Stream *fp);
|
||||
extern long LengthResFile (uio_Stream *fp);
|
||||
extern BOOLEAN res_CloseResFile (uio_Stream *fp);
|
||||
extern BOOLEAN DeleteResFile (uio_DirHandle *dir, const char *filename);
|
||||
|
||||
extern MEM_HANDLE InitResourceSystem (PVOID resfile, COUNT resindex_type,
|
||||
BOOLEAN (*FileErrorFunc) (PVOID filename));
|
||||
extern BOOLEAN UninitResourceSystem (void);
|
||||
extern BOOLEAN InstallResTypeVectors (
|
||||
COUNT res_type,
|
||||
MEM_HANDLE (*load_func) (FILE *fp, DWORD len),
|
||||
MEM_HANDLE (*load_func) (uio_Stream *fp, DWORD len),
|
||||
BOOLEAN (*free_func) (MEM_HANDLE handle));
|
||||
extern MEM_HANDLE res_GetResource (RESOURCE res);
|
||||
extern MEM_HANDLE res_DetachResource (RESOURCE res);
|
||||
@@ -80,7 +83,7 @@ extern MEM_HANDLE OpenResourceIndexInstance (DWORD
|
||||
extern MEM_HANDLE SetResourceIndex (MEM_HANDLE hRH);
|
||||
extern BOOLEAN CloseResourceIndex (MEM_HANDLE hRH);
|
||||
|
||||
extern MEM_HANDLE GetResourceData (FILE *fp, DWORD
|
||||
extern MEM_HANDLE GetResourceData (uio_Stream *fp, DWORD
|
||||
length, MEM_FLAGS mem_flags);
|
||||
|
||||
#define RESOURCE_PRIORITY DEFAULT_MEM_PRIORITY
|
||||
@@ -102,7 +105,9 @@ typedef STRING_TABLE DIRENTRY_REF;
|
||||
typedef STRING DIRENTRY;
|
||||
typedef STRINGPTR DIRENTRYPTR;
|
||||
|
||||
extern DIRENTRY_REF LoadDirEntryTable (PSTR pattern,
|
||||
|
||||
extern DIRENTRY_REF LoadDirEntryTable (uio_DirHandle *dirHandle,
|
||||
const char *path, const char *pattern, match_MatchType matchType,
|
||||
PCOUNT pnum_entries);
|
||||
#define CaptureDirEntryTable CaptureStringTable
|
||||
#define ReleaseDirEntryTable ReleaseStringTable
|
||||
|
||||
@@ -16,281 +16,95 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* This file contains two versions of LoadDirEntryTable; one for Windows, and
|
||||
* one for other systems (POSIX).
|
||||
* It might be better to split this up in seperate files eventually.
|
||||
* - SvdB
|
||||
*/
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#include <ctype.h>
|
||||
#include "libs/strings/strintrn.h"
|
||||
|
||||
DIRENTRY_REF
|
||||
LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries)
|
||||
{
|
||||
COUNT num_entries, length;
|
||||
STRING_TABLE StringTable;
|
||||
STRING_TABLEPTR lpST;
|
||||
PDWORD lpLastOffs;
|
||||
|
||||
num_entries = 0;
|
||||
StringTable = 0;
|
||||
do
|
||||
{
|
||||
COUNT slen;
|
||||
long handle;
|
||||
struct _finddata_t f;
|
||||
|
||||
if (num_entries == 0)
|
||||
length = 0;
|
||||
else
|
||||
{
|
||||
slen = sizeof (STRING_TABLE_DESC)
|
||||
+ (num_entries * sizeof (DWORD));
|
||||
StringTable = AllocResourceData (slen + length, 0);
|
||||
LockStringTable (StringTable, &lpST);
|
||||
if (lpST == 0)
|
||||
{
|
||||
FreeStringTable (StringTable);
|
||||
StringTable = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lpST->StringCount = num_entries;
|
||||
lpLastOffs = &lpST->StringOffsets[0];
|
||||
*lpLastOffs = slen;
|
||||
|
||||
num_entries = 0;
|
||||
length = slen;
|
||||
}
|
||||
|
||||
handle = _findfirst (pattern, &f);
|
||||
if (handle != -1)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (f.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM))
|
||||
continue;
|
||||
|
||||
slen = strlen (f.name) + 1;
|
||||
length += slen;
|
||||
|
||||
if ((MEM_HANDLE)StringTable)
|
||||
{
|
||||
PSTR lpStr;
|
||||
PDWORD lpLo, lpHi;
|
||||
|
||||
lpLo = &lpST->StringOffsets[0];
|
||||
lpHi = lpLastOffs - 1;
|
||||
while (lpLo <= lpHi)
|
||||
{
|
||||
char c1, c2;
|
||||
PSTR pStr;
|
||||
COUNT LocLen;
|
||||
PDWORD lpMid;
|
||||
|
||||
lpMid = lpLo + ((lpHi - lpLo) >> 1);
|
||||
|
||||
LocLen = lpMid[1] - lpMid[0];
|
||||
if (LocLen > slen)
|
||||
LocLen = slen;
|
||||
|
||||
lpStr = (PSTR)lpST + lpMid[0];
|
||||
pStr = f.name;
|
||||
while (LocLen--
|
||||
&& (c1 = toupper (*lpStr++))
|
||||
== (c2 = toupper (*pStr++)))
|
||||
;
|
||||
|
||||
if (c1 <= c2)
|
||||
lpLo = lpMid + 1;
|
||||
else
|
||||
lpHi = lpMid - 1;
|
||||
}
|
||||
|
||||
lpStr = (PSTR)lpST + lpLo[0];
|
||||
memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]);
|
||||
strcpy (lpStr, f.name);
|
||||
|
||||
for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi)
|
||||
lpHi[1] = lpHi[0] + slen;
|
||||
}
|
||||
|
||||
++num_entries;
|
||||
} while (_findnext (handle, &f) == 0);
|
||||
_findclose (handle);
|
||||
}
|
||||
} while (num_entries && (MEM_HANDLE)StringTable == 0);
|
||||
|
||||
if ((MEM_HANDLE)StringTable == 0)
|
||||
*pnum_entries = 0;
|
||||
else
|
||||
{
|
||||
*pnum_entries = num_entries;
|
||||
|
||||
UnlockStringTable (StringTable);
|
||||
}
|
||||
|
||||
return ((DIRENTRY_REF)StringTable);
|
||||
}
|
||||
|
||||
#else /* ! defined(WIN32) */
|
||||
|
||||
#include "libs/strings/strintrn.h"
|
||||
#include <sys/types.h>
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <fnmatch.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
DIRENTRY_REF
|
||||
LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries)
|
||||
LoadDirEntryTable (uio_DirHandle *dirHandle, const char *path,
|
||||
const char *pattern, match_MatchType matchType, PCOUNT pnum_entries)
|
||||
{
|
||||
uio_DirList *dirList;
|
||||
COUNT num_entries, length;
|
||||
COUNT i;
|
||||
COUNT slen;
|
||||
uio_DirHandle *dir;
|
||||
STRING_TABLE StringTable;
|
||||
STRING_TABLEPTR lpST;
|
||||
PSTR lpStr;
|
||||
PDWORD lpLastOffs;
|
||||
PSTR slash; // Pointer inside pattern to the last /
|
||||
SBYTE path[PATH_MAX]; // buffer for a filename with path
|
||||
PSTR file; // Pointer inside path to the filename
|
||||
size_t pathlen; // length of path, excluding last / and filename
|
||||
|
||||
slash = (PSTR) strrchr ((const char *) pattern, '/');
|
||||
if (slash == NULL)
|
||||
{
|
||||
pathlen = 1;
|
||||
path[0] = '.';
|
||||
}
|
||||
else
|
||||
{
|
||||
pathlen = slash - pattern;
|
||||
memcpy (path, pattern, pathlen);
|
||||
pattern = slash + 1;
|
||||
}
|
||||
file = path + pathlen + 1;
|
||||
|
||||
dir = uio_openDirRelative (dirHandle, path, 0);
|
||||
assert(dir != NULL);
|
||||
dirList = uio_getDirList (dir, "", pattern, matchType);
|
||||
assert(dirList != NULL);
|
||||
num_entries = 0;
|
||||
StringTable = 0;
|
||||
do
|
||||
{
|
||||
COUNT slen;
|
||||
DIR *handle;
|
||||
|
||||
if (num_entries == 0)
|
||||
length = 0;
|
||||
else
|
||||
|
||||
// First, count the amount of space needed
|
||||
for (i = 0; i < dirList->numNames; i++)
|
||||
{
|
||||
slen = sizeof (STRING_TABLE_DESC)
|
||||
+ (num_entries * sizeof (DWORD));
|
||||
StringTable = AllocResourceData (slen + length, 0);
|
||||
LockStringTable (StringTable, &lpST);
|
||||
if (lpST == 0)
|
||||
{
|
||||
FreeStringTable (StringTable);
|
||||
StringTable = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lpST->StringCount = num_entries;
|
||||
lpLastOffs = &lpST->StringOffsets[0];
|
||||
*lpLastOffs = slen;
|
||||
|
||||
num_entries = 0;
|
||||
length = slen;
|
||||
}
|
||||
|
||||
|
||||
path[pathlen] = '\0'; // strip any file part
|
||||
handle = opendir((const char *) path);
|
||||
if (handle != NULL)
|
||||
{
|
||||
path[pathlen] = '/';
|
||||
// change the 0 char to a slash; a filename will be
|
||||
// attached here.
|
||||
while (1)
|
||||
{
|
||||
struct dirent *de;
|
||||
struct stat sb;
|
||||
|
||||
de = readdir(handle);
|
||||
if (de == NULL)
|
||||
break;
|
||||
if (de->d_name[0] == '.')
|
||||
if (dirList->names[i][0] == '.')
|
||||
{
|
||||
dirList->names[i] = NULL;
|
||||
continue;
|
||||
strcpy (file, de->d_name);
|
||||
// attach the filename to path
|
||||
if (stat(path, &sb) == -1)
|
||||
}
|
||||
if (uio_stat (dir, dirList->names[i], &sb) == -1)
|
||||
{
|
||||
dirList->names[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
if (!S_ISREG (sb.st_mode))
|
||||
continue;
|
||||
if (fnmatch(pattern, de->d_name, 0) != 0)
|
||||
continue;
|
||||
|
||||
slen = strlen (de->d_name) + 1;
|
||||
length += slen;
|
||||
|
||||
if ((MEM_HANDLE)StringTable)
|
||||
{
|
||||
PSTR lpStr;
|
||||
PDWORD lpLo, lpHi;
|
||||
|
||||
lpLo = &lpST->StringOffsets[0];
|
||||
lpHi = lpLastOffs - 1;
|
||||
while (lpLo <= lpHi)
|
||||
{
|
||||
char c1, c2;
|
||||
PSTR pStr;
|
||||
COUNT LocLen;
|
||||
PDWORD lpMid;
|
||||
|
||||
lpMid = lpLo + ((lpHi - lpLo) >> 1);
|
||||
|
||||
LocLen = lpMid[1] - lpMid[0];
|
||||
if (LocLen > slen)
|
||||
LocLen = slen;
|
||||
|
||||
lpStr = (PSTR)lpST + lpMid[0];
|
||||
pStr = de->d_name;
|
||||
while (LocLen--
|
||||
&& (c1 = toupper (*lpStr++))
|
||||
== (c2 = toupper (*pStr++)))
|
||||
;
|
||||
|
||||
if (c1 <= c2)
|
||||
lpLo = lpMid + 1;
|
||||
else
|
||||
lpHi = lpMid - 1;
|
||||
dirList->names[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
lpStr = (PSTR)lpST + lpLo[0];
|
||||
memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]);
|
||||
strcpy (lpStr, de->d_name);
|
||||
|
||||
for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi)
|
||||
lpHi[1] = lpHi[0] + slen;
|
||||
length += strlen (dirList->names[i]) + 1;
|
||||
num_entries++;
|
||||
}
|
||||
uio_closeDir (dir);
|
||||
|
||||
++num_entries;
|
||||
}
|
||||
closedir(handle);
|
||||
}
|
||||
} while (num_entries && (MEM_HANDLE)StringTable == 0);
|
||||
|
||||
if ((MEM_HANDLE)StringTable == 0)
|
||||
if (num_entries == 0) {
|
||||
uio_freeDirList(dirList);
|
||||
*pnum_entries = 0;
|
||||
else
|
||||
{
|
||||
*pnum_entries = num_entries;
|
||||
|
||||
UnlockStringTable (StringTable);
|
||||
return ((DIRENTRY_REF) 0);
|
||||
}
|
||||
|
||||
slen = sizeof (STRING_TABLE_DESC)
|
||||
+ (num_entries * sizeof (DWORD));
|
||||
StringTable = AllocResourceData (slen + length, 0);
|
||||
LockStringTable (StringTable, &lpST);
|
||||
if (lpST == 0)
|
||||
{
|
||||
FreeStringTable (StringTable);
|
||||
uio_freeDirList(dirList);
|
||||
*pnum_entries = 0;
|
||||
return ((DIRENTRY_REF) 0);
|
||||
}
|
||||
lpST->StringCount = num_entries;
|
||||
lpLastOffs = &lpST->StringOffsets[0];
|
||||
*lpLastOffs = slen;
|
||||
lpStr = (PSTR)lpST + slen;
|
||||
|
||||
for (i = 0; i < dirList->numNames; i++)
|
||||
{
|
||||
int size;
|
||||
if (dirList->names[i] == NULL)
|
||||
continue;
|
||||
size = strlen (dirList->names[i]) + 1;
|
||||
memcpy (lpStr, dirList->names[i], size);
|
||||
lpLastOffs[1] = lpLastOffs[0] + size;
|
||||
lpLastOffs++;
|
||||
lpStr += size;
|
||||
}
|
||||
|
||||
uio_freeDirList(dirList);
|
||||
*pnum_entries = num_entries;
|
||||
UnlockStringTable (StringTable);
|
||||
return ((DIRENTRY_REF) StringTable);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -24,33 +24,31 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "port.h"
|
||||
#include "resintrn.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
FILE *
|
||||
res_OpenResFile (PVOID filename, const char *mode)
|
||||
uio_Stream *
|
||||
res_OpenResFile (uio_DirHandle *dir, const char *filename, const char *mode)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
struct stat sb;
|
||||
|
||||
#ifdef WIN32
|
||||
if (stat (filename, &sb) == 0 && (sb.st_mode & _S_IFDIR))
|
||||
#else
|
||||
if (stat (filename, &sb) == 0 && S_ISDIR(sb.st_mode))
|
||||
#endif
|
||||
return ((FILE *) ~0);
|
||||
if (uio_stat (dir, filename, &sb) == 0 && S_ISDIR(sb.st_mode))
|
||||
return ((uio_Stream *) ~0);
|
||||
|
||||
fp = fopen (filename, mode);
|
||||
fp = uio_fopen (dir, filename, mode);
|
||||
|
||||
return (fp);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
res_CloseResFile (FILE *fp)
|
||||
res_CloseResFile (uio_Stream *fp)
|
||||
{
|
||||
if (fp)
|
||||
{
|
||||
if (fp != (FILE *)~0)
|
||||
fclose (fp);
|
||||
if (fp != (uio_Stream *)~0)
|
||||
uio_fclose (fp);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
@@ -58,85 +56,80 @@ res_CloseResFile (FILE *fp)
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
DeleteResFile (PVOID filename)
|
||||
DeleteResFile (uio_DirHandle *dir, const char *filename)
|
||||
{
|
||||
return (remove (filename) == 0);
|
||||
return (uio_unlink (dir, filename) == 0);
|
||||
}
|
||||
|
||||
int
|
||||
ReadResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp)
|
||||
ReadResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = fread (lpBuf, size, count, fp);
|
||||
retval = uio_fread (lpBuf, size, count, fp);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
int
|
||||
WriteResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp)
|
||||
WriteResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = fwrite (lpBuf, size, count, fp);
|
||||
retval = uio_fwrite (lpBuf, size, count, fp);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
int
|
||||
GetResFileChar (FILE *fp)
|
||||
GetResFileChar (uio_Stream *fp)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = getc (fp);
|
||||
retval = uio_getc (fp);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
int
|
||||
PutResFileChar (char ch, FILE *fp)
|
||||
PutResFileChar (char ch, uio_Stream *fp)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = putc (ch, fp);
|
||||
|
||||
retval = uio_putc (ch, fp);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
long
|
||||
SeekResFile (FILE *fp, long offset, int whence)
|
||||
SeekResFile (uio_Stream *fp, long offset, int whence)
|
||||
{
|
||||
long retval;
|
||||
|
||||
retval = fseek (fp, offset, whence);
|
||||
retval = uio_fseek (fp, offset, whence);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
long
|
||||
TellResFile (FILE *fp)
|
||||
TellResFile (uio_Stream *fp)
|
||||
{
|
||||
long retval;
|
||||
|
||||
retval = ftell (fp);
|
||||
retval = uio_ftell (fp);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
long
|
||||
LengthResFile (FILE *fp)
|
||||
{
|
||||
if (fp == (FILE *)~0)
|
||||
return (1);
|
||||
#ifdef WIN32
|
||||
return filelength (fileno (fp));
|
||||
#else
|
||||
LengthResFile (uio_Stream *fp)
|
||||
{
|
||||
struct stat sb;
|
||||
if (fstat(fileno(fp), &sb) == -1)
|
||||
|
||||
if (fp == (uio_Stream *)~0)
|
||||
return (1);
|
||||
if (uio_fstat(uio_streamHandle(fp), &sb) == -1)
|
||||
return 1;
|
||||
return sb.st_size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "resintrn.h"
|
||||
#include "port.h"
|
||||
#include "options.h"
|
||||
|
||||
char *_cur_resfile_name;
|
||||
|
||||
@@ -156,7 +157,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package)
|
||||
{
|
||||
BOOLEAN DanglingOpen;
|
||||
MEM_HANDLE hList;
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
COUNT t, num_types, num_instances;
|
||||
DWORD file_offs, data_len;
|
||||
RES_HANDLE_LISTPTR ResourceHandleListPtr;
|
||||
@@ -221,7 +222,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package)
|
||||
fp = ResHeaderPtr->res_fp;
|
||||
else
|
||||
{
|
||||
fp = res_OpenResFile (file_buf, "rb");
|
||||
fp = res_OpenResFile (contentDir, file_buf, "rb");
|
||||
if (fp)
|
||||
DanglingOpen = TRUE;
|
||||
}
|
||||
@@ -298,7 +299,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package)
|
||||
{
|
||||
get_resource_filename (ResHeaderPtr, file_buf, (COUNT)data_len);
|
||||
|
||||
fp = res_OpenResFile (file_buf, "rb");
|
||||
fp = res_OpenResFile (contentDir, file_buf, "rb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
#if 1 // def DEBUG
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MEM_HANDLE (*load_func) (FILE *fp, DWORD len);
|
||||
MEM_HANDLE (*load_func) (uio_Stream *fp, DWORD len);
|
||||
BOOLEAN (*free_func) (MEM_HANDLE handle);
|
||||
} RES_VECTORS;
|
||||
|
||||
@@ -50,7 +50,7 @@ typedef BYTE RES_FLAGS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FILE *res_fp;
|
||||
uio_Stream *res_fp;
|
||||
|
||||
DWORD packmem_list_offs;
|
||||
DWORD path_list_offs;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "declib.h"
|
||||
|
||||
MEM_HANDLE
|
||||
GetResourceData (FILE *fp, DWORD length, MEM_FLAGS mem_flags)
|
||||
GetResourceData (uio_Stream *fp, DWORD length, MEM_FLAGS mem_flags)
|
||||
{
|
||||
MEM_HANDLE RData;
|
||||
DECODE_REF fh;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "resintrn.h"
|
||||
#include "options.h"
|
||||
|
||||
static MEM_HANDLE hIndexList;
|
||||
|
||||
@@ -83,7 +84,7 @@ _sub_index_list (MEM_HANDLE hRH)
|
||||
}
|
||||
|
||||
MEM_HANDLE
|
||||
_GetResFileData (FILE *res_fp, DWORD flen)
|
||||
_GetResFileData (uio_Stream *res_fp, DWORD flen)
|
||||
{
|
||||
UWORD lo_word, hi_word;
|
||||
DWORD res_offs, remainder;
|
||||
@@ -250,17 +251,17 @@ UninitResourceSystem (void)
|
||||
MEM_HANDLE
|
||||
OpenResourceIndexFile (PVOID resfile)
|
||||
{
|
||||
FILE *res_fp;
|
||||
uio_Stream *res_fp;
|
||||
char fullname[256];
|
||||
|
||||
strcpy (fullname, resfile);
|
||||
if ((res_fp = res_OpenResFile (fullname, "rb")) == 0)
|
||||
if ((res_fp = res_OpenResFile (contentDir, fullname, "rb")) == 0)
|
||||
{
|
||||
sprintf (fullname, "%s.pkg", (char *) resfile);
|
||||
if ((res_fp = res_OpenResFile (fullname, "rb")) == 0)
|
||||
if ((res_fp = res_OpenResFile (contentDir, fullname, "rb")) == 0)
|
||||
{
|
||||
sprintf (fullname, "%s.ndx", (char *) resfile);
|
||||
res_fp = res_OpenResFile (fullname, "rb");
|
||||
res_fp = res_OpenResFile (contentDir, fullname, "rb");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +316,7 @@ CloseResourceIndex (MEM_HANDLE hRH)
|
||||
{
|
||||
if (UnlockResourceHeader (hRH))
|
||||
{
|
||||
FILE *res_fp;
|
||||
uio_Stream *res_fp;
|
||||
INDEX_HEADERPTR ResHeaderPtr;
|
||||
|
||||
ResHeaderPtr = LockResourceHeader (hRH);
|
||||
@@ -379,7 +380,7 @@ CloseResourceIndex (MEM_HANDLE hRH)
|
||||
|
||||
BOOLEAN
|
||||
InstallResTypeVectors (COUNT res_type,
|
||||
MEM_HANDLE (*load_func) (FILE *fp, DWORD len),
|
||||
MEM_HANDLE (*load_func) (uio_Stream *fp, DWORD len),
|
||||
BOOLEAN (*free_func) (MEM_HANDLE handle))
|
||||
{
|
||||
INDEX_HEADERPTR ResHeaderPtr;
|
||||
|
||||
@@ -54,7 +54,7 @@ do \
|
||||
#define DoLoad(pRH, t,fp,len) (*(pRH)->TypeList[t-1].func_vectors.load_func)(fp,len)
|
||||
#define DoFree(pRH, t,h) (*(pRH)->TypeList[t-1].func_vectors.free_func)(h)
|
||||
|
||||
extern MEM_HANDLE _GetResFileData (FILE *res_fp, DWORD flen);
|
||||
extern MEM_HANDLE _GetResFileData (uio_Stream *res_fp, DWORD flen);
|
||||
#define IsIndexType(pRH, t) ((pRH)->TypeList[t-1].func_vectors.load_func \
|
||||
==_GetResFileData)
|
||||
|
||||
|
||||
@@ -27,12 +27,17 @@
|
||||
#include <string.h>
|
||||
#include <vorbis/codec.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include "port.h"
|
||||
#include "libs/misc.h"
|
||||
#include "libs/uio.h"
|
||||
#include "decoder.h"
|
||||
#include "wav.h"
|
||||
#include "libs/sound/sound_common.h"
|
||||
#include "mikmod/mikmod.h"
|
||||
|
||||
extern bool fileExists2(uio_DirHandle *dir, const char *fileName);
|
||||
// Can't '#include "libs/file.h"' due to some type conflicts.
|
||||
|
||||
MIKMODAPI extern struct MDRIVER drv_openal;
|
||||
|
||||
static char *decoder_info_wav = "Wav";
|
||||
@@ -42,35 +47,25 @@ static char *decoder_info_nul = "None";
|
||||
|
||||
TFB_DecoderFormats decoder_formats;
|
||||
|
||||
static int file_exists (char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
if ((fp = fopen(filename, "rb")) == NULL)
|
||||
return 0;
|
||||
|
||||
fclose (fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t ogg_read (void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
return fread (ptr, size, nmemb, datasource);
|
||||
return uio_fread ((uio_Stream *) ptr, size, nmemb, datasource);
|
||||
}
|
||||
|
||||
static int ogg_seek (void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
long off = (long) offset;
|
||||
return fseek (datasource, off, whence);
|
||||
return uio_fseek ((uio_Stream *) datasource, off, whence);
|
||||
}
|
||||
|
||||
static int ogg_close (void *datasource)
|
||||
{
|
||||
return fclose (datasource);
|
||||
return uio_fclose ((uio_Stream *) datasource);
|
||||
}
|
||||
|
||||
static long ogg_tell(void *datasource)
|
||||
{
|
||||
return ftell (datasource);
|
||||
return uio_ftell ((uio_Stream *) datasource);
|
||||
}
|
||||
|
||||
static const ov_callbacks ogg_callbacks =
|
||||
@@ -152,13 +147,13 @@ void SoundDecoder_Uninit (void)
|
||||
MikMod_Exit ();
|
||||
}
|
||||
|
||||
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
uint32 startTime, sint32 runTime)
|
||||
TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir, char *filename,
|
||||
uint32 buffer_size, uint32 startTime, sint32 runTime)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = strlen (filename) - 3;
|
||||
if (!file_exists (filename))
|
||||
if (!fileExists2 (dir, filename))
|
||||
{
|
||||
if (runTime)
|
||||
{
|
||||
@@ -180,6 +175,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
|
||||
decoder->decoder_info = decoder_info_nul;
|
||||
decoder->type = SOUNDDECODER_NULL;
|
||||
decoder->dir = dir;
|
||||
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
|
||||
strcpy (decoder->filename, filename);
|
||||
decoder->data = NULL;
|
||||
@@ -208,6 +204,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
decoder->length = 0; // FIXME should be calculated
|
||||
decoder->decoder_info = decoder_info_wav;
|
||||
decoder->type = SOUNDDECODER_WAV;
|
||||
decoder->dir = dir;
|
||||
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
|
||||
decoder->start_sample = 0;
|
||||
decoder->end_sample = 0;
|
||||
@@ -223,7 +220,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
|
||||
//fprintf (stderr, "SoundDecoder_Load(): %s interpreted as mod\n", filename);
|
||||
|
||||
mod = Player_Load (filename, 4, 0);
|
||||
mod = Player_Load (dir, filename, 4, 0);
|
||||
if (!mod)
|
||||
{
|
||||
fprintf (stderr, "SoundDecoder_Load(): couldn't load %s\n", filename);
|
||||
@@ -245,6 +242,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
decoder->length = 0; // FIXME way to obtain this from mikmod?
|
||||
decoder->decoder_info = decoder_info_mod;
|
||||
decoder->type = SOUNDDECODER_MOD;
|
||||
decoder->dir = dir;
|
||||
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
|
||||
decoder->start_sample = 0;
|
||||
decoder->end_sample = 0;
|
||||
@@ -257,7 +255,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
else if (!strcmp (&filename[i], "ogg"))
|
||||
{
|
||||
int rc;
|
||||
FILE *vfp;
|
||||
uio_Stream *vfp;
|
||||
OggVorbis_File *vf;
|
||||
vorbis_info *vinfo;
|
||||
TFB_SoundDecoder *decoder;
|
||||
@@ -270,22 +268,20 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
fprintf (stderr, "SoundDecoder_Load(): couldn't allocate mem for OggVorbis_File\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((vfp = fopen (filename, "r")) == NULL)
|
||||
|
||||
vfp = uio_fopen (dir, filename, "rb");
|
||||
if (vfp == NULL)
|
||||
{
|
||||
fprintf (stderr, "SoundDecoder_Load(): couldn't open %s\n", filename);
|
||||
HFree (vf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
_setmode( _fileno(vfp), _O_BINARY);
|
||||
#endif
|
||||
|
||||
rc = ov_open_callbacks (vfp, vf, NULL, 0, ogg_callbacks);
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf (stderr, "SoundDecoder_Load(): ov_open_callbacks failed for %s, error code %d\n", filename, rc);
|
||||
fclose (vfp);
|
||||
uio_fclose (vfp);
|
||||
HFree (vf);
|
||||
return NULL;
|
||||
}
|
||||
@@ -330,6 +326,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
|
||||
decoder->decoder_info = decoder_info_ogg;
|
||||
decoder->type = SOUNDDECODER_OGG;
|
||||
decoder->dir = dir;
|
||||
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
|
||||
strcpy (decoder->filename, filename);
|
||||
decoder->data = vf;
|
||||
@@ -506,8 +503,9 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
|
||||
{
|
||||
case SOUNDDECODER_WAV:
|
||||
{
|
||||
LoadWAVFile (decoder->filename ,&decoder->format, &decoder->buffer,
|
||||
&decoder->buffer_size, &decoder->frequency, decoder_formats.want_big_endian);
|
||||
LoadWAVFile (decoder->dir, decoder->filename, &decoder->format,
|
||||
&decoder->buffer, &decoder->buffer_size,
|
||||
&decoder->frequency, decoder_formats.want_big_endian);
|
||||
|
||||
if (decoder->buffer_size != 0)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#ifndef DECODER_H
|
||||
#define DECODER_H
|
||||
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma comment (lib, "vorbisfile.lib")
|
||||
@@ -51,6 +53,7 @@ typedef struct tfb_sounddecoder
|
||||
|
||||
// semi-private
|
||||
sint32 type;
|
||||
uio_DirHandle *dir;
|
||||
char *filename;
|
||||
void *data;
|
||||
uint32 pos;
|
||||
@@ -82,8 +85,8 @@ extern TFB_DecoderFormats decoder_formats;
|
||||
void SoundDecoder_SwapWords (uint16* data, uint32 size);
|
||||
sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats);
|
||||
void SoundDecoder_Uninit (void);
|
||||
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
|
||||
uint32 startTime, sint32 runTime);
|
||||
TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir,
|
||||
char *filename, uint32 buffer_size, uint32 startTime, sint32 runTime);
|
||||
uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder);
|
||||
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
|
||||
float SoundDecoder_GetTime (TFB_SoundDecoder *decoder);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -324,8 +326,8 @@ typedef struct SAMPLE {
|
||||
|
||||
/* Sample functions */
|
||||
|
||||
MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);
|
||||
MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*);
|
||||
MIKMODAPI extern SAMPLE *Sample_Load(uio_DirHandle*,CHAR*);
|
||||
MIKMODAPI extern SAMPLE *Sample_LoadFP(uio_Stream*);
|
||||
MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
|
||||
MIKMODAPI extern void Sample_Free(SAMPLE*);
|
||||
MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE);
|
||||
@@ -527,10 +529,10 @@ MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */
|
||||
MIKMODAPI extern MODULE* Player_LoadRW(SDL_RWops*,int,BOOL);
|
||||
#endif /* USE_RWOPS */
|
||||
/* End SDL_RWops compatability */
|
||||
MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL);
|
||||
MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL);
|
||||
MIKMODAPI extern MODULE* Player_Load(uio_DirHandle *, CHAR*,int,BOOL);
|
||||
MIKMODAPI extern MODULE* Player_LoadFP(uio_Stream*,int,BOOL);
|
||||
MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL);
|
||||
MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*);
|
||||
MIKMODAPI extern CHAR* Player_LoadTitle(uio_DirHandle*,CHAR*);
|
||||
MIKMODAPI extern void Player_Free(MODULE*);
|
||||
MIKMODAPI extern void Player_Start(MODULE*);
|
||||
MIKMODAPI extern BOOL Player_Active(void);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#endif
|
||||
|
||||
#include "mikmod_build.h"
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
#ifdef macintosh
|
||||
#ifndef __MWERKS__
|
||||
@@ -142,13 +144,13 @@ extern void _mm_delete_rwops_reader (MREADER*);
|
||||
#endif /* USE_RWOPS */
|
||||
/* End SDL_RWops compatability */
|
||||
|
||||
extern MREADER* _mm_new_file_reader(FILE* fp);
|
||||
extern MREADER* _mm_new_file_reader(uio_Stream* fp);
|
||||
extern void _mm_delete_file_reader(MREADER*);
|
||||
|
||||
extern MWRITER* _mm_new_file_writer(FILE *fp);
|
||||
extern MWRITER* _mm_new_file_writer(uio_Stream *fp);
|
||||
extern void _mm_delete_file_writer(MWRITER*);
|
||||
|
||||
extern BOOL _mm_FileExists(CHAR *fname);
|
||||
extern BOOL _mm_FileExists(uio_DirHandle *dir,CHAR *fname);
|
||||
|
||||
#define _mm_write_SBYTE(x,y) y->Put(y,(int)x)
|
||||
#define _mm_write_UBYTE(x,y) y->Put(y,(int)x)
|
||||
@@ -169,7 +171,7 @@ extern BOOL _mm_FileExists(CHAR *fname);
|
||||
|
||||
extern void _mm_iobase_setcur(MREADER*);
|
||||
extern void _mm_iobase_revert(void);
|
||||
extern FILE *_mm_fopen(CHAR*,CHAR*);
|
||||
extern uio_Stream *_mm_fopen(uio_DirHandle *,CHAR*,CHAR*);
|
||||
extern void _mm_write_string(CHAR*,MWRITER*);
|
||||
extern int _mm_read_string (CHAR*,int,MREADER*);
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mikmod_internals.h"
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
|
||||
MREADER *modreader;
|
||||
@@ -372,20 +374,20 @@ static CHAR* Player_LoadTitle_internal(MREADER *reader)
|
||||
return l->LoadTitle();
|
||||
}
|
||||
|
||||
CHAR* Player_LoadTitle(CHAR* filename)
|
||||
CHAR* Player_LoadTitle(uio_DirHandle *dir, CHAR* filename)
|
||||
{
|
||||
CHAR* result=NULL;
|
||||
FILE* fp;
|
||||
uio_Stream* fp;
|
||||
MREADER* reader;
|
||||
|
||||
if((fp=_mm_fopen(filename,"rb"))) {
|
||||
if((fp=_mm_fopen(dir, filename,"rb"))) {
|
||||
if((reader=_mm_new_file_reader(fp))) {
|
||||
MUTEX_LOCK(lists);
|
||||
result=Player_LoadTitle_internal(reader);
|
||||
MUTEX_UNLOCK(lists);
|
||||
_mm_delete_file_reader(reader);
|
||||
}
|
||||
fclose(fp);
|
||||
uio_fclose(fp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -507,7 +509,7 @@ MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
|
||||
|
||||
/* Loads a module given a file pointer.
|
||||
File is loaded from the current file seek position. */
|
||||
MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
|
||||
MODULE* Player_LoadFP(uio_Stream* fp,int maxchan,BOOL curious)
|
||||
{
|
||||
MODULE* result=NULL;
|
||||
struct MREADER* reader=_mm_new_file_reader (fp);
|
||||
@@ -521,14 +523,14 @@ MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
|
||||
|
||||
/* Open a module via its filename. The loader will initialize the specified
|
||||
song-player 'player'. */
|
||||
MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious)
|
||||
MODULE* Player_Load(uio_DirHandle *dir,CHAR* filename,int maxchan,BOOL curious)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
MODULE *mf=NULL;
|
||||
|
||||
if((fp=_mm_fopen(filename,"rb"))) {
|
||||
if((fp=_mm_fopen(dir, filename,"rb"))) {
|
||||
mf=Player_LoadFP(fp,maxchan,curious);
|
||||
fclose(fp);
|
||||
uio_fclose(fp);
|
||||
}
|
||||
return mf;
|
||||
}
|
||||
|
||||
@@ -142,23 +142,23 @@ void _mm_delete_rwops_reader (MREADER* reader)
|
||||
|
||||
*/
|
||||
|
||||
FILE* _mm_fopen(CHAR* fname,CHAR* attrib)
|
||||
uio_Stream* _mm_fopen(uio_DirHandle* dir,CHAR* fname,CHAR* attrib)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
if(!(fp=fopen(fname,attrib))) {
|
||||
if(!(fp=uio_fopen(dir,fname,attrib))) {
|
||||
_mm_errno = MMERR_OPENING_FILE;
|
||||
if(_mm_errorhandler) _mm_errorhandler();
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
BOOL _mm_FileExists(CHAR* fname)
|
||||
BOOL _mm_FileExists(uio_DirHandle* dir,CHAR* fname)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
if(!(fp=fopen(fname,"r"))) return 0;
|
||||
fclose(fp);
|
||||
if(!(fp=uio_fopen(dir, fname,"rb"))) return 0;
|
||||
uio_fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -180,36 +180,36 @@ void _mm_iobase_revert(void)
|
||||
|
||||
typedef struct MFILEREADER {
|
||||
MREADER core;
|
||||
FILE* file;
|
||||
uio_Stream* file;
|
||||
} MFILEREADER;
|
||||
|
||||
static BOOL _mm_FileReader_Eof(MREADER* reader)
|
||||
{
|
||||
return feof(((MFILEREADER*)reader)->file);
|
||||
return uio_feof(((MFILEREADER*)reader)->file);
|
||||
}
|
||||
|
||||
static BOOL _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size)
|
||||
{
|
||||
return fread(ptr,size,1,((MFILEREADER*)reader)->file);
|
||||
return uio_fread(ptr,size,1,((MFILEREADER*)reader)->file);
|
||||
}
|
||||
|
||||
static int _mm_FileReader_Get(MREADER* reader)
|
||||
{
|
||||
return fgetc(((MFILEREADER*)reader)->file);
|
||||
return uio_fgetc(((MFILEREADER*)reader)->file);
|
||||
}
|
||||
|
||||
static BOOL _mm_FileReader_Seek(MREADER* reader,long offset,int whence)
|
||||
{
|
||||
return fseek(((MFILEREADER*)reader)->file,
|
||||
return uio_fseek(((MFILEREADER*)reader)->file,
|
||||
(whence==SEEK_SET)?offset+_mm_iobase:offset,whence);
|
||||
}
|
||||
|
||||
static long _mm_FileReader_Tell(MREADER* reader)
|
||||
{
|
||||
return ftell(((MFILEREADER*)reader)->file)-_mm_iobase;
|
||||
return uio_ftell(((MFILEREADER*)reader)->file)-_mm_iobase;
|
||||
}
|
||||
|
||||
MREADER *_mm_new_file_reader(FILE* fp)
|
||||
MREADER *_mm_new_file_reader(uio_Stream* fp)
|
||||
{
|
||||
MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER));
|
||||
if (reader) {
|
||||
@@ -232,30 +232,30 @@ void _mm_delete_file_reader (MREADER* reader)
|
||||
|
||||
typedef struct MFILEWRITER {
|
||||
MWRITER core;
|
||||
FILE* file;
|
||||
uio_Stream* file;
|
||||
} MFILEWRITER;
|
||||
|
||||
static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence)
|
||||
{
|
||||
return fseek(((MFILEWRITER*)writer)->file,offset,whence);
|
||||
return uio_fseek(((MFILEWRITER*)writer)->file,offset,whence);
|
||||
}
|
||||
|
||||
static long _mm_FileWriter_Tell(MWRITER* writer)
|
||||
{
|
||||
return ftell(((MFILEWRITER*)writer)->file);
|
||||
return uio_ftell(((MFILEWRITER*)writer)->file);
|
||||
}
|
||||
|
||||
static BOOL _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size)
|
||||
{
|
||||
return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size);
|
||||
return (uio_fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size);
|
||||
}
|
||||
|
||||
static BOOL _mm_FileWriter_Put(MWRITER* writer,int value)
|
||||
{
|
||||
return fputc(value,((MFILEWRITER*)writer)->file);
|
||||
return uio_fputc(value,((MFILEWRITER*)writer)->file);
|
||||
}
|
||||
|
||||
MWRITER *_mm_new_file_writer(FILE* fp)
|
||||
MWRITER *_mm_new_file_writer(uio_Stream* fp)
|
||||
{
|
||||
MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER));
|
||||
if (writer) {
|
||||
|
||||
@@ -143,7 +143,7 @@ SAMPLE* Sample_LoadGeneric(MREADER* reader)
|
||||
return result;
|
||||
}
|
||||
|
||||
SAMPLE* Sample_LoadFP(FILE *fp)
|
||||
SAMPLE* Sample_LoadFP(uio_Stream *fp)
|
||||
{
|
||||
SAMPLE* result=NULL;
|
||||
MREADER* reader;
|
||||
@@ -155,15 +155,15 @@ SAMPLE* Sample_LoadFP(FILE *fp)
|
||||
return result;
|
||||
}
|
||||
|
||||
SAMPLE* Sample_Load(CHAR* filename)
|
||||
SAMPLE* Sample_Load(uio_DirHandle* dir,CHAR* filename)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
SAMPLE *si=NULL;
|
||||
|
||||
if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;
|
||||
if((fp=_mm_fopen(filename,"rb"))) {
|
||||
if((fp=_mm_fopen(dir,filename,"rb"))) {
|
||||
si = Sample_LoadFP(fp);
|
||||
fclose(fp);
|
||||
uio_fclose(fp);
|
||||
}
|
||||
return si;
|
||||
}
|
||||
|
||||
@@ -53,52 +53,52 @@ typedef struct
|
||||
|
||||
|
||||
void
|
||||
LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
|
||||
uint32 *freq, bool want_big_endian)
|
||||
LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format,
|
||||
void **data, uint32 *size, uint32 *freq, bool want_big_endian)
|
||||
{
|
||||
WAVChunkHdr_Struct ChunkHdr;
|
||||
WAVFileHdr_Struct FileHdr;
|
||||
WAVFmtHdr_Struct FmtHdr;
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
*format = decoder_formats.mono16;
|
||||
*data = NULL;
|
||||
*size = 0;
|
||||
*freq = 22050;
|
||||
|
||||
fp = fopen (file, "rb");
|
||||
fp = uio_fopen (dir, file, "rb");
|
||||
if (fp)
|
||||
{
|
||||
fread(&FileHdr.Id, 4, 1, fp);
|
||||
uio_fread(&FileHdr.Id, 4, 1, fp);
|
||||
FileHdr.Id = UQM_SwapLE32 (FileHdr.Id);
|
||||
fread(&FileHdr.Size, 4, 1, fp);
|
||||
uio_fread(&FileHdr.Size, 4, 1, fp);
|
||||
FileHdr.Size = UQM_SwapLE32 (FileHdr.Size);
|
||||
fread(&FileHdr.Type, 4, 1, fp);
|
||||
uio_fread(&FileHdr.Type, 4, 1, fp);
|
||||
FileHdr.Type = UQM_SwapLE32 (FileHdr.Type);
|
||||
|
||||
FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4;
|
||||
while (FileHdr.Size != 0)
|
||||
{
|
||||
if (!fread (&ChunkHdr.Id, 4, 1, fp))
|
||||
if (!uio_fread (&ChunkHdr.Id, 4, 1, fp))
|
||||
break;
|
||||
ChunkHdr.Id = UQM_SwapLE32 (ChunkHdr.Id);
|
||||
if (!fread (&ChunkHdr.Size, 4, 1, fp))
|
||||
if (!uio_fread (&ChunkHdr.Size, 4, 1, fp))
|
||||
break;
|
||||
ChunkHdr.Size = UQM_SwapLE32 (ChunkHdr.Size);
|
||||
|
||||
if (ChunkHdr.Id == FMT)
|
||||
{
|
||||
fread (&FmtHdr.Format, 2, 1, fp);
|
||||
uio_fread (&FmtHdr.Format, 2, 1, fp);
|
||||
FmtHdr.Format = UQM_SwapLE16 (FmtHdr.Format);
|
||||
fread (&FmtHdr.Channels, 2, 1, fp);
|
||||
uio_fread (&FmtHdr.Channels, 2, 1, fp);
|
||||
FmtHdr.Channels = UQM_SwapLE16 (FmtHdr.Channels);
|
||||
fread (&FmtHdr.SamplesPerSec, 4, 1, fp);
|
||||
uio_fread (&FmtHdr.SamplesPerSec, 4, 1, fp);
|
||||
FmtHdr.SamplesPerSec = UQM_SwapLE32 (FmtHdr.SamplesPerSec);
|
||||
fread (&FmtHdr.BytesPerSec, 4, 1, fp);
|
||||
uio_fread (&FmtHdr.BytesPerSec, 4, 1, fp);
|
||||
FmtHdr.BytesPerSec = UQM_SwapLE32 (FmtHdr.BytesPerSec);
|
||||
fread (&FmtHdr.BlockAlign, 2, 1, fp);
|
||||
uio_fread (&FmtHdr.BlockAlign, 2, 1, fp);
|
||||
FmtHdr.BlockAlign = UQM_SwapLE16 (FmtHdr.BlockAlign);
|
||||
fread (&FmtHdr.BitsPerSample, 2, 1, fp);
|
||||
uio_fread (&FmtHdr.BitsPerSample, 2, 1, fp);
|
||||
FmtHdr.BitsPerSample = UQM_SwapLE16 (FmtHdr.BitsPerSample);
|
||||
|
||||
if (FmtHdr.Format == 0x0001)
|
||||
@@ -112,12 +112,12 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
|
||||
: decoder_formats.stereo16)
|
||||
);
|
||||
*freq = FmtHdr.SamplesPerSec;
|
||||
fseek (fp, ChunkHdr.Size - 16, SEEK_CUR);
|
||||
uio_fseek (fp, ChunkHdr.Size - 16, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "LoadWAVFile(): unsupported format %x\n", FmtHdr.Format);
|
||||
fclose (fp);
|
||||
uio_fclose (fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -125,18 +125,18 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
|
||||
{
|
||||
*size = ChunkHdr.Size;
|
||||
if ((*data = HMalloc (ChunkHdr.Size + 31)))
|
||||
fread (*data, FmtHdr.BlockAlign, ChunkHdr.Size / FmtHdr.BlockAlign, fp);
|
||||
uio_fread (*data, FmtHdr.BlockAlign, ChunkHdr.Size / FmtHdr.BlockAlign, fp);
|
||||
memset(((char *)*data) + ChunkHdr.Size, 0, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(fp, ChunkHdr.Size, SEEK_CUR);
|
||||
uio_fseek(fp, ChunkHdr.Size, SEEK_CUR);
|
||||
}
|
||||
|
||||
fseek (fp, ChunkHdr.Size & 1, SEEK_CUR);
|
||||
uio_fseek (fp, ChunkHdr.Size & 1, SEEK_CUR);
|
||||
FileHdr.Size -= (((ChunkHdr.Size + 1) & ~1) + 8);
|
||||
}
|
||||
fclose(fp);
|
||||
uio_fclose(fp);
|
||||
}
|
||||
|
||||
if (want_big_endian &&
|
||||
@@ -148,3 +148,4 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
|
||||
if (*size == 0)
|
||||
fprintf (stderr, "LoadWAVFile(): loading %s failed!\n", file);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
#ifndef WAV_H
|
||||
#define WAV_H
|
||||
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
#include "uio.h"
|
||||
|
||||
void LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
|
||||
uint32 *freq, bool want_big_endian);
|
||||
void LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format,
|
||||
void **data, uint32 *size, uint32 *freq, bool want_big_endian);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,20 +17,21 @@
|
||||
*/
|
||||
|
||||
#include "sndintrn.h"
|
||||
#include "options.h"
|
||||
|
||||
extern char *_cur_resfile_name;
|
||||
|
||||
SOUND_REF
|
||||
LoadSoundFile (PVOID pStr)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
// FIXME: this theoretically needs a mechanism to prevent races
|
||||
if (_cur_resfile_name)
|
||||
// something else is loading resources atm
|
||||
return 0;
|
||||
|
||||
fp = res_OpenResFile (pStr, "rb");
|
||||
fp = res_OpenResFile (contentDir, pStr, "rb");
|
||||
if (fp)
|
||||
{
|
||||
MEM_HANDLE hData;
|
||||
@@ -50,14 +51,14 @@ LoadSoundFile (PVOID pStr)
|
||||
MUSIC_REF
|
||||
LoadMusicFile (PVOID pStr)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
// FIXME: this theoretically needs a mechanism to prevent races
|
||||
if (_cur_resfile_name)
|
||||
// something else is loading resources atm
|
||||
return 0;
|
||||
|
||||
fp = res_OpenResFile (pStr, "rb");
|
||||
fp = res_OpenResFile (contentDir, pStr, "rb");
|
||||
if (fp)
|
||||
{
|
||||
MEM_HANDLE hData;
|
||||
|
||||
@@ -107,7 +107,7 @@ SetMusicVolume (COUNT Volume)
|
||||
}
|
||||
|
||||
MEM_HANDLE
|
||||
_GetMusicData (FILE *fp, DWORD length)
|
||||
_GetMusicData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
MEM_HANDLE h;
|
||||
extern char *_cur_resfile_name;
|
||||
@@ -142,7 +142,7 @@ _GetMusicData (FILE *fp, DWORD length)
|
||||
|
||||
strcpy (threedoname, filename);
|
||||
strcpy (&threedoname[strlen (threedoname)-3], "ogg");
|
||||
if (fileExists (threedoname))
|
||||
if (fileExists2 (contentDir, threedoname))
|
||||
{
|
||||
strcpy (filename, threedoname);
|
||||
}
|
||||
@@ -155,7 +155,8 @@ _GetMusicData (FILE *fp, DWORD length)
|
||||
}
|
||||
|
||||
fprintf (stderr, "_GetMusicData(): loading %s\n", filename);
|
||||
if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096, 0, 0)) == 0)
|
||||
if (((*pmus)->decoder = SoundDecoder_Load (contentDir, filename,
|
||||
4096, 0, 0)) == 0)
|
||||
{
|
||||
fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename);
|
||||
|
||||
|
||||
@@ -165,11 +165,8 @@ GetSampleRate (SOUND sound)
|
||||
}
|
||||
|
||||
MEM_HANDLE
|
||||
_GetSoundBankData (FILE *fp, DWORD length)
|
||||
_GetSoundBankData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int omode;
|
||||
#endif
|
||||
int snd_ct, n;
|
||||
DWORD opos;
|
||||
char CurrentLine[1024], filename[1024];
|
||||
@@ -178,7 +175,7 @@ _GetSoundBankData (FILE *fp, DWORD length)
|
||||
STRING_TABLE Snd;
|
||||
|
||||
(void) length; // ignored
|
||||
opos = ftell (fp);
|
||||
opos = uio_ftell (fp);
|
||||
|
||||
{
|
||||
char *s1, *s2;
|
||||
@@ -197,11 +194,9 @@ _GetSoundBankData (FILE *fp, DWORD length)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
omode = _setmode (fileno (fp), O_TEXT);
|
||||
#endif
|
||||
snd_ct = 0;
|
||||
while (fgets (CurrentLine, sizeof (CurrentLine), fp) && snd_ct < MAX_FX)
|
||||
while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) &&
|
||||
snd_ct < MAX_FX)
|
||||
{
|
||||
if (sscanf(CurrentLine, "%s", &filename[n]) == 1)
|
||||
{
|
||||
@@ -211,7 +206,8 @@ _GetSoundBankData (FILE *fp, DWORD length)
|
||||
sndfx[snd_ct]->buffer_tag = 0;
|
||||
sndfx[snd_ct]->read_chain_ptr = NULL;
|
||||
|
||||
sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096, 0, 0);
|
||||
sndfx[snd_ct]->decoder = SoundDecoder_Load (contentDir,
|
||||
filename, 4096, 0, 0);
|
||||
if (!sndfx[snd_ct]->decoder)
|
||||
{
|
||||
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
|
||||
@@ -244,12 +240,9 @@ _GetSoundBankData (FILE *fp, DWORD length)
|
||||
}
|
||||
|
||||
// pkunk insult fix 2002/11/12 (ftell shouldn't be needed for loop to terminate)
|
||||
/*if (ftell (fp) - opos >= length)
|
||||
/*if (uio_ftell (fp) - opos >= length)
|
||||
break;*/
|
||||
}
|
||||
#ifdef WIN32
|
||||
_setmode (fileno (fp), omode);
|
||||
#endif
|
||||
|
||||
Snd = 0;
|
||||
if (snd_ct && (Snd = AllocStringTable (
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
#include "sndlib.h"
|
||||
#include "reslib.h"
|
||||
|
||||
extern MEM_HANDLE _GetMusicData (FILE *fp, DWORD length);
|
||||
extern MEM_HANDLE _GetMusicData (uio_Stream *fp, DWORD length);
|
||||
extern BOOLEAN _ReleaseMusicData (MEM_HANDLE handle);
|
||||
|
||||
extern MEM_HANDLE _GetSoundBankData (FILE *fp, DWORD length);
|
||||
extern MEM_HANDLE _GetSoundBankData (uio_Stream *fp, DWORD length);
|
||||
extern BOOLEAN _ReleaseSoundBankData (MEM_HANDLE handle);
|
||||
|
||||
#define AllocMusicData(s) AllocResourceData((s),MEM_ZEROINIT)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "sound.h"
|
||||
#include "libs/sound/trackplayer.h"
|
||||
#include "comm.h"
|
||||
#include "options.h"
|
||||
|
||||
static int tct; //total number of subtitle tracks
|
||||
static int tcur; //currently playing subtitle track
|
||||
@@ -316,7 +317,8 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
|
||||
fprintf (stderr, "SpliceMultiTrack(): loading...\n");
|
||||
for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++)
|
||||
{
|
||||
track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768, 0, - 3 * TEXT_SPEED);
|
||||
track_decs[tracks] = SoundDecoder_Load (contentDir, *TrackNames,
|
||||
32768, 0, - 3 * TEXT_SPEED);
|
||||
if (track_decs[tracks])
|
||||
{
|
||||
fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n",
|
||||
@@ -471,7 +473,8 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers);
|
||||
sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers);
|
||||
TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
||||
decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[page_counter]);
|
||||
decoder = SoundDecoder_Load (contentDir, TrackName, 4096,
|
||||
startTime, time_stamps[page_counter]);
|
||||
sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0);
|
||||
sound_sample->decoder = decoder;
|
||||
first_chain = last_chain = sound_sample->read_chain_ptr;
|
||||
@@ -481,7 +484,8 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
else
|
||||
{
|
||||
TFB_SoundDecoder *decoder;
|
||||
decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[page_counter]);
|
||||
decoder = SoundDecoder_Load (contentDir, TrackName, 4096,
|
||||
startTime, time_stamps[page_counter]);
|
||||
last_chain->next = create_soundchain (decoder, sound_sample->length);
|
||||
last_chain = last_chain->next;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "strintrn.h"
|
||||
#include "libs/graphics/gfx_common.h"
|
||||
#include "options.h"
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
@@ -39,7 +40,7 @@ dword_convert (PDWORD dword_array, COUNT num_dwords)
|
||||
}
|
||||
|
||||
MEM_HANDLE
|
||||
_GetStringData (FILE *fp, DWORD length)
|
||||
_GetStringData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
MEM_HANDLE hData;
|
||||
|
||||
@@ -51,16 +52,13 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
{
|
||||
#define MAX_STRINGS 2048
|
||||
#define POOL_SIZE 4096
|
||||
#ifdef WIN32
|
||||
int omode;
|
||||
#endif
|
||||
int n, path_len, num_data_sets;
|
||||
DWORD opos,
|
||||
slen[MAX_STRINGS], StringOffs, tot_string_size,
|
||||
clen[MAX_STRINGS], ClipOffs, tot_clip_size,
|
||||
tslen[MAX_STRINGS], TSOffs, tot_ts_size;
|
||||
char CurrentLine[1024], clip_path[1024], *strdata, *clipdata, *ts_data;
|
||||
FILE *timestamp_fp = NULL;
|
||||
uio_Stream *timestamp_fp = NULL;
|
||||
|
||||
if ((strdata = HMalloc (tot_string_size = POOL_SIZE)) == 0)
|
||||
return (0);
|
||||
@@ -97,7 +95,8 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
s += 2;
|
||||
*s++ = 's';
|
||||
*s = '\0';
|
||||
if ((timestamp_fp = fopen (ts_file_name, "rb")))
|
||||
if ((timestamp_fp = uio_fopen (contentDir, ts_file_name,
|
||||
"rb")))
|
||||
{
|
||||
fprintf (stderr, "Found timestamp file: %s\n", ts_file_name);
|
||||
if ((ts_data = HMalloc (tot_ts_size = POOL_SIZE)) == 0)
|
||||
@@ -105,13 +104,10 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
}
|
||||
}
|
||||
|
||||
opos = ftell (fp);
|
||||
#ifdef WIN32
|
||||
omode = _setmode (fileno (fp), O_TEXT);
|
||||
#endif
|
||||
opos = uio_ftell (fp);
|
||||
n = -1;
|
||||
StringOffs = ClipOffs = TSOffs = 0;
|
||||
while (fgets (CurrentLine, sizeof (CurrentLine), fp) && n < MAX_STRINGS - 1)
|
||||
while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) && n < MAX_STRINGS - 1)
|
||||
{
|
||||
int l;
|
||||
|
||||
@@ -139,7 +135,7 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
{
|
||||
char TimeStampLine[1024], *tsptr;
|
||||
BOOLEAN ts_ok = FALSE;
|
||||
fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp);
|
||||
uio_fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp);
|
||||
if (TimeStampLine[0] == '#')
|
||||
{
|
||||
tslen[n] = 0;
|
||||
@@ -171,7 +167,7 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
// timestamp data is invalid, remove all of it
|
||||
fprintf (stderr, "Invalid timestamp data for '%s'. Disabling timestamps\n", s);
|
||||
HFree (ts_data);
|
||||
fclose (timestamp_fp);
|
||||
uio_fclose (timestamp_fp);
|
||||
timestamp_fp = NULL;
|
||||
TSOffs = 0;
|
||||
}
|
||||
@@ -219,12 +215,9 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
strcpy (s, CurrentLine);
|
||||
}
|
||||
|
||||
if ((int)ftell (fp) - (int)opos >= (int)length)
|
||||
if ((int)uio_ftell (fp) - (int)opos >= (int)length)
|
||||
break;
|
||||
}
|
||||
#ifdef WIN32
|
||||
_setmode (fileno (fp), omode);
|
||||
#endif
|
||||
if (n >= 0)
|
||||
{
|
||||
while (slen[n] > 1 && strdata[StringOffs - 2] == '\n')
|
||||
@@ -236,7 +229,7 @@ _GetStringData (FILE *fp, DWORD length)
|
||||
}
|
||||
|
||||
if (timestamp_fp)
|
||||
fclose (timestamp_fp);
|
||||
uio_fclose (timestamp_fp);
|
||||
|
||||
hData = 0;
|
||||
num_data_sets = (ClipOffs ? 1 : 0) + (TSOffs ? 1 : 0) + 1;
|
||||
|
||||
@@ -16,26 +16,28 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "strintrn.h"
|
||||
#include "uio.h"
|
||||
|
||||
extern char *_cur_resfile_name;
|
||||
|
||||
STRING_TABLE
|
||||
LoadStringTableFile (PVOID pStr)
|
||||
LoadStringTableFile (uio_DirHandle *dir, char *fileName)
|
||||
{
|
||||
FILE *fp;
|
||||
uio_Stream *fp;
|
||||
|
||||
// FIXME: this theoretically needs a mechanism to prevent races
|
||||
if (_cur_resfile_name)
|
||||
// something else is loading resources atm
|
||||
return 0;
|
||||
|
||||
fp = res_OpenResFile (pStr, "rb");
|
||||
fp = res_OpenResFile (dir, fileName, "rb");
|
||||
if (fp)
|
||||
{
|
||||
MEM_HANDLE hData;
|
||||
|
||||
_cur_resfile_name = pStr;
|
||||
_cur_resfile_name = fileName;
|
||||
hData = _GetStringData (fp, LengthResFile (fp));
|
||||
_cur_resfile_name = 0;
|
||||
res_CloseResFile (fp);
|
||||
|
||||
@@ -46,7 +46,7 @@ typedef STRING_TABLE_DESC *PSTRING_TABLE_DESC;
|
||||
#define BUILD_STRING(h,i) ((STRING_TABLE)MAKE_DWORD(h,i))
|
||||
#define BUILD_STRING_TABLE(h) (STRING_TABLE)(h)
|
||||
|
||||
extern MEM_HANDLE _GetStringData (FILE *fp, DWORD length);
|
||||
extern MEM_HANDLE _GetStringData (uio_Stream *fp, DWORD length);
|
||||
|
||||
#endif /* _STRINTRN_H */
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#define _STRLIB_H
|
||||
|
||||
#include "compiler.h"
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
typedef DWORD STRING_TABLE;
|
||||
typedef DWORD STRING;
|
||||
@@ -27,7 +29,8 @@ typedef PBYTE STRINGPTR;
|
||||
|
||||
extern BOOLEAN InstallStringTableResType (COUNT string_type);
|
||||
extern STRING_TABLE LoadStringTableInstance (DWORD res);
|
||||
extern STRING_TABLE LoadStringTableFile (PVOID pStr);
|
||||
extern STRING_TABLE LoadStringTableFile (uio_DirHandle *dir,
|
||||
char *fileName);
|
||||
extern BOOLEAN DestroyStringTable (STRING_TABLE StringTable);
|
||||
extern STRING CaptureStringTable (STRING_TABLE StringTable);
|
||||
extern STRING_TABLE ReleaseStringTable (STRING String);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UIO_H
|
||||
#define _UIO_H
|
||||
|
||||
#include "uio/io.h"
|
||||
|
||||
#endif /* _UIO_H */
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
Below the text of the GNU General Public License is quoted verbatim.
|
||||
It applies to all files in and below this directory that say so.
|
||||
Note that most of these files will say only version 2 of the
|
||||
GNU General Public License applies, not any later version.
|
||||
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
uqm_SUBDIRS="stdio"
|
||||
uqm_CFILES="charhashtable.c defaultfs.c fileblock.c fstypes.c
|
||||
gphys.c hashtable.c io.c ioaux.c match.c mount.c
|
||||
mounttree.c paths.c physical.c uiostream.c uioutils.c"
|
||||
|
||||
if [ -n "$uqm_USE_ZIP_IO" ]; then
|
||||
uqm_SUBDIRS="$uqm_SUBDIRS zip"
|
||||
fi
|
||||
|
||||
if [ -n "$DEBUG" -o -n "$uqm_UIO_DEBUG" ]; then
|
||||
uqm_CFILES="$uqm_CFILES debug.c"
|
||||
fi
|
||||
|
||||
if [ -n "$MEMDEBUG" ]; then
|
||||
uqm_CFILES="$uqm_CFILES memdebug.c"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define HASHTABLE_INTERNAL
|
||||
#include "charhashtable.h"
|
||||
#include "types.h"
|
||||
#include "uioport.h"
|
||||
|
||||
static inline uio_uint32 CharHashTable_hash(CharHashTable_HashTable *hashTable,
|
||||
const char *string);
|
||||
static inline uio_bool CharHashTable_equal(CharHashTable_HashTable *hashTable,
|
||||
const char *key1, const char *key2);
|
||||
static inline char *CharHashTable_copy(CharHashTable_HashTable *hashTable,
|
||||
const char *key);
|
||||
static inline void CharHashTable_free(CharHashTable_HashTable *hashTable,
|
||||
char *key);
|
||||
|
||||
#include "hashtable.c"
|
||||
|
||||
|
||||
static inline uio_uint32
|
||||
CharHashTable_hash(CharHashTable_HashTable *hashTable, const char *key) {
|
||||
uio_uint32 hash;
|
||||
|
||||
(void) hashTable;
|
||||
// Rotating hash, variation of something on the web which
|
||||
// wasn't original itself.
|
||||
hash = 0;
|
||||
// Hash was on that web page initialised as the length,
|
||||
// but that isn't known at this time.
|
||||
while (*key != '\0') {
|
||||
hash = (hash << 4) ^ (hash >> 28) ^ *key;
|
||||
key++;
|
||||
}
|
||||
return hash ^ (hash >> 10) ^ (hash >> 20);
|
||||
}
|
||||
|
||||
static inline uio_bool
|
||||
CharHashTable_equal(CharHashTable_HashTable *hashTable,
|
||||
const char *key1, const char *key2) {
|
||||
(void) *hashTable;
|
||||
return strcmp(key1, key2) == 0;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
CharHashTable_copy(CharHashTable_HashTable *hashTable,
|
||||
const char *key) {
|
||||
(void) *hashTable;
|
||||
return uio_strdup(key);
|
||||
}
|
||||
|
||||
static inline void
|
||||
CharHashTable_free(CharHashTable_HashTable *hashTable,
|
||||
char *key) {
|
||||
(void) *hashTable;
|
||||
uio_free(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CHARHASHTABLE_H
|
||||
#define _CHARHASHTABLE_H
|
||||
|
||||
|
||||
#define HASHTABLE_(identifier) CharHashTable ## _ ## identifier
|
||||
typedef char HASHTABLE_(Key);
|
||||
typedef void HASHTABLE_(Value);
|
||||
#define CharHashTable_HASH CharHashTable_hash
|
||||
#define CharHashTable_EQUAL CharHashTable_equal
|
||||
#define CharHashTable_COPY CharHashTable_copy
|
||||
#define CharHashTable_FREE CharHashTable_free
|
||||
|
||||
#include "hashtable.h"
|
||||
|
||||
|
||||
#endif /* _HASHTABLE_H */
|
||||
|
||||
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "uioport.h"
|
||||
#include "io.h"
|
||||
#include "types.h"
|
||||
#include "mem.h"
|
||||
#include "uioutils.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
#define LINEBUFLEN 1024
|
||||
|
||||
typedef struct DebugContext {
|
||||
uio_bool exit;
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
FILE *err;
|
||||
uio_DirHandle *cwd;
|
||||
} DebugContext;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int (*fun)(DebugContext *, int, char *[]);
|
||||
} DebugCommand;
|
||||
|
||||
#ifdef STAND_ALONE
|
||||
void initRepository(void);
|
||||
void unInitRepository(void);
|
||||
#endif
|
||||
|
||||
static int debugCmdCat(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdCd(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdExit(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdLs(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdMem(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdMkDir(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdMount(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdPwd(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdRm(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdRmDir(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdStat(DebugContext *debugContext, int argc, char *argv[]);
|
||||
static int debugCmdWriteTest(DebugContext *debugContext, int argc,
|
||||
char *argv[]);
|
||||
static int debugCmdFwriteTest(DebugContext *debugContext, int argc,
|
||||
char *argv[]);
|
||||
|
||||
static void makeArgs(char *lineBuf, int *argc, char ***argv);
|
||||
static int debugCallCommand(DebugContext *debugContext,
|
||||
int argc, char *argv[]);
|
||||
uio_MountHandle *
|
||||
debugMountOne(uio_Repository *destRep, const char *mountPoint,
|
||||
uio_FileSystemID fsType,
|
||||
uio_DirHandle *sourceDir, const char *sourcePath,
|
||||
const char *inPath, uio_AutoMount **autoMount, int flags,
|
||||
uio_MountHandle *relative);
|
||||
|
||||
// In alphabetic order:
|
||||
DebugCommand debugCommands[] = {
|
||||
{ "cat", debugCmdCat },
|
||||
{ "cd", debugCmdCd },
|
||||
{ "exit", debugCmdExit },
|
||||
{ "fwritetest", debugCmdFwriteTest },
|
||||
{ "ls", debugCmdLs },
|
||||
{ "mem", debugCmdMem },
|
||||
{ "mkdir", debugCmdMkDir },
|
||||
{ "mount", debugCmdMount },
|
||||
{ "pwd", debugCmdPwd },
|
||||
{ "rm", debugCmdRm },
|
||||
{ "rmdir", debugCmdRmDir },
|
||||
{ "stat", debugCmdStat },
|
||||
{ "writetest", debugCmdWriteTest },
|
||||
};
|
||||
|
||||
|
||||
#ifndef STAND_ALONE
|
||||
extern uio_Repository *repository;
|
||||
#else
|
||||
uio_Repository *repository;
|
||||
uio_MountHandle *mountHandles[9]; // TODO: remove (this is just a test)
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
initRepository();
|
||||
uio_debugInteractive(stdin, stdout, stderr);
|
||||
unInitRepository();
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
uio_MountHandle *
|
||||
debugMountOne(uio_Repository *destRep, const char *mountPoint,
|
||||
uio_FileSystemID fsType,
|
||||
uio_DirHandle *sourceDir, const char *sourcePath,
|
||||
const char *inPath, uio_AutoMount **autoMount, int flags,
|
||||
uio_MountHandle *relative) {
|
||||
uio_MountHandle *mountHandle;
|
||||
|
||||
mountHandle = uio_mountDir(destRep, mountPoint, fsType, sourceDir,
|
||||
sourcePath, inPath, autoMount, flags, relative);
|
||||
if (mountHandle == NULL) {
|
||||
int saveErrno = errno;
|
||||
fprintf(stderr, "Could not mount '%s' and graft '%s' from that "
|
||||
"into the repository at '%s': %s\n",
|
||||
sourcePath, inPath, mountPoint, strerror(errno));
|
||||
errno = saveErrno;
|
||||
}
|
||||
return mountHandle;
|
||||
}
|
||||
|
||||
void
|
||||
initRepository(void) {
|
||||
static uio_AutoMount autoMountZip = {
|
||||
.pattern = "*.zip",
|
||||
.matchType = match_MATCH_SUFFIX,
|
||||
.fileSystemID = uio_FSTYPE_ZIP,
|
||||
.mountFlags = uio_MOUNT_BELOW | uio_MOUNT_RDONLY
|
||||
};
|
||||
static uio_AutoMount *autoMount[] = {
|
||||
&autoMountZip,
|
||||
NULL
|
||||
};
|
||||
|
||||
uio_init();
|
||||
repository = uio_openRepository(0);
|
||||
|
||||
memset(&mountHandles, '\0', sizeof mountHandles);
|
||||
#if 1
|
||||
mountHandles[0] = debugMountOne(repository, "/", uio_FSTYPE_STDIO,
|
||||
NULL, NULL, "/home/svdb/cvs/sc2/content", autoMount,
|
||||
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
#endif
|
||||
#if 1
|
||||
mountHandles[1] = debugMountOne(repository, "/", uio_FSTYPE_STDIO,
|
||||
NULL, NULL, "/home/svdb/cvs/sc2/src/sc2code/ships",
|
||||
autoMount, uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
#endif
|
||||
#if 1
|
||||
mountHandles[2] = debugMountOne(repository, "/", uio_FSTYPE_STDIO,
|
||||
NULL, NULL, "/tmp/vfstest", autoMount, uio_MOUNT_TOP, NULL);
|
||||
#endif
|
||||
#if 1
|
||||
mountHandles[3] = debugMountOne(repository, "/", uio_FSTYPE_STDIO,
|
||||
NULL, NULL, "/tmp/vfstest2", autoMount, uio_MOUNT_TOP, NULL);
|
||||
#endif
|
||||
|
||||
// TODO: should work too:
|
||||
#if 0
|
||||
mountHandle[4] = debugMountOne(repository, "/zip/", uio_FSTYPE_ZIP, NULL,
|
||||
NULL, "/ziptest/foo.zip", autoMount, uio_MOUNT_TOP, NULL);
|
||||
#endif
|
||||
{
|
||||
uio_DirHandle *rootDir;
|
||||
rootDir = uio_openDir(repository, "/", 0);
|
||||
if (rootDir == NULL) {
|
||||
fprintf(stderr, "Could not open '/' dir.\n");
|
||||
} else {
|
||||
#if 1
|
||||
mountHandles[4] = debugMountOne(repository, "/example/",
|
||||
uio_FSTYPE_ZIP, rootDir, "/example2.zip", "/", autoMount,
|
||||
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
#endif
|
||||
#if 1
|
||||
mountHandles[5] = debugMountOne(repository, "/example/",
|
||||
uio_FSTYPE_ZIP, rootDir, "/example/example.zip", "/",
|
||||
autoMount, uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
#endif
|
||||
#if 1
|
||||
mountHandles[6] = debugMountOne(repository, "/zip/",
|
||||
uio_FSTYPE_ZIP, rootDir, "/voice.zip", "/", autoMount,
|
||||
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
#endif
|
||||
#if 1
|
||||
mountHandles[7] = debugMountOne(repository, "/foo/",
|
||||
uio_FSTYPE_ZIP, rootDir, "/foo.zip", "/", autoMount,
|
||||
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
#endif
|
||||
uio_closeDir(rootDir);
|
||||
}
|
||||
}
|
||||
mountHandles[8] = debugMountOne(repository, "/root/root/",
|
||||
uio_FSTYPE_STDIO, NULL, NULL, "/", autoMount,
|
||||
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
unInitRepository(void) {
|
||||
#if 1
|
||||
int i;
|
||||
// uio_printMountTree(stderr, repository->mountTree, 0);
|
||||
// fprintf(stderr, "\n");
|
||||
for (i = 7; i >= 0; i--) {
|
||||
if (mountHandles[i] != NULL)
|
||||
uio_unmountDir(mountHandles[i]);
|
||||
// uio_printMountTree(stderr, repository->mountTree, 0);
|
||||
// uio_printMounts(stderr, repository);
|
||||
// fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
uio_closeRepository(repository);
|
||||
uio_unInit();
|
||||
}
|
||||
#endif /* STAND_ALONE */
|
||||
|
||||
void
|
||||
uio_debugInteractive(FILE *in, FILE *out, FILE *err) {
|
||||
char lineBuf[LINEBUFLEN];
|
||||
size_t lineLen;
|
||||
int argc;
|
||||
char **argv;
|
||||
DebugContext debugContext;
|
||||
uio_bool interactive;
|
||||
|
||||
memset(&debugContext, '\0', sizeof (DebugContext));
|
||||
debugContext.exit = false;
|
||||
debugContext.in = in;
|
||||
debugContext.out = out;
|
||||
debugContext.err = err;
|
||||
debugContext.cwd = uio_openDir(repository, "/", 0);
|
||||
if (debugContext.cwd == NULL) {
|
||||
fprintf(err, "Fatal: Could not open working dir.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
interactive = isatty(fileno(in));
|
||||
do {
|
||||
if (interactive)
|
||||
fprintf(out, "> ");
|
||||
if (fgets(lineBuf, LINEBUFLEN, in) == NULL) {
|
||||
if (feof(in)) {
|
||||
// user pressed ^D
|
||||
break;
|
||||
}
|
||||
// error occured
|
||||
clearerr(in);
|
||||
continue;
|
||||
}
|
||||
lineLen = strlen(lineBuf);
|
||||
if (lineBuf[lineLen - 1] != '\n' && lineBuf[lineLen - 1] != '\r') {
|
||||
fprintf(err, "Too long command line.\n");
|
||||
// TODO: read until EOL
|
||||
continue;
|
||||
}
|
||||
makeArgs(lineBuf, &argc, &argv);
|
||||
if (argc == 0) {
|
||||
uio_free(argv);
|
||||
continue;
|
||||
}
|
||||
debugCallCommand(&debugContext, argc, argv);
|
||||
uio_free(argv);
|
||||
} while (!debugContext.exit);
|
||||
if (interactive)
|
||||
fprintf(out, "\n");
|
||||
uio_closeDir(debugContext.cwd);
|
||||
}
|
||||
|
||||
static void
|
||||
makeArgs(char *lineBuf, int *argc, char ***argv) {
|
||||
int numArg;
|
||||
char **args;
|
||||
char *ptr;
|
||||
|
||||
numArg = 0;
|
||||
ptr = lineBuf;
|
||||
while(1) {
|
||||
while (isspace(*ptr))
|
||||
ptr++;
|
||||
if (*ptr == '\0')
|
||||
break;
|
||||
numArg++;
|
||||
while (!isspace(*ptr))
|
||||
ptr++;
|
||||
}
|
||||
|
||||
args = uio_malloc((numArg + 1) * sizeof (char *));
|
||||
numArg = 0;
|
||||
ptr = lineBuf;
|
||||
while(1) {
|
||||
while (isspace(*ptr))
|
||||
ptr++;
|
||||
if (*ptr == '\0')
|
||||
break;
|
||||
args[numArg] = ptr;
|
||||
numArg++;
|
||||
while (!isspace(*ptr))
|
||||
ptr++;
|
||||
if (*ptr == '\0')
|
||||
break;
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
}
|
||||
args[numArg] = NULL;
|
||||
*argv = args;
|
||||
*argc = numArg;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCallCommand(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
int i;
|
||||
int numDebugCommands;
|
||||
|
||||
i = 0;
|
||||
numDebugCommands = sizeof debugCommands / sizeof debugCommands[0];
|
||||
// could be improved with binary search
|
||||
while(1) {
|
||||
if (i == numDebugCommands) {
|
||||
fprintf(debugContext->err, "Invalid command.\n");
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[0], debugCommands[i].name) == 0)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return debugCommands[i].fun(debugContext, argc, argv);
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdCat(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
uio_Handle *handle;
|
||||
#define READBUFSIZE 0x10000
|
||||
char readBuf[READBUFSIZE];
|
||||
char *bufPtr;
|
||||
ssize_t numInBuf, numWritten;
|
||||
size_t totalWritten;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
handle = uio_open(debugContext->cwd, argv[1], O_RDONLY
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, 0);
|
||||
if (handle == NULL) {
|
||||
fprintf(debugContext->err, "Could not open file: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
totalWritten = 0;
|
||||
while (1) {
|
||||
numInBuf = uio_read(handle, readBuf, READBUFSIZE);
|
||||
if (numInBuf == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(debugContext->err, "Could not read from file: %s\n",
|
||||
strerror(errno));
|
||||
uio_close(handle);
|
||||
return 1;
|
||||
}
|
||||
if (numInBuf == 0)
|
||||
break;
|
||||
bufPtr = readBuf;
|
||||
do {
|
||||
numWritten = write(fileno(debugContext->out), bufPtr, numInBuf);
|
||||
if (numWritten == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(debugContext->err, "Could not read from file: %s\n",
|
||||
strerror(errno));
|
||||
uio_close(handle);
|
||||
}
|
||||
numInBuf -= numWritten;
|
||||
bufPtr += numWritten;
|
||||
totalWritten += numWritten;
|
||||
} while (numInBuf > 0);
|
||||
}
|
||||
fprintf(debugContext->out, "[%d bytes]\n", totalWritten);
|
||||
|
||||
uio_close(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdCd(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
uio_DirHandle *newWd;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
newWd = uio_openDirRelative(debugContext->cwd, argv[1], 0);
|
||||
if (newWd == NULL) {
|
||||
fprintf(debugContext->err, "Could not access new dir: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
uio_closeDir(debugContext->cwd);
|
||||
debugContext->cwd = newWd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdExit(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
debugContext->exit = true;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdFwriteTest(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
uio_Stream *stream;
|
||||
const char testString[] = "0123456789\n";
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stream = uio_fopen(debugContext->cwd, argv[1], "w+b");
|
||||
if (stream == NULL) {
|
||||
fprintf(debugContext->err, "Could not open file: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (uio_fwrite(testString, strlen(testString), 1, stream) != 1) {
|
||||
fprintf(debugContext->err, "uio_fwrite() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if (uio_fputs(testString, stream) == EOF) {
|
||||
fprintf(debugContext->err, "uio_fputs() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if (uio_fseek(stream, 15, SEEK_SET) != 0) {
|
||||
fprintf(debugContext->err, "uio_fseek() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if (uio_fputc('A', stream) != 'A') {
|
||||
fprintf(debugContext->err, "uio_fputc() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if (uio_fseek(stream, 0, SEEK_SET) != 0) {
|
||||
fprintf(debugContext->err, "uio_fseek() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
{
|
||||
char buf[6];
|
||||
char *ptr;
|
||||
int i;
|
||||
i = 1;
|
||||
while (1) {
|
||||
ptr = uio_fgets(buf, sizeof buf, stream);
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
fprintf(debugContext->out, "%d: [%s]\n", i, ptr);
|
||||
i++;
|
||||
}
|
||||
if (uio_ferror(stream)) {
|
||||
fprintf(debugContext->err, "uio_fgets() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
uio_clearerr(stream);
|
||||
}
|
||||
if (uio_fseek(stream, 4, SEEK_END) != 0) {
|
||||
fprintf(debugContext->err, "uio_fseek() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
{
|
||||
char buf[2000];
|
||||
memset(buf, 'Q', sizeof buf);
|
||||
if (uio_fwrite(buf, 100, 20, stream) != 20) {
|
||||
fprintf(debugContext->err, "uio_fwrite() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (uio_fseek(stream, 5, SEEK_SET) != 0) {
|
||||
fprintf(debugContext->err, "uio_fseek() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if (uio_fputc('B', stream) != 'B') {
|
||||
fprintf(debugContext->err, "uio_fputc() failed: %s\n",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
uio_fclose(stream);
|
||||
return 0;
|
||||
err:
|
||||
uio_fclose(stream);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
listOneDir(DebugContext *debugContext, const char *arg) {
|
||||
uio_DirList *dirList;
|
||||
int i;
|
||||
const char *pattern;
|
||||
const char *cpath;
|
||||
|
||||
if (arg[0] == '\0') {
|
||||
cpath = arg;
|
||||
pattern = "*";
|
||||
} else {
|
||||
pattern = strrchr(arg, '/');
|
||||
if (pattern == NULL) {
|
||||
cpath = "";
|
||||
pattern = arg;
|
||||
} else if (pattern[1] == '\0') {
|
||||
// argument ends on /
|
||||
cpath = arg;
|
||||
pattern = "*";
|
||||
} else {
|
||||
if (pattern == arg) {
|
||||
cpath = "/";
|
||||
} else {
|
||||
char *path;
|
||||
path = uio_alloca(pattern - arg + 1);
|
||||
memcpy(path, arg, pattern - arg);
|
||||
path[pattern - arg] = '\0';
|
||||
cpath = path;
|
||||
}
|
||||
pattern++;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_GLOB
|
||||
dirList = uio_getDirList(debugContext->cwd, cpath, pattern,
|
||||
match_MATCH_GLOB);
|
||||
#else
|
||||
if (pattern[0] == '*' && pattern[1] == '\0') {
|
||||
dirList = uio_getDirList(debugContext->cwd, cpath, "",
|
||||
match_MATCH_PREFIX);
|
||||
} else {
|
||||
dirList = uio_getDirList(debugContext->cwd, cpath, pattern,
|
||||
match_MATCH_LITTERAL);
|
||||
}
|
||||
#endif
|
||||
if (dirList == NULL) {
|
||||
fprintf(debugContext->out, "Error in uio_getDirList(): %s.\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < dirList->numNames; i++)
|
||||
fprintf(debugContext->out, "%s\n", dirList->names[i]);
|
||||
uio_freeDirList(dirList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdLs(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
int argI;
|
||||
int retVal;
|
||||
|
||||
if (argc == 1)
|
||||
return listOneDir(debugContext, unconst(""));
|
||||
|
||||
for (argI = 1; argI < argc; argI++) {
|
||||
retVal = listOneDir(debugContext, argv[argI]);
|
||||
if (retVal != 0)
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdMem(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_printPointers(debugContext->out);
|
||||
#else
|
||||
fprintf(debugContext->out, "Memory debugging not compiled in.\n");
|
||||
#endif
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdMkDir(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
int retVal;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
retVal = uio_mkdir(debugContext->cwd, argv[1], 0777);
|
||||
if (retVal == -1) {
|
||||
fprintf(debugContext->err, "Could not create directory: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdMount(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
if (argc == 1) {
|
||||
uio_printMounts(debugContext->out, repository);
|
||||
// uio_printMountTree(debugContext->out, repository->mountTree, 0);
|
||||
}
|
||||
(void) argv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdPwd(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
uio_DirHandle_print(debugContext->cwd, debugContext->out);
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdRm(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
int retVal;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
retVal = uio_unlink(debugContext->cwd, argv[1]);
|
||||
if (retVal == -1) {
|
||||
fprintf(debugContext->err, "Could not remove file: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdRmDir(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
int retVal;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
retVal = uio_rmdir(debugContext->cwd, argv[1]);
|
||||
if (retVal == -1) {
|
||||
fprintf(debugContext->err, "Could not remove directory: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdStat(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
struct stat statBuf;
|
||||
uio_Handle *handle;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
handle = uio_open(debugContext->cwd, argv[1], O_RDONLY
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, 0);
|
||||
if (handle == NULL) {
|
||||
fprintf(debugContext->err, "Could not open file: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uio_fstat(handle, &statBuf) == -1) {
|
||||
// errno is set
|
||||
int saveErrno;
|
||||
saveErrno = errno;
|
||||
uio_close(handle);
|
||||
errno = saveErrno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(debugContext->out,
|
||||
"size %ld bytes\n"
|
||||
"uid %d gid %d mode 0%o\n",
|
||||
(unsigned long) statBuf.st_size,
|
||||
(unsigned int) statBuf.st_uid,
|
||||
(unsigned int) statBuf.st_gid,
|
||||
(unsigned int) statBuf.st_mode &
|
||||
(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID));
|
||||
// Can't do these next three in one fprintf, as ctime uses a static buffer
|
||||
// that is overwritten with each call.
|
||||
fprintf(debugContext->out,
|
||||
"last access: %s", ctime(&statBuf.st_atime));
|
||||
fprintf(debugContext->out,
|
||||
"last modification: %s", ctime(&statBuf.st_mtime));
|
||||
fprintf(debugContext->out,
|
||||
"last status change: %s", ctime(&statBuf.st_ctime));
|
||||
|
||||
uio_close(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
debugCmdWriteTest(DebugContext *debugContext, int argc, char *argv[]) {
|
||||
uio_Handle *handle;
|
||||
const char testString[] = "Hello world!\n";
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(debugContext->err, "Invalid number of arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
handle = uio_open(debugContext->cwd, argv[1],
|
||||
O_WRONLY | O_CREAT | O_EXCL
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, 0644);
|
||||
if (handle == NULL) {
|
||||
fprintf(debugContext->err, "Could not open file: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uio_write(handle, testString, sizeof testString) == -1) {
|
||||
fprintf(debugContext->err, "Write failed: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
uio_close(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
void uio_debugInteractive(FILE *in, FILE *out, FILE *err);
|
||||
|
||||
|
||||
#endif /* _DEBUG_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "defaultfs.h"
|
||||
#include "uioport.h"
|
||||
|
||||
extern uio_FileSystemHandler stdio_fileSystemHandler;
|
||||
#ifdef HAVE_ZIP
|
||||
extern uio_FileSystemHandler zip_fileSystemHandler;
|
||||
#endif
|
||||
|
||||
const uio_DefaultFileSystemSetup defaultFileSystems[] = {
|
||||
{ uio_FSTYPE_STDIO, "stdio", &stdio_fileSystemHandler },
|
||||
#ifdef HAVE_ZIP
|
||||
{ uio_FSTYPE_ZIP, "zip", &zip_fileSystemHandler },
|
||||
#endif
|
||||
};
|
||||
|
||||
int
|
||||
uio_numDefaultFileSystems(void) {
|
||||
return sizeof defaultFileSystems / sizeof defaultFileSystems[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef uio_DEFAULTFS_H
|
||||
#define uio_DEFAULTFS_H
|
||||
|
||||
typedef struct uio_DefaultFileSystemSetup uio_DefaultFileSystemSetup;
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "uioport.h"
|
||||
#include "fstypes.h"
|
||||
|
||||
struct uio_DefaultFileSystemSetup {
|
||||
uio_FileSystemID id;
|
||||
const char *name;
|
||||
uio_FileSystemHandler *handler;
|
||||
};
|
||||
|
||||
extern const uio_DefaultFileSystemSetup defaultFileSystems[];
|
||||
|
||||
int uio_numDefaultFileSystems(void);
|
||||
|
||||
#endif /* uio_DEFAULTFS_H */
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
-= Introduction =-
|
||||
|
||||
The file io system I present here provides the user with a virtual file
|
||||
systems on which normal POSIX-like file operations can be performed.
|
||||
|
||||
A virtual file system consists of a number of underlying filesystems merged
|
||||
together in one directory structure.
|
||||
Underlying file systems can be POSIX filesystems, or zip archives, but
|
||||
others can be added easilly.
|
||||
Filesystems are grafted into the virtual filesystem either explicitely, by
|
||||
mounting, or implicitely, by having files of a specific type (for instance
|
||||
those ending on .zip) mounted automatically.
|
||||
When a filesystem is mounted to a directory which already exists in an
|
||||
earlier mounted file system, files in the later mounted file system hide
|
||||
files in an earlier mounted file system. Files present in a filesystem
|
||||
mounted earlier that don't exist in a filesystem mounted later will remain
|
||||
visible.
|
||||
Accessing compressed files inside compressde files is possible, though slow.
|
||||
|
||||
|
||||
-= Nomenclature =-
|
||||
'repository'
|
||||
A collection of files from various sources as a virtual file system.
|
||||
|
||||
'physical directory structure'
|
||||
An underlying filesystem, such as a POSIX filesystem, or a .zip archive.
|
||||
|
||||
'logical directory structure'
|
||||
The merger of one or more Physical directory structures.
|
||||
|
||||
'mounting'
|
||||
Grafting a physical directory structure in a logical directory system.
|
||||
|
||||
When mounting several dirs on top of eachother, I refer to later mounted
|
||||
dirs as 'higher' dirs, and earlier mounted dirs as 'lower' dirs.
|
||||
|
||||
'directory entry'
|
||||
A file or subdirectory within a directory.
|
||||
|
||||
|
||||
-= API =-
|
||||
|
||||
Types:
|
||||
uio_Repository - A struct describing a repository
|
||||
uio_Handle - A handle for working on files
|
||||
uio_DirHandle - A handle for working on directories
|
||||
|
||||
|
||||
TODO: functions
|
||||
|
||||
|
||||
-= Behaviour relating directory structures =-
|
||||
|
||||
The design of the virtual filesystem is guided by the following rules:
|
||||
- Combined directories contain the entries of each directory.
|
||||
If some of the source directories contain an entry with the same name,
|
||||
the combined directory will contain the entry of the topmost directory.
|
||||
(this means a directory can hide a file and the other way around)
|
||||
- Entries hidden in this way are never accessable.
|
||||
- Where possible, actions on directory entries within a combined directory
|
||||
are done as in a normal file system.
|
||||
Because of these, some design decisions have been made:
|
||||
- New entries are created in the topmost writable filesystem. If the path to
|
||||
the directory where the entry is to be created does not exist, it is
|
||||
created [1].
|
||||
- When a file is to be opened for writing, and the file in the combined
|
||||
filesystem exists, but is not writable, and there exists a writable
|
||||
filesystem, mounted higher than the filesystem where the existing file
|
||||
resides, the file is first copied to the topmost writable filesystem.
|
||||
|
||||
[1] I could have decided to use a pre-existing writable directory if one
|
||||
is available.
|
||||
With this choice, when no such pre-existing directory exists,
|
||||
it would make sense to complete the path in the writable filesystem
|
||||
in which the part of the path that does exist is the longest.
|
||||
As you can't create a directory inside a specific filesystem,
|
||||
this would complicate and confuse things for the user.
|
||||
|
||||
|
||||
In specific, for various actions:
|
||||
|
||||
opening a file:
|
||||
- if O_RDONLY:
|
||||
- open the file in the highest dir.
|
||||
- if O_WRONLY or O_RDWR:
|
||||
- if file already exists:
|
||||
- if O_CREAT and O_EXCL: return EEXIST
|
||||
- if file is writable, use that one
|
||||
- if file is not writable, copy it to the highest writable location
|
||||
higher than the location of that file (don't bother if O_TRUNC) and use
|
||||
the new file. If necessary, create the path leading upto it.
|
||||
If no such location exists, return EACCESS.
|
||||
- if file does not exist:
|
||||
- if not O_CREAT: return ENOENT
|
||||
- if the path to the file does not exists, return ENOENT.
|
||||
- find the highest writable dir and open the file there, creating
|
||||
the path leading upto it if necessary.
|
||||
|
||||
removing a file:
|
||||
- try removing the specified file from all physical directory structures
|
||||
for a repository.
|
||||
- once a file is encountered that can't be removed, return an error for
|
||||
that and don't try the rest.
|
||||
|
||||
creating a directory:
|
||||
- as for opening a file with O_WRONLY | O_CREAT | O_EXCL
|
||||
|
||||
removing a directory:
|
||||
- as for removing a file
|
||||
(but a physical directory not being empty is a reason for failure)
|
||||
|
||||
|
||||
-= Limitations =-
|
||||
|
||||
There's no limit to the length of a path in the logical file system.
|
||||
Paths in the underlying physical filesystem can be limited though.
|
||||
|
||||
At the moment, the system is not thread safe. Only one thread should access
|
||||
a repository at once. Seperate threads working on seperate repositories is
|
||||
no problem, as long as the repositories don't overlap.
|
||||
|
||||
|
||||
-= Internals =-
|
||||
|
||||
Types:
|
||||
uio_MountTree - A node in a data structure describing the mounted directories.
|
||||
uio_PRoot - A struct describing the a physical file system.
|
||||
uio_PRootExtra - Filesystem-dependant extra data for a PRoot.
|
||||
uio_GPRoot - Generic filesystem-dependant data for a PRoot, used as
|
||||
uio_PRootExtra.
|
||||
uio_GPRootExtra - Extra filesystem-dependant data for a PRoot, when using
|
||||
uio_GPRoot for generic filesystem-dependant data.
|
||||
uio_GPDir - Generic structure representing a node in a physical directory
|
||||
structure describing one directory.
|
||||
uio_GPFile - Generic structure describing a file in a physical file system.
|
||||
|
||||
|
||||
TODO: functions
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
This file describes the various conventions used in the source.
|
||||
|
||||
|
||||
-= Naming of constructors and destructors =-
|
||||
|
||||
uio_Thing *uio_Thing_new(args)
|
||||
Allocates the structure, and initialises it from the arguments.
|
||||
(was: uio_newThing())
|
||||
void uio_Thing_delete(uio_Thing *thing)
|
||||
Frees the structure and all sub-structures.
|
||||
Decrements references to shared structures.
|
||||
uio_Thing *uio_Thing_alloc()
|
||||
Allocates memory for a new structure.
|
||||
Could be omited for standard allocators.
|
||||
Particularly relevant when a non-standard allocation scheme is
|
||||
used (for instance, allocation from a pool of pre-allocated strucures).
|
||||
(was: uio_allocThing())
|
||||
void uio_Thing_free(Thing *thing)
|
||||
Frees the memory allocated for thing (reverse of uio_Thing_alloc).
|
||||
Could be omited for standard deallocators.
|
||||
void uio_Thing_ref(Thing *thing)
|
||||
Increments the reference counter to the structure.
|
||||
void uio_Thing_unref(Thing *thing)
|
||||
Decrements the reference counter to the structure.
|
||||
Calls uio_Thing_Delete() if the refcounter becomes 0.
|
||||
|
||||
These functions are always declared and defined in this order.
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
|
||||
Om dezelfde dir/file op meerdere plaatsen te kunnen mounten:
|
||||
- dirs/files moeten herkenbaar zijn als al gemount
|
||||
(pDirs moeten gedeeld worden)
|
||||
- LDir moet voor iedere PDir ook een pointer naar de mount opties hebben
|
||||
(aparte structure).
|
||||
Als een file eerst gemount was als read-only, maar daarna ook als
|
||||
read-write, moet die file opnieuw geopend worden. Als een rw file
|
||||
ge-unmount wordt en er alleen nog maar ro mounts zijn, dan mag de file
|
||||
opnieuw geopenend worden.
|
||||
|
||||
|
||||
Iedere entry in een LDir moet bij zich hebben:
|
||||
- een aanduiding van het filesystem type (in de vorm van een PRoot)
|
||||
- data alleen voor belang voor dat type
|
||||
|
||||
|
||||
|
||||
Without LDirs:
|
||||
- DirHandle just has a path to the dir
|
||||
- FileHandle just has a filesystem pointer and a handle local to that
|
||||
fileSystem
|
||||
- To open a file, the MountTree is checked to determine what fs is relevant
|
||||
|
||||
With LDirs:
|
||||
- locating a directory is faster
|
||||
- locating a file within a directory is faster
|
||||
- DirHandle has:
|
||||
- a pointer to an LDir
|
||||
- a pointer to the mount info (Repository would be enough)
|
||||
- LDir points to relevant PDirs
|
||||
- If a PDir is changed, *all* LDirs that refer to it are invalid.
|
||||
Either the PDir would have a time stamp (a sequence # is enough),
|
||||
or the PDir should have a pointer to all relative LDirs and change then
|
||||
when possible. The latter is preferable, as little changes in the PDir
|
||||
only require little changes in the LDir.
|
||||
- when a fs is mounted, the LDirs for the mountpoint (and the dirs in
|
||||
between) should be created.
|
||||
|
||||
|
||||
FileTree type
|
||||
|
||||
|
||||
|
||||
|
||||
Wanneer er een mount-poging gedaan wordt, moet er nagegaan worden of
|
||||
er geen aliasing plaatsvindt. Daarom moeten bij een nieuwe mount alle pRoots
|
||||
die in gebruik zijn nagelopen worden.
|
||||
root1->handle->pRoot == root2->handle->pRoot &&
|
||||
root1->handlers->equalNode(root1->handle->native, root2->handle->native)
|
||||
equalNode zou moeten aangeven of 2 handlers naar dezelfde file wijzen.
|
||||
Dit zou geimplementeerd kunnen worden met fstat of door in de native handle
|
||||
een path bij te houden. fstat heeft de voorkeur, waar dit mogelijk is,
|
||||
aangezien daarmee ook links afgevangen worden (kan niet op Windows).
|
||||
Als het overeenkomt met een eerdere pRoot, moet die gebruikt worden.
|
||||
Als de 2e pRoot als RW wordt gemount, met een RW handle, en de 1e pRoot als
|
||||
een RO handle, dan hebben we een probleem. Het beste zou zijn om de 2e te
|
||||
gebruiken, maar dan moeten alle handles die binnen de 1e pRoot uitgegeven zijn
|
||||
vervangen moeten worden (inclusief seek goedzetten). Alles wat indirect
|
||||
afhangt van die pRoot zou in principe goed moeten gaan.
|
||||
Voorlopig kan het best om een RW remount niet toe te staan.
|
||||
|
||||
Het kan voorkomen dat een pRoot structuur nog bestaat, terwijl er geen mount
|
||||
info meer naar is. Dit is het geval wanneer er nog handlers naar zijn.
|
||||
In dat geval dient die pRoot herbruikt te worden bij opnieuw mounten.
|
||||
Er moet dus een globaal lijstje van pRoots bijgehouden worden.
|
||||
|
||||
|
||||
For absolute paths:
|
||||
Paths should end on / if the location is meant.
|
||||
When the dir entry (either file or dir) is meant, there's no / at the end.
|
||||
Internally, paths don't start with a '/' (unless it's the only character).
|
||||
|
||||
uio_addFile moet iets anders
|
||||
items worden hoe dan ook toegevoegd. Het enige dat een handler kan regelen
|
||||
is dat er automatisch iets nieuws gemount wordt.
|
||||
(of niet? zo worden de .zip files zelf niet hidden (valt op te lossen
|
||||
door behalve type 'file' en 'dir' ook een type 'hide' te maken; mount optie
|
||||
voor toevoegen)
|
||||
Bij het vullen van een PDir moeten niet direct de fileType handlers
|
||||
aangeroepen worden. In plaats daarvan moeten ze worden aangeroepen bij
|
||||
1) het opvragen van een directory lijst
|
||||
2) een poging een specifieke directory in te gaan.
|
||||
|
||||
|
||||
|
||||
When deleting a PDir, it should be verified that the dir was not mounted.
|
||||
Same for PFiles.
|
||||
|
||||
|
||||
add uio_fdopen
|
||||
extern uio_Handle uio_stdin, uio_stdout, uio_stderr;
|
||||
create those on uio_init();
|
||||
Make function that associates a stdio file descriptor with an uio_Handle.
|
||||
Can be used for uio_stdin, uio_stdout, and uio_stderr;
|
||||
Make function 'uio_forwardData()' that reads from one stream and outputs to the
|
||||
other. Useful for copying stuff.
|
||||
|
||||
TODO: dirs that only exist as a mount point aren't shown in dir listings
|
||||
|
||||
|
||||
-= mmap() =-
|
||||
Simulate mmap(). For stdio fs it can be a real mmap(). For others, it
|
||||
could be a temporary file which is mmapped (deleted immediately on POSIX
|
||||
systems where you can have a handle to an unlinked file.
|
||||
If possible, it could be demand-paged. (reserving a page somehow and catching
|
||||
sigsegv?)
|
||||
For operating systems that don't have mmap(), a copy into memory could work.
|
||||
MS Windows has it's own variant which should be usable
|
||||
(see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/file_mapping.asp)
|
||||
|
||||
|
||||
|
||||
-= automounting =-
|
||||
Put pointer to automount structure in automount structure, so that you can
|
||||
set the automount structure you want to use for automounted file systems.
|
||||
Add 'options' argument to uio_MountDir, and 'options' field to AutoMount.
|
||||
This should be a structure with file-system dependant options.
|
||||
|
||||
Say /yabba/dabba/doo is mounted under /zut/, with automounting of .zip files.
|
||||
What if /yabba/ contains dabba.zip file which contains dabba/doo/bla?
|
||||
Is it to be used?
|
||||
No. Automount options count for the mountPoint, not for the physical
|
||||
structure that is mounted.
|
||||
|
||||
|
||||
|
||||
|
||||
Add options for case-insensitivity?
|
||||
|
||||
|
||||
|
||||
It would be beneficial for speed to open a new handle for a filesystem when a
|
||||
file inside the filesystem is opened. It shouldn't normally be a real problem,
|
||||
but for instance when you are reading two files inside a zip file, there will
|
||||
be a lot of seeking in that .zip file, which is a problem if that .zip file
|
||||
is itself in a .zip file, and it is not completely loaded in memory.
|
||||
|
||||
|
||||
Locking of files.
|
||||
Wouldn't even need filesystem-dependant code, though it would be nice for
|
||||
stdio and perhaps some remote file systems to lock low-level too.
|
||||
|
||||
|
||||
stat on directories?
|
||||
|
||||
|
||||
|
||||
It might be useful to have an uio_walkPath variant inside the
|
||||
FileSystemHandler struct, for speed.
|
||||
|
||||
|
||||
Move PRoot->handle to PRoot->native->handle?
|
||||
|
||||
|
||||
PDirHandles and PFileHandles don't add to the reference count of a PRoot.
|
||||
Currently this is no problem as the handles are short-lived (during
|
||||
which time the PRoot will be referenced anyhow).
|
||||
It should either be changed, or documented.
|
||||
|
||||
|
||||
For systems that use the GPDir strucure, PDirHandle has a GPDir directly
|
||||
in its 'extra' field. This leaves no room for filesystem-dependant data.
|
||||
It's the question whether that's ever necessary. Probably not.
|
||||
A way to solve it would be to have a structure with as fields the PDir and an
|
||||
extra field.
|
||||
(same for PFileHandle)
|
||||
|
||||
Naming not consistent: 'unref' vs 'unInit'.
|
||||
|
||||
Do we need a seperate mountRef and handlesRef for pRoot?
|
||||
|
||||
Maybe accept NULL as io_DirHandle for a lot of functions which use a relative
|
||||
path.
|
||||
uio_OpenDirRelative can then be uio_OpenDir.
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
Needed before use in UQM:
|
||||
- documentation
|
||||
- configuring for HAVE_REGEX and GLOB
|
||||
|
||||
Documentation:
|
||||
- use doxygen
|
||||
- Warning: getting (part of) the contents of a directory is fairly slow,
|
||||
as dirs need to be merged.
|
||||
- It would be (theoretically) possible to add HTTP and FTP support for
|
||||
remote file systems.
|
||||
- on adding extra file system types:
|
||||
- open, mkdir, rmdir, and unlink should themselves make sure that
|
||||
the physical structure is kept up to date when an entry is
|
||||
removed or added.
|
||||
- stream stuff is not thread safe
|
||||
writing using stream functions is not implemented.
|
||||
- uio_fflush() does not accept NULL as argument to flush all streams,
|
||||
like stdio fflush() does.
|
||||
- uio_close() does never fail
|
||||
- The physical open function should call uio_Handle_new and store its own
|
||||
data in it.
|
||||
The physical close function should delete its own data. It's called
|
||||
Will cleanup the general Handle.
|
||||
Analogous for mount/unmount with PRoot
|
||||
- (internal) arguments for uio_Bla_new are always copied as-is.
|
||||
If they are ref-counted, the counter should be incremented by the caller,
|
||||
if the caller does not need the reference itself.
|
||||
The uio_Bla_delete function decrements the ref counter of the ref-counted
|
||||
fields.
|
||||
- No need to store MountHandles. They will be automatically freed
|
||||
when the repository is closed.
|
||||
|
||||
Bugs:
|
||||
- uio_Stream file might get unaligned (not sure).
|
||||
- 'openDir(repository, "dir/")' will have the trailing '/'
|
||||
in the dirHandle, which will cause problems.
|
||||
|
||||
Extra features (not necessary for UQM):
|
||||
- Make functions to use for uio_malloc, uio_free and uio_realloc
|
||||
configurable at init.
|
||||
- add uio_mmap()
|
||||
- add match_MATCH_ALL and match_MATCH_NONE
|
||||
- automounting
|
||||
- Unmount automounted filesystems when the originating filesystem
|
||||
is unmounted.
|
||||
- when doing stat() on a directory, merge the stat info of the underlying
|
||||
physical dirs.
|
||||
- read directory information from zip files.
|
||||
- implement ungetc()
|
||||
- make fileblocks public
|
||||
- setmode() for windows?
|
||||
- prevent aliasing of files/dirs, both between two physical file
|
||||
systems (where possible), as within the same filesystem (in particular
|
||||
stdio). On Windows, aliasing can occur easilly when a file or dir
|
||||
is accessed with the long vs the short ("PROGRA~1") name, or when
|
||||
capitalisation is involved.
|
||||
- accept non-dir, non-regular-file dir entries in stdio.
|
||||
|
||||
Optimisations (not necessary for UQM):
|
||||
- use mmap for fileBlocks
|
||||
- Use a pre-allocated pool of hash table entries for allocHashEntry.
|
||||
- optimise certain strings (specifically directory entries) by making
|
||||
a string type which has pointers to a shared char array.
|
||||
Invariant: if two strings are the same, they point to the same
|
||||
character array. Consequence: string comparison is pointer comparison.
|
||||
Making a new string would imply checking the existing strings.
|
||||
Existing strings should be in a hash table.
|
||||
- optimise paths
|
||||
Encode all paths internally as (double-linked) chains of path components
|
||||
This way, operations like going up one path component, are cheap.
|
||||
Each path component could either be represented by a pointer to a string,
|
||||
(possibly shared as above), or as a pair of begin and end pointers
|
||||
(or begin pointer and length). In the latter case, there's no need for
|
||||
copying strings when parsing a user-supplied string, but sharing of strings
|
||||
would not be possible.
|
||||
It's probably possible to use both methods next to eachother;
|
||||
shared strings for stored paths, and pointers into a path for user-supplied
|
||||
strings (which would be freed when the call returns).
|
||||
Instead of a linked list, perhaps an array can be used, as paths rarely
|
||||
change. It would be a problem if for some reason, recursively path
|
||||
components are added to a path.
|
||||
- (maybe) keep track of already issued handles, so that the ref counter
|
||||
could just be incremented, instead of issuing a new one.
|
||||
(uio_getPDirEntryHandle)
|
||||
- Make it possible for people to add their own file system, without giving
|
||||
away the internals. (no wanton including of .h files)
|
||||
- Don't cache stdio dir structure
|
||||
(and don't read the dir leading up to the dir that is actually needed)
|
||||
- mounting foo to /Foo and foo/bar to /Foo/Bar should result in only one
|
||||
physical structure. Preferably, it shouldn't even lead to two mountInfo
|
||||
structures for /Foo/Bar, so that merging the dirs is not unnecessarilly
|
||||
expensive.
|
||||
- add uio_access()
|
||||
(uqm fileExists can be redone then)
|
||||
- implement the physical function cleanup() to clean up the physical
|
||||
structure. Int argument that specifies how thoroughly.
|
||||
On it depends whether cache is cleaned, whether stuff is realloc'ed
|
||||
to defragment memory, etc.
|
||||
|
||||
Cleanups (not necessary for UQM):
|
||||
- rename function names to be more like class names for as far as that's
|
||||
not already done.
|
||||
uio_PRoot_unref etc
|
||||
- Add uio_fatal(), uio_error(), uio_warning()
|
||||
- Clean up the include structure
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "fileblock.h"
|
||||
#include "uioport.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static uio_FileBlock *uio_newFileBlock(uio_Handle *handle, int flags,
|
||||
off_t offset, size_t blockSize, char *buffer, size_t bufSize);
|
||||
static inline uio_FileBlock *uio_allocFileBlock(void);
|
||||
static void uio_freeFileBlock(uio_FileBlock *block);
|
||||
|
||||
|
||||
uio_FileBlock *
|
||||
uio_openFileBlock(uio_Handle *handle) {
|
||||
// TODO: if mmap support is available, and it is available natively
|
||||
// for the filesystem (make some sort of sysctl for filesystems
|
||||
// to check this?), use mmap.
|
||||
// mmap the entire file if it's small enough.
|
||||
// N.B. Keep in mind streams of which the size is not known in
|
||||
// advance.
|
||||
struct stat statBuf;
|
||||
if (uio_fstat(handle, &statBuf) == -1) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
uio_Handle_ref(handle);
|
||||
return uio_newFileBlock(handle, 0, 0, statBuf.st_size, NULL, 0);
|
||||
}
|
||||
|
||||
uio_FileBlock *
|
||||
uio_openFileBlock2(uio_Handle *handle, off_t offset, size_t size) {
|
||||
// TODO: mmap (see uio_openFileBlock)
|
||||
|
||||
// TODO: check if offset and size are acceptable.
|
||||
// Need to handle streams of which the size is unknown.
|
||||
#if 0
|
||||
if (uio_stat(handle, &statBuf) == -1) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
if (statBuf.st_size >
|
||||
#endif
|
||||
uio_Handle_ref(handle);
|
||||
return uio_newFileBlock(handle, 0, offset, size, NULL, 0);
|
||||
}
|
||||
|
||||
// block remains usable until the next call to uio_accessFileBlock
|
||||
// with the same block as argument, or until uio_closeFileBlock with
|
||||
// that block as argument.
|
||||
ssize_t
|
||||
uio_accessFileBlock(uio_FileBlock *block, off_t offset, size_t length,
|
||||
char **buffer) {
|
||||
if (block->flags & uio_FB_USE_MMAP) {
|
||||
// TODO
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
} else {
|
||||
// TODO: add read-ahead buffering
|
||||
ssize_t numRead;
|
||||
|
||||
if (length > block->blockSize - offset)
|
||||
length = block->blockSize - offset;
|
||||
|
||||
if (block->buffer != NULL && length != block->bufSize) {
|
||||
uio_free(block->buffer);
|
||||
block->buffer = NULL;
|
||||
}
|
||||
if (block->buffer == NULL)
|
||||
block->buffer = uio_malloc(length);
|
||||
|
||||
// TODO: lock handle
|
||||
if (uio_lseek(block->handle, block->offset + offset, SEEK_SET) ==
|
||||
(off_t) -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
numRead = uio_read(block->handle, block->buffer, length);
|
||||
if (numRead == -1) {
|
||||
// errno is set
|
||||
// TODO: unlock handle
|
||||
return -1;
|
||||
}
|
||||
// TODO: unlock handle
|
||||
*buffer = block->buffer;
|
||||
return numRead;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
uio_copyFileBlock(uio_FileBlock *block, off_t offset, char *buffer,
|
||||
size_t length) {
|
||||
if (block->flags & uio_FB_USE_MMAP) {
|
||||
// TODO
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
} else {
|
||||
ssize_t numRead;
|
||||
|
||||
if (length > block->blockSize - offset)
|
||||
length = block->blockSize - offset;
|
||||
|
||||
// TODO: lock handle
|
||||
if (uio_lseek(block->handle, block->offset + offset, SEEK_SET) ==
|
||||
(off_t) -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
numRead = uio_read(block->handle, buffer, length);
|
||||
if (numRead == -1) {
|
||||
// errno is set
|
||||
// TODO: unlock handle
|
||||
return -1;
|
||||
}
|
||||
// TODO: unlock handle
|
||||
return numRead;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
uio_closeFileBlock(uio_FileBlock *block) {
|
||||
if (block->flags & uio_FB_USE_MMAP) {
|
||||
#if 0
|
||||
if (block->buffer != NULL)
|
||||
uio_mmunmap(block->buffer);
|
||||
#endif
|
||||
} else {
|
||||
if (block->buffer != NULL)
|
||||
uio_free(block->buffer);
|
||||
}
|
||||
uio_Handle_unref(block->handle);
|
||||
uio_freeFileBlock(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// caller should uio_refHandle(handle) (unless it doesn't need it's own
|
||||
// reference anymore).
|
||||
static uio_FileBlock *
|
||||
uio_newFileBlock(uio_Handle *handle, int flags, off_t offset,
|
||||
size_t blockSize, char *buffer, size_t bufSize) {
|
||||
uio_FileBlock *result;
|
||||
|
||||
result = uio_allocFileBlock();
|
||||
result->handle = handle;
|
||||
result->flags = flags;
|
||||
result->offset = offset;
|
||||
result->blockSize = blockSize;
|
||||
result->buffer = buffer;
|
||||
result->bufSize = bufSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uio_FileBlock *
|
||||
uio_allocFileBlock(void) {
|
||||
return uio_malloc(sizeof (uio_FileBlock));
|
||||
}
|
||||
|
||||
static void
|
||||
uio_freeFileBlock(uio_FileBlock *block) {
|
||||
uio_free(block);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FILEBLOCK_H
|
||||
#define _FILEBLOCK_H
|
||||
|
||||
#include "io.h"
|
||||
#include "uioport.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct uio_FileBlock {
|
||||
uio_Handle *handle;
|
||||
int flags;
|
||||
#define uio_FB_USE_MMAP 1
|
||||
off_t offset;
|
||||
// Offset to the start of the block in the file.
|
||||
size_t blockSize;
|
||||
char *buffer;
|
||||
// either allocated buffer, or buffer to mmap'ed area.
|
||||
size_t bufSize;
|
||||
} uio_FileBlock;
|
||||
|
||||
uio_FileBlock *uio_openFileBlock(uio_Handle *handle);
|
||||
uio_FileBlock *uio_openFileBlock2(uio_Handle *handle, off_t offset,
|
||||
size_t size);
|
||||
ssize_t uio_accessFileBlock(uio_FileBlock *block, off_t offset, size_t length,
|
||||
char **buffer);
|
||||
int uio_copyFileBlock(uio_FileBlock *block, off_t offset, char *buffer,
|
||||
size_t length);
|
||||
int uio_closeFileBlock(uio_FileBlock *block);
|
||||
|
||||
#endif /* _FILEBLOCK_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "uioport.h"
|
||||
#include "fstypes.h"
|
||||
#include "mem.h"
|
||||
#include "defaultfs.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
|
||||
static uio_bool uio_validFileSystemHandler(uio_FileSystemHandler *handler);
|
||||
static uio_FileSystemInfo *uio_newFileSystemInfo(uio_FileSystemID id,
|
||||
uio_FileSystemHandler *handler, char *name);
|
||||
static uio_FileSystemInfo **uio_getFileSystemInfoPtr(uio_FileSystemID id);
|
||||
|
||||
static inline uio_FileSystemInfo *uio_allocFileSystemInfo(void);
|
||||
|
||||
static inline void uio_freeFileSystemInfo(uio_FileSystemInfo *fileSystemInfo);
|
||||
|
||||
|
||||
uio_FileSystemInfo *uio_fileSystems = NULL;
|
||||
// list sorted by id
|
||||
|
||||
|
||||
|
||||
void
|
||||
uio_registerDefaultFileSystems(void) {
|
||||
int i;
|
||||
int num;
|
||||
uio_FileSystemID registerResult;
|
||||
|
||||
num = uio_numDefaultFileSystems();
|
||||
for (i = 0; i < num; i++) {
|
||||
registerResult = uio_registerFileSystem(
|
||||
defaultFileSystems[i].id,
|
||||
defaultFileSystems[i].name,
|
||||
defaultFileSystems[i].handler);
|
||||
switch (registerResult) {
|
||||
case 0:
|
||||
fprintf(stderr, "Warning: Default file system '%s' is "
|
||||
"already registered.\n",
|
||||
defaultFileSystems[i].name);
|
||||
break;
|
||||
case -1:
|
||||
fprintf(stderr, "Error: Could not register '%s' file \n"
|
||||
"system: %s\n", defaultFileSystems[i].name,
|
||||
strerror(errno));
|
||||
break;
|
||||
default:
|
||||
assert(registerResult == defaultFileSystems[i].id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_unRegisterDefaultFileSystems(void) {
|
||||
int i;
|
||||
int num;
|
||||
|
||||
num = uio_numDefaultFileSystems();
|
||||
for (i = 0; i < num; i++) {
|
||||
if (uio_unRegisterFileSystem(defaultFileSystems[i].id) == -1) {
|
||||
fprintf(stderr, "Could not unregister '%s' file system: %s\n",
|
||||
defaultFileSystems[i].name, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if wantedID = 0, just pick one
|
||||
// if wantedID != 0, 0 will be returned if that id wasn't available
|
||||
// a copy of 'name' is made
|
||||
uio_FileSystemID
|
||||
uio_registerFileSystem(uio_FileSystemID wantedID, const char *name,
|
||||
uio_FileSystemHandler *handler) {
|
||||
uio_FileSystemInfo **ptr;
|
||||
|
||||
if (!uio_validFileSystemHandler(handler)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (wantedID == 0) {
|
||||
// Search for the first free id >= uio_FIRST_CUSTOM_ID
|
||||
// it is put in wantedID
|
||||
|
||||
for (ptr = &uio_fileSystems; *ptr != NULL; ptr = &(*ptr)->next)
|
||||
if ((*ptr)->id >= uio_FS_FIRST_CUSTOM_ID)
|
||||
break;
|
||||
|
||||
wantedID = uio_FS_FIRST_CUSTOM_ID;
|
||||
while (*ptr != NULL) {
|
||||
if ((*ptr)->id != wantedID) {
|
||||
// wantedID is not in use
|
||||
break;
|
||||
}
|
||||
wantedID++;
|
||||
ptr = &(*ptr)->next;
|
||||
}
|
||||
// wantedID contains the new ID
|
||||
} else {
|
||||
// search for the place in the list where to insert the wanted
|
||||
// id, keeping the list sorted
|
||||
for (ptr = &uio_fileSystems; *ptr != NULL; ptr = &(*ptr)->next) {
|
||||
if ((*ptr)->id <= wantedID) {
|
||||
if ((*ptr)->id == wantedID)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// ptr points to the place where the new link can inserted
|
||||
|
||||
if (handler->init != NULL && handler->init() == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
uio_FileSystemInfo *newInfo;
|
||||
|
||||
newInfo = uio_newFileSystemInfo(wantedID, handler, uio_strdup(name));
|
||||
newInfo->next = *ptr;
|
||||
*ptr = newInfo;
|
||||
return wantedID;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
uio_unRegisterFileSystem(uio_FileSystemID id) {
|
||||
uio_FileSystemInfo **ptr;
|
||||
uio_FileSystemInfo *temp;
|
||||
|
||||
ptr = uio_getFileSystemInfoPtr(id);
|
||||
if (ptr == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ((*ptr)->ref > 1) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*ptr)->handler->unInit != NULL &&
|
||||
((*ptr)->handler->unInit() == -1)) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
temp = *ptr;
|
||||
*ptr = (*ptr)->next;
|
||||
|
||||
// uio_unrefFileSystemHandler(temp->handler);
|
||||
uio_free(temp->name);
|
||||
uio_freeFileSystemInfo(temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uio_bool
|
||||
uio_validFileSystemHandler(uio_FileSystemHandler *handler) {
|
||||
// Check for the essentials
|
||||
if (handler->mount == NULL ||
|
||||
handler->umount == NULL ||
|
||||
handler->open == NULL ||
|
||||
handler->close == NULL ||
|
||||
handler->read == NULL ||
|
||||
handler->openEntries == NULL ||
|
||||
handler->readEntries == NULL ||
|
||||
handler->closeEntries == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Invalid file system handler.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uio_FileSystemHandler *
|
||||
uio_getFileSystemHandler(uio_FileSystemID id) {
|
||||
uio_FileSystemInfo *ptr;
|
||||
|
||||
for (ptr = uio_fileSystems; ptr != NULL; ptr = ptr->next) {
|
||||
if (ptr->id == id)
|
||||
return ptr->handler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uio_FileSystemInfo *
|
||||
uio_getFileSystemInfo(uio_FileSystemID id) {
|
||||
uio_FileSystemInfo *ptr;
|
||||
|
||||
for (ptr = uio_fileSystems; ptr != NULL; ptr = ptr->next) {
|
||||
if (ptr->id == id)
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uio_FileSystemInfo **
|
||||
uio_getFileSystemInfoPtr(uio_FileSystemID id) {
|
||||
uio_FileSystemInfo **ptr;
|
||||
|
||||
for (ptr = &uio_fileSystems; *ptr != NULL; ptr = &(*ptr)->next) {
|
||||
if ((*ptr)->id == id)
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// sets ref to 1
|
||||
static uio_FileSystemInfo *
|
||||
uio_newFileSystemInfo(uio_FileSystemID id, uio_FileSystemHandler *handler,
|
||||
char *name) {
|
||||
uio_FileSystemInfo *result;
|
||||
|
||||
result = uio_allocFileSystemInfo();
|
||||
result->id = id;
|
||||
result->handler = handler;
|
||||
result->name = name;
|
||||
result->ref = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
// *** Allocators ***
|
||||
|
||||
static inline uio_FileSystemInfo *
|
||||
uio_allocFileSystemInfo(void) {
|
||||
uio_FileSystemInfo *result = uio_malloc(sizeof (uio_FileSystemInfo));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_FileSystemInfo, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *** Deallocators ***
|
||||
|
||||
static inline void
|
||||
uio_freeFileSystemInfo(uio_FileSystemInfo *fileSystemInfo) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_FileSystemInfo, (void *) fileSystemInfo);
|
||||
#endif
|
||||
uio_free(fileSystemInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FSTYPES_H
|
||||
#define _FSTYPES_H
|
||||
|
||||
typedef int uio_FileSystemID;
|
||||
#define uio_FSTYPE_STDIO 1
|
||||
#define uio_FSTYPE_ZIP 2
|
||||
|
||||
|
||||
#ifdef uio_INTERNAL
|
||||
|
||||
#define uio_FS_FIRST_CUSTOM_ID 0x10
|
||||
|
||||
#ifndef uio_INTERNAL_PHYSICAL
|
||||
typedef void *uio_NativeHandle;
|
||||
#endif
|
||||
|
||||
// 'forward' declarations
|
||||
typedef struct uio_FileSystemHandler uio_FileSystemHandler;
|
||||
typedef struct uio_FileSystemInfo uio_FileSystemInfo;
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "physical.h"
|
||||
#include "uioport.h"
|
||||
|
||||
|
||||
/* Structure describing how to access files _in_ a directory of a certain
|
||||
* type (not files _of_ a certain type.) Except for mount().
|
||||
* in open(), the first arg points to the dir where the file should be
|
||||
* in, and the second arg is the name of that file (no path)
|
||||
*/
|
||||
struct uio_FileSystemHandler {
|
||||
int (*init) (void);
|
||||
int (*unInit) (void);
|
||||
void (*cleanup) (uio_PRoot *, int);
|
||||
// Called to cleanup memory. The second argument specifies
|
||||
// how thoroughly.
|
||||
|
||||
struct uio_PRoot * (*mount) (uio_Handle *, int);
|
||||
int (*umount) (uio_PRoot *);
|
||||
|
||||
void (*close) (uio_Handle *);
|
||||
// called when the last reference is closed, not
|
||||
// necessarilly each time when uio_close() is called
|
||||
int (*fstat) (uio_Handle *, struct stat *);
|
||||
int (*stat) (uio_PDirHandle *, const char *,
|
||||
struct stat *);
|
||||
uio_PDirHandle * (*mkdir) (uio_PDirHandle *, const char *, mode_t);
|
||||
uio_Handle * (*open) (uio_PDirHandle *, const char *, int,
|
||||
mode_t);
|
||||
ssize_t (*read) (uio_Handle *, void *, size_t);
|
||||
int (*rmdir) (uio_PDirHandle *, const char *);
|
||||
off_t (*seek) (uio_Handle *, off_t, int);
|
||||
ssize_t (*write) (uio_Handle *, const void *, size_t);
|
||||
int (*unlink) (uio_PDirHandle *, const char *);
|
||||
|
||||
uio_NativeEntriesContext (*openEntries) (uio_PDirHandle *);
|
||||
int (*readEntries) (uio_NativeEntriesContext *, char *,
|
||||
size_t);
|
||||
void (*closeEntries) (uio_NativeEntriesContext);
|
||||
|
||||
uio_PDirEntryHandle * (*getPDirEntryHandle) (
|
||||
const uio_PDirHandle *, const char *);
|
||||
void (*deletePRootExtra) (uio_PRootExtra pRootExtra);
|
||||
void (*deletePDirHandleExtra) (
|
||||
uio_PDirHandleExtra pDirHandleExtra);
|
||||
void (*deletePFileHandleExtra) (
|
||||
uio_PFileHandleExtra pFileHandleExtra);
|
||||
};
|
||||
|
||||
struct uio_FileSystemInfo {
|
||||
int ref;
|
||||
uio_FileSystemID id;
|
||||
char *name; // name of the file system
|
||||
uio_FileSystemHandler *handler;
|
||||
struct uio_FileSystemInfo *next;
|
||||
};
|
||||
|
||||
void uio_registerDefaultFileSystems(void);
|
||||
void uio_unRegisterDefaultFileSystems(void);
|
||||
uio_FileSystemID uio_registerFileSystem(uio_FileSystemID wantedID,
|
||||
const char *name, uio_FileSystemHandler *handler);
|
||||
int uio_unRegisterFileSystem(uio_FileSystemID id);
|
||||
uio_FileSystemHandler *uio_getFileSystemHandler(uio_FileSystemID id);
|
||||
uio_FileSystemInfo *uio_getFileSystemInfo(uio_FileSystemID id);
|
||||
|
||||
#endif /* uio_INTERNAL */
|
||||
|
||||
#endif /* _FSTYPES_H */
|
||||
|
||||
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#define uio_INTERNAL_PHYSICAL
|
||||
#define uio_INTERNAL_GPHYS
|
||||
typedef void *uio_NativeHandle;
|
||||
typedef void *uio_GPRootExtra;
|
||||
typedef void *uio_GPDirExtra;
|
||||
typedef void *uio_GPFileExtra;
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gphys.h"
|
||||
#include "paths.h"
|
||||
#include "uioport.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
static void uio_GPDir_deepPersistentUnref(uio_GPDir *gPDir);
|
||||
static uio_GPRoot *uio_GPRoot_alloc(void);
|
||||
|
||||
static void uio_GPRoot_free(uio_GPRoot *gPRoot);
|
||||
|
||||
static inline uio_GPDir *uio_GPDir_alloc(void);
|
||||
void uio_GPDir_delete(uio_GPDir *gPDir);
|
||||
static inline void uio_GPDir_free(uio_GPDir *gPDir);
|
||||
|
||||
static inline uio_GPFile *uio_GPFile_alloc(void);
|
||||
void uio_GPFile_delete(uio_GPFile *gPFile);
|
||||
static inline void uio_GPFile_free(uio_GPFile *gPFile);
|
||||
|
||||
// Call this when you need to edit a file 'dirName' in the GPDir 'gPDir'.
|
||||
// a new entry is created when necessary.
|
||||
// uio_gPDirCommitSubDir should be called when you're done with it.
|
||||
//
|
||||
// a copy of dirName is made if needed; the caller remains responsible for
|
||||
// freeing the original
|
||||
// Allocates a new dir if necessary.
|
||||
uio_GPDir *
|
||||
uio_GPDir_prepareSubDir(uio_GPDir *gPDir, const char *dirName) {
|
||||
uio_GPDir *subDir;
|
||||
uio_GPDirEntry *entry;
|
||||
|
||||
entry = uio_GPDirEntries_find(gPDir->entries, dirName);
|
||||
if (entry != NULL) {
|
||||
if (uio_GPDirEntry_isDir(entry)) {
|
||||
// Return existing subdir.
|
||||
uio_GPDir_ref((uio_GPDir *) entry);
|
||||
return (uio_GPDir *) entry;
|
||||
} else {
|
||||
// There already exists a file with the same name.
|
||||
// This should not happen within one file system.
|
||||
fprintf(stderr, "Directory %s shadows file with the same name "
|
||||
"from the same filesystem.\n", dirName);
|
||||
}
|
||||
}
|
||||
|
||||
// return new subdir
|
||||
subDir = uio_GPDir_new(gPDir->pRoot, NULL, uio_GPDir_DETACHED);
|
||||
// subDir->ref is initialised at 1
|
||||
return subDir;
|
||||
}
|
||||
|
||||
// call this when you're done with a dir acquired by a call to
|
||||
// uio_gPDirPrepareSubDir
|
||||
void
|
||||
uio_GPDir_commitSubDir(uio_GPDir *gPDir, const char *dirName,
|
||||
uio_GPDir *subDir) {
|
||||
if (subDir->flags & uio_GPDir_DETACHED) {
|
||||
// New dir.
|
||||
// reference to the subDir is passed along to the upDir,
|
||||
// so subDir->ref should not be changed.
|
||||
uio_GPDirEntries_add(gPDir->entries, dirName, subDir);
|
||||
subDir->flags &= ~uio_GPDir_DETACHED;
|
||||
if (!(subDir->flags & uio_GPDir_PERSISTENT)) {
|
||||
// Persistent dirs have an extra reference.
|
||||
uio_GPDir_unref(subDir);
|
||||
}
|
||||
} else {
|
||||
uio_GPDir_unref(subDir);
|
||||
}
|
||||
}
|
||||
|
||||
// a copy of fileName is made if needed; the caller remains responsible for
|
||||
// freeing the original
|
||||
void
|
||||
uio_GPDir_addFile(uio_GPDir *gPDir, const char *fileName, uio_GPFile *file) {
|
||||
// A file will never already exist in a dir. There can only be
|
||||
// one entry in a physical dir with the same name.
|
||||
uio_GPDirEntries_add(gPDir->entries, fileName, (uio_GPDirEntry *) file);
|
||||
}
|
||||
|
||||
// Pre: 'fileName' exists in 'gPDir' and is a dir.
|
||||
void
|
||||
uio_GPDir_removeFile(uio_GPDir *gPDir, const char *fileName) {
|
||||
uio_GPDirEntry *entry;
|
||||
uio_GPFile *file;
|
||||
uio_bool retVal;
|
||||
|
||||
entry = uio_GPDirEntries_find(gPDir->entries, fileName);
|
||||
if (entry == NULL) {
|
||||
// This means the file has no associated GPFile.
|
||||
// This can happen when the GPFile structure is only used for caching.
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!uio_GPDirEntry_isDir(entry));
|
||||
file = (uio_GPFile *) entry;
|
||||
uio_GPFile_unref(file);
|
||||
retVal = uio_GPDirEntries_remove(gPDir->entries, fileName);
|
||||
assert(retVal);
|
||||
}
|
||||
|
||||
// Pre: 'dirName' exists in 'gPDir' and is a dir.
|
||||
void
|
||||
uio_GPDir_removeSubDir(uio_GPDir *gPDir, const char *dirName) {
|
||||
uio_GPDirEntry *entry;
|
||||
uio_GPDir *subDir;
|
||||
uio_bool retVal;
|
||||
|
||||
entry = uio_GPDirEntries_find(gPDir->entries, dirName);
|
||||
if (entry == NULL) {
|
||||
// This means the directory has no associated GPDir.
|
||||
// This can happen when the GPDir structure is only used for caching.
|
||||
return;
|
||||
}
|
||||
|
||||
assert(uio_GPDirEntry_isDir(entry));
|
||||
subDir = (uio_GPDir *) entry;
|
||||
if (subDir->flags & uio_GPDir_PERSISTENT) {
|
||||
// Persistent dirs have an extra reference.
|
||||
uio_GPDir_unref(subDir);
|
||||
}
|
||||
retVal = uio_GPDirEntries_remove(gPDir->entries, dirName);
|
||||
assert(retVal);
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPDir_setComplete(uio_GPDir *gPDir, uio_bool flag) {
|
||||
if (flag) {
|
||||
gPDir->flags |= uio_GPDir_COMPLETE;
|
||||
} else
|
||||
gPDir->flags &= ~uio_GPDir_COMPLETE;
|
||||
}
|
||||
|
||||
int
|
||||
uio_GPDir_entryCount(const uio_GPDir *gPDir) {
|
||||
return uio_GPDirEntries_count(gPDir->entries);
|
||||
}
|
||||
|
||||
static void
|
||||
uio_GPDir_access(uio_GPDir *gPDir) {
|
||||
if (!(gPDir->flags & uio_GPDir_COMPLETE))
|
||||
uio_GPDir_fill(gPDir);
|
||||
}
|
||||
|
||||
// The ref counter for the dir entry is not incremented.
|
||||
uio_GPDirEntry *
|
||||
uio_GPDir_getGPDirEntry(uio_GPDir *gPDir, const char *name) {
|
||||
uio_GPDir_access(gPDir);
|
||||
return uio_GPDirEntries_find(gPDir->entries, name);
|
||||
}
|
||||
|
||||
// The ref counter for the dir entry is not incremented.
|
||||
uio_PDirEntryHandle *
|
||||
uio_GPDir_getPDirEntryHandle(const uio_PDirHandle *pDirHandle,
|
||||
const char *name) {
|
||||
uio_GPDirEntry *gPDirEntry;
|
||||
|
||||
gPDirEntry = uio_GPDir_getGPDirEntry(pDirHandle->extra, name);
|
||||
if (gPDirEntry == NULL)
|
||||
return NULL;
|
||||
uio_GPDirEntry_ref(gPDirEntry);
|
||||
if (uio_GPDirEntry_isDir(gPDirEntry)) {
|
||||
return (uio_PDirEntryHandle *) uio_PDirHandle_new(pDirHandle->pRoot,
|
||||
(uio_GPDir *) gPDirEntry);
|
||||
} else {
|
||||
return (uio_PDirEntryHandle *) uio_PFileHandle_new(pDirHandle->pRoot,
|
||||
(uio_GPFile *) gPDirEntry);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Follow a path starting from a specified physical dir as long as possible.
|
||||
* When you can get no further, 'endGPDir' will be filled in with the dir
|
||||
* where you ended up, and 'pathRest' will point into the original path. to
|
||||
* the beginning of the part that was not matched.
|
||||
* It is allowed to have endGPDir point to gPDir and/or restPath
|
||||
* point to path when calling this function.i
|
||||
* returns: 0 if the complete path was matched
|
||||
* ENOENT if some component (the next one) didn't exists
|
||||
* ENODIR if a component (the next one) exists but isn't a dir
|
||||
* See also uio_walkPhysicalPath. The difference is that this one works
|
||||
* directly on the GPDirs and is faster because of that.
|
||||
*/
|
||||
int
|
||||
uio_walkGPPath(uio_GPDir *startGPDir, const char *path,
|
||||
size_t pathLen, uio_GPDir **endGPDir, const char **pathRest) {
|
||||
const char *pathEnd;
|
||||
const char *partStart, *partEnd;
|
||||
char *tempBuf;
|
||||
uio_GPDir *gPDir;
|
||||
uio_GPDirEntry *entry;
|
||||
int retVal;
|
||||
|
||||
gPDir = startGPDir;
|
||||
tempBuf = uio_alloca(strlen(path) + 1);
|
||||
pathEnd = path + pathLen;
|
||||
getFirstPathComponent(path, pathEnd, &partStart, &partEnd);
|
||||
while (1) {
|
||||
if (partStart == pathEnd) {
|
||||
retVal = 0;
|
||||
break;
|
||||
}
|
||||
memcpy(tempBuf, partStart, partEnd - partStart);
|
||||
tempBuf[partEnd - partStart] = '\0';
|
||||
|
||||
entry = uio_GPDir_getGPDirEntry(gPDir, tempBuf);
|
||||
if (entry == NULL) {
|
||||
retVal = ENOENT;
|
||||
break;
|
||||
}
|
||||
if (!uio_GPDirEntry_isDir(entry)) {
|
||||
retVal = ENOTDIR;
|
||||
break;
|
||||
}
|
||||
gPDir = (uio_GPDir *) entry;
|
||||
getNextPathComponent(pathEnd, &partStart, &partEnd);
|
||||
}
|
||||
|
||||
*pathRest = partStart;
|
||||
*endGPDir = gPDir;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uio_GPDirEntries_Iterator *
|
||||
uio_GPDir_openEntries(uio_PDirHandle *pDirHandle) {
|
||||
uio_GPDir_access(pDirHandle->extra);
|
||||
return uio_GPDirEntries_getIterator(pDirHandle->extra->entries);
|
||||
}
|
||||
|
||||
// the start of 'buf' will be filled with pointers to strings
|
||||
// those strings are stored elsewhere in buf.
|
||||
// The function returns the number of strings passed along, or -1 for error.
|
||||
// If there are no more entries, the last pointer will be NULL.
|
||||
// (this pointer counts towards the return value)
|
||||
int
|
||||
uio_GPDir_readEntries(uio_GPDirEntries_Iterator **iterator,
|
||||
char *buf, size_t len) {
|
||||
char *end;
|
||||
char **start;
|
||||
int num;
|
||||
const char *name;
|
||||
size_t nameLen;
|
||||
|
||||
// buf will be filled like this:
|
||||
// The start of buf will contain pointers to char *,
|
||||
// the end will contain the actual char[] that those pointers point to.
|
||||
// The start and the end will grow towards eachother.
|
||||
start = (char **) buf;
|
||||
end = buf + len;
|
||||
num = 0;
|
||||
while (!uio_GPDirEntries_iteratorDone(*iterator)) {
|
||||
name = uio_GPDirEntries_iteratorName(*iterator);
|
||||
nameLen = strlen(name) + 1;
|
||||
|
||||
// Does this work with systems that need memory access to be
|
||||
// aligned on a certain number of bytes?
|
||||
if ((size_t) (sizeof (char *) + nameLen) >
|
||||
(size_t) (end - (char *) start)) {
|
||||
// Not enough room to fit the pointer (at the beginning) and
|
||||
// the string (at the end).
|
||||
return num;
|
||||
}
|
||||
end -= nameLen;
|
||||
memcpy(end, name, nameLen);
|
||||
*start = end;
|
||||
start++;
|
||||
num++;
|
||||
*iterator = uio_GPDirEntries_iteratorNext(*iterator);
|
||||
}
|
||||
if (sizeof (char *) > (size_t) (end - (char *) start)) {
|
||||
// not enough room to fit the NULL pointer.
|
||||
// It will have to be reported seperately the next time.
|
||||
return num;
|
||||
}
|
||||
*start = NULL;
|
||||
num++;
|
||||
return num;
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPDir_closeEntries(uio_GPDirEntries_Iterator *iterator) {
|
||||
uio_GPDirEntries_freeIterator(iterator);
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPDir_fill(uio_GPDir *gPDir) {
|
||||
if ((gPDir->flags & uio_GPDir_COMPLETE) &&
|
||||
!(gPDir->flags & uio_GPDir_NOCACHE))
|
||||
return;
|
||||
assert(gPDir->pRoot->extra->ops->fillGPDir != NULL);
|
||||
gPDir->pRoot->extra->ops->fillGPDir(gPDir);
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPRoot_deleteGPRootExtra(uio_GPRoot *gPRoot) {
|
||||
if (gPRoot->extra == NULL)
|
||||
return;
|
||||
assert(gPRoot->ops->deleteGPRootExtra != NULL);
|
||||
gPRoot->ops->deleteGPRootExtra(gPRoot->extra);
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPDir_deleteGPDirExtra(uio_GPDir *gPDir) {
|
||||
if (gPDir->extra == NULL)
|
||||
return;
|
||||
assert(gPDir->pRoot->extra->ops->deleteGPDirExtra != NULL);
|
||||
gPDir->pRoot->extra->ops->deleteGPDirExtra(gPDir->extra);
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPFile_deleteGPFileExtra(uio_GPFile *gPFile) {
|
||||
if (gPFile->extra == NULL)
|
||||
return;
|
||||
assert(gPFile->pRoot->extra->ops->deleteGPFileExtra != NULL);
|
||||
gPFile->pRoot->extra->ops->deleteGPFileExtra(gPFile->extra);
|
||||
}
|
||||
|
||||
int
|
||||
uio_gPDirFlagsFromPRootFlags(int flags) {
|
||||
int newFlags;
|
||||
|
||||
newFlags = 0;
|
||||
if (flags & uio_PRoot_NOCACHE)
|
||||
newFlags |= uio_GPDir_NOCACHE;
|
||||
|
||||
return newFlags;
|
||||
}
|
||||
|
||||
int
|
||||
uio_gPFileFlagsFromPRootFlags(int flags) {
|
||||
int newFlags;
|
||||
|
||||
newFlags = 0;
|
||||
if (flags & uio_PRoot_NOCACHE)
|
||||
newFlags |= uio_GPFile_NOCACHE;
|
||||
|
||||
return newFlags;
|
||||
}
|
||||
|
||||
// This function is to be called from the physical layer.
|
||||
// uio_GPDirHandle is the extra information for an uio_PDirHandle.
|
||||
// This is in practice a pointer to the uio_GPDir.
|
||||
void
|
||||
uio_GPDirHandle_delete(uio_GPDirHandle *gPDirHandle) {
|
||||
uio_GPDir_unref((uio_GPDir *) gPDirHandle);
|
||||
(void) gPDirHandle;
|
||||
}
|
||||
|
||||
// This function is to be called from the physical layer.
|
||||
// uio_GPFileHandle is the extra information for an uio_PFileHandle.
|
||||
// This is in practice a pointer to the uio_GPFile.
|
||||
void
|
||||
uio_GPFileHandle_delete(uio_GPFileHandle *gPFileHandle) {
|
||||
uio_GPFile_unref((uio_GPFile *) gPFileHandle);
|
||||
(void) gPFileHandle;
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPDirEntry_delete(uio_GPDirEntry *gPDirEntry) {
|
||||
if (uio_GPDirEntry_isDir(gPDirEntry)) {
|
||||
uio_GPDir_delete((uio_GPDir *) gPDirEntry);
|
||||
} else {
|
||||
uio_GPFile_delete((uio_GPFile *) gPDirEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// note: sets ref count to 1
|
||||
uio_GPDir *
|
||||
uio_GPDir_new(uio_PRoot *pRoot, uio_GPDirExtra extra, int flags) {
|
||||
uio_GPDir *gPDir;
|
||||
|
||||
gPDir = uio_GPDir_alloc();
|
||||
gPDir->ref = 1;
|
||||
gPDir->pRoot = pRoot;
|
||||
gPDir->entries = uio_GPDirEntries_new();
|
||||
gPDir->extra = extra;
|
||||
flags |= uio_gPDirFlagsFromPRootFlags(gPDir->pRoot->flags);
|
||||
if (pRoot->extra->flags & uio_GPRoot_PERSISTENT)
|
||||
flags |= uio_GPDir_PERSISTENT;
|
||||
gPDir->flags = flags | uio_GPDirEntry_TYPE_DIR;
|
||||
return gPDir;
|
||||
}
|
||||
|
||||
// pre: There are no more references to within the gPDir, and
|
||||
// gPDir is the last reference to the gPDir itself.
|
||||
void
|
||||
uio_GPDir_delete(uio_GPDir *gPDir) {
|
||||
#if 0
|
||||
uio_GPDirEntry *entry;
|
||||
|
||||
uio_GPDirEntries_Iterator *iterator;
|
||||
|
||||
iterator = uio_GPDirEntries_getIterator(gPDir->entries);
|
||||
while (!uio_GPDirEntries_iteratorDone(iterator)) {
|
||||
entry = uio_GPDirEntries_iteratorItem(iterator);
|
||||
assert(entry->ref == 0);
|
||||
if (uio_GPDirEntry_isDir(entry)) {
|
||||
uio_GPDir_delete((uio_GPDir *) entry);
|
||||
} else {
|
||||
uio_GPFile_delete((uio_GPFile *) entry);
|
||||
}
|
||||
iterator = uio_GPDirEntries_iteratorNext(iterator);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(gPDir->ref == 0);
|
||||
uio_GPDirEntries_deleteHashTable(gPDir->entries);
|
||||
uio_GPDir_deleteGPDirExtra(gPDir);
|
||||
uio_GPDir_free(gPDir);
|
||||
}
|
||||
|
||||
static void
|
||||
uio_GPDir_deepPersistentUnref(uio_GPDir *gPDir) {
|
||||
uio_GPDirEntry *entry;
|
||||
uio_GPDirEntries_Iterator *iterator;
|
||||
|
||||
iterator = uio_GPDirEntries_getIterator(gPDir->entries);
|
||||
while (!uio_GPDirEntries_iteratorDone(iterator)) {
|
||||
entry = uio_GPDirEntries_iteratorItem(iterator);
|
||||
if (uio_GPDirEntry_isDir(entry)) {
|
||||
uio_GPDir_deepPersistentUnref((uio_GPDir *) entry);
|
||||
} else {
|
||||
uio_GPFile_unref((uio_GPFile *) entry);
|
||||
}
|
||||
iterator = uio_GPDirEntries_iteratorNext(iterator);
|
||||
}
|
||||
uio_GPDirEntries_freeIterator(iterator);
|
||||
if (gPDir->flags & uio_GPDir_PERSISTENT) {
|
||||
uio_GPDir_unref(gPDir);
|
||||
} else {
|
||||
gPDir->flags &= ~uio_GPDir_COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uio_GPDir *
|
||||
uio_GPDir_alloc(void) {
|
||||
uio_GPDir *result = uio_malloc(sizeof (uio_GPDir));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_GPDir, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPDir_free(uio_GPDir *gPDir) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_GPDir, (void *) gPDir);
|
||||
#endif
|
||||
uio_free(gPDir);
|
||||
}
|
||||
|
||||
// note: sets ref count to 1
|
||||
uio_GPFile *
|
||||
uio_GPFile_new(uio_PRoot *pRoot, uio_GPFileExtra extra, int flags) {
|
||||
uio_GPFile *gPFile;
|
||||
|
||||
gPFile = uio_GPFile_alloc();
|
||||
gPFile->ref = 1;
|
||||
gPFile->pRoot = pRoot;
|
||||
gPFile->extra = extra;
|
||||
gPFile->flags = flags;
|
||||
return gPFile;
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPFile_delete(uio_GPFile *gPFile) {
|
||||
assert(gPFile->ref == 0);
|
||||
uio_GPFile_deleteGPFileExtra(gPFile);
|
||||
uio_GPFile_free(gPFile);
|
||||
}
|
||||
|
||||
static inline uio_GPFile *
|
||||
uio_GPFile_alloc(void) {
|
||||
uio_GPFile *result = uio_malloc(sizeof (uio_GPFile));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_GPFile, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPFile_free(uio_GPFile *gPFile) {
|
||||
uio_free(gPFile);
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_GPFile, (void *) gPFile);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The ref counter to 'handle' is not incremented.
|
||||
uio_PRoot *
|
||||
uio_GPRoot_makePRoot(uio_FileSystemHandler *handler, int pRootFlags,
|
||||
uio_GPRoot_Operations *ops, uio_GPRootExtra gPRootExtra, int gPRootFlags,
|
||||
uio_Handle *handle, uio_GPDirExtra gPDirExtra, int gPDirFlags) {
|
||||
uio_PRoot *result;
|
||||
uio_GPDir *gPTopDir;
|
||||
uio_GPRoot *gPRoot;
|
||||
|
||||
gPRoot = uio_GPRoot_new(ops, gPRootExtra, gPRootFlags);
|
||||
result = uio_PRoot_new(NULL, handler, handle, gPRoot, pRootFlags);
|
||||
|
||||
gPTopDir = uio_GPDir_new(result, gPDirExtra, gPDirFlags);
|
||||
if (gPRoot->flags & uio_GPRoot_PERSISTENT)
|
||||
uio_GPDir_ref(gPTopDir);
|
||||
result->rootDir = uio_GPDir_makePDirHandle(gPTopDir);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pre: there are no more references to PRoot or anything inside it.
|
||||
int
|
||||
uio_GPRoot_umount(uio_PRoot *pRoot) {
|
||||
uio_PDirHandle *topDirHandle;
|
||||
uio_GPDir *topDir;
|
||||
|
||||
topDirHandle = uio_PRoot_getRootDirHandle(pRoot);
|
||||
topDir = topDirHandle->extra;
|
||||
if (pRoot->extra->flags & uio_GPRoot_PERSISTENT)
|
||||
uio_GPDir_deepPersistentUnref(topDir);
|
||||
uio_PDirHandle_unref(topDirHandle);
|
||||
(void) pRoot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uio_GPRoot *
|
||||
uio_GPRoot_new(uio_GPRoot_Operations *ops, uio_GPRootExtra extra, int flags) {
|
||||
uio_GPRoot *result;
|
||||
|
||||
result = uio_GPRoot_alloc();
|
||||
result->ops = ops;
|
||||
result->extra = extra;
|
||||
result->flags = flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPRoot_delete(uio_GPRoot *gPRoot) {
|
||||
uio_GPRoot_deleteGPRootExtra(gPRoot);
|
||||
uio_GPRoot_free(gPRoot);
|
||||
}
|
||||
|
||||
static uio_GPRoot *
|
||||
uio_GPRoot_alloc(void) {
|
||||
uio_GPRoot *result = uio_malloc(sizeof (uio_GPRoot));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_GPRoot, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
uio_GPRoot_free(uio_GPRoot *gPRoot) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_GPRoot, (void *) gPRoot);
|
||||
#endif
|
||||
uio_free(gPRoot);
|
||||
}
|
||||
|
||||
// The ref counter to the gPDir is not inremented.
|
||||
uio_PDirHandle *
|
||||
uio_GPDir_makePDirHandle(uio_GPDir *gPDir) {
|
||||
return uio_PDirHandle_new(gPDir->pRoot, gPDir);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
uio_GPDirEntry_print(FILE *outStream, uio_GPDirEntry *gPDirEntry) {
|
||||
if (uio_GPDirEntry_isDir(gPDirEntry)) {
|
||||
uio_GPDir_print(outStream, (uio_GPDir *) gPDirEntry);
|
||||
} else {
|
||||
uio_GPFile_print(outStream, (uio_GPFile *) gPDirEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPDir_print(FILE *outStream, uio_GPDir *gPDir) {
|
||||
(void) outStream;
|
||||
(void) gPDir;
|
||||
}
|
||||
|
||||
void
|
||||
uio_GPFile_print(FILE *outStream, uio_GPFile *gPFile) {
|
||||
(void) outStream;
|
||||
(void) gPFile;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GPHYS_H
|
||||
#define _GPHYS_H
|
||||
|
||||
#include "uioport.h"
|
||||
|
||||
#ifndef uio_INTERNAL_PHYSICAL
|
||||
typedef void *uio_GPRootExtra;
|
||||
typedef void *uio_GPDirExtra;
|
||||
typedef void *uio_GPFileExtra;
|
||||
#endif
|
||||
|
||||
typedef struct CharHashTable_HashTable uio_GPDirEntries;
|
||||
|
||||
#define uio_GPDirEntries_new() \
|
||||
((uio_GPDirEntries *) CharHashTable_newHashTable(NULL, NULL, NULL, \
|
||||
NULL, 0, 0.85, 0.9))
|
||||
#define uio_GPDirEntries_add(hashTable, name, item) \
|
||||
CharHashTable_add((CharHashTable_HashTable *) hashTable, name, \
|
||||
(void *) item)
|
||||
#define uio_GPDirEntries_remove(hashTable, name) \
|
||||
CharHashTable_remove((CharHashTable_HashTable *) hashTable, name)
|
||||
#define uio_GPDirEntries_count(hashTable) \
|
||||
CharHashTable_count((CharHashTable_HashTable *) hashTable)
|
||||
#define uio_GPDirEntries_find(hashTable, name) \
|
||||
((uio_GPDirEntry *) CharHashTable_find( \
|
||||
(CharHashTable_HashTable *) hashTable, name))
|
||||
#define uio_GPDirEntries_deleteHashTable(hashTable) \
|
||||
CharHashTable_deleteHashTable((CharHashTable_HashTable *) hashTable)
|
||||
//#define uio_GPDirEntries_clear(hashTable)
|
||||
// CharHashTable_clear((CharHashTable_HashTable *) hashTable)
|
||||
#define uio_GPDirEntries_getIterator(hashTable) \
|
||||
((uio_GPDirEntries_Iterator *) CharHashTable_getIterator( \
|
||||
(const CharHashTable_HashTable *) hashTable))
|
||||
#define uio_GPDirEntries_iteratorDone(iterator) \
|
||||
CharHashTable_iteratorDone((const CharHashTable_Iterator *) iterator)
|
||||
#define uio_GPDirEntries_iteratorName(iterator) \
|
||||
CharHashTable_iteratorKey((CharHashTable_Iterator *) iterator)
|
||||
#define uio_GPDirEntries_iteratorItem(iterator) \
|
||||
((uio_GPDirEntry *) CharHashTable_iteratorValue( \
|
||||
(CharHashTable_Iterator *) iterator))
|
||||
#define uio_GPDirEntries_iteratorNext(iterator) \
|
||||
((uio_GPDirEntries_Iterator *) CharHashTable_iteratorNext( \
|
||||
(CharHashTable_Iterator *) iterator))
|
||||
#define uio_GPDirEntries_freeIterator(iterator) \
|
||||
CharHashTable_freeIterator(iterator)
|
||||
|
||||
// 'forward' declarations
|
||||
typedef struct uio_GPDirEntry uio_GPDirEntry;
|
||||
typedef struct uio_GPDir uio_GPDir;
|
||||
typedef struct uio_GPFile uio_GPFile;
|
||||
typedef struct uio_GPRoot_Operations uio_GPRoot_Operations;
|
||||
typedef struct uio_GPRoot uio_GPRoot;
|
||||
|
||||
#include "charhashtable.h"
|
||||
typedef CharHashTable_Iterator uio_GPDirEntries_Iterator;
|
||||
|
||||
#ifdef uio_INTERNAL_GPHYS
|
||||
typedef uio_GPDirEntries_Iterator *uio_NativeEntriesContext;
|
||||
#endif
|
||||
typedef struct uio_GPRoot *uio_PRootExtra;
|
||||
typedef struct uio_GPDir uio_GPDirHandle;
|
||||
typedef uio_GPDirHandle *uio_PDirHandleExtra;
|
||||
typedef struct uio_GPFile uio_GPFileHandle;
|
||||
typedef uio_GPFileHandle *uio_PFileHandleExtra;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include "iointrn.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
struct uio_GPRoot_Operations {
|
||||
void (*fillGPDir)(uio_GPDir *);
|
||||
void (*deleteGPRootExtra)(uio_GPRootExtra);
|
||||
void (*deleteGPDirExtra)(uio_GPDirExtra);
|
||||
void (*deleteGPFileExtra)(uio_GPFileExtra);
|
||||
};
|
||||
|
||||
struct uio_GPRoot {
|
||||
int flags;
|
||||
#define uio_GPRoot_PERSISTENT 0x4000
|
||||
/* Set if directories in this file system should not be deleted
|
||||
* as long as the file system is mounted. If this flag is not
|
||||
* set, the GPDir structure is only a cache.
|
||||
*/
|
||||
uio_GPRoot_Operations *ops;
|
||||
uio_GPRootExtra extra;
|
||||
};
|
||||
|
||||
#define uio_GPDirEntry_COMMON \
|
||||
int flags; \
|
||||
int ref; \
|
||||
/* Number of times this structure is referenced from the \
|
||||
* outside (so not counting the references from subdirs \
|
||||
* or files when the entry is a directory) \
|
||||
*/
|
||||
|
||||
#define uio_GPDirEntry_NOCACHE uio_PRoot_NOCACHE
|
||||
|
||||
/*
|
||||
* uio_GPDirEntry
|
||||
* super-'class' of uio_GPDir and uio_GPFile
|
||||
*/
|
||||
struct uio_GPDirEntry {
|
||||
uio_GPDirEntry_COMMON
|
||||
void *extra;
|
||||
};
|
||||
|
||||
#define uio_GPDirEntry_TYPE_REG 0x0000
|
||||
#define uio_GPDirEntry_TYPE_DIR 0x0001
|
||||
#define uio_GPDirEntry_TYPEMASK 0x0001
|
||||
|
||||
/*
|
||||
* uio_GPDir
|
||||
* Represents a directory in a physical directory structure.
|
||||
* sub-'class' of uio_GPDirEntry
|
||||
*/
|
||||
struct uio_GPDir {
|
||||
uio_GPDirEntry_COMMON
|
||||
# define uio_GPDir_NOCACHE uio_GPDirEntry_NOCACHE
|
||||
/* This directory info will not be cached.
|
||||
* PDIR_COMPLETE is irrelevant in this case */
|
||||
# define uio_GPDir_COMPLETE 0x1000
|
||||
/* Set if fillDir should not be called if an entry does not
|
||||
* exist in a directory. Usually set if the entire dir has been
|
||||
* completely read in.
|
||||
*/
|
||||
# define uio_GPDir_DETACHED 0x2000
|
||||
/* Set if this dir is not linked to from elsewhere in the physical
|
||||
* structure */
|
||||
# define uio_GPDir_PERSISTENT 0x4000
|
||||
/* Set if this dir should not be deleted as long as the file
|
||||
* system is mounted. If this flag is not set, the GPDir
|
||||
* structure is only a cache.
|
||||
*/
|
||||
uio_GPDirExtra extra;
|
||||
/* extra internal data for some filesystem types */
|
||||
uio_PRoot *pRoot;
|
||||
uio_GPDirEntries *entries;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* uio_GPFile
|
||||
* Represents a file in a physical directory structure.
|
||||
* sub-'class' of uio_GPDirEntry
|
||||
*/
|
||||
struct uio_GPFile {
|
||||
uio_GPDirEntry_COMMON
|
||||
# define uio_GPFile_NOCACHE uio_GPDirEntry_NOCACHE
|
||||
/* Info on this file will not be cached. */
|
||||
uio_PRoot *pRoot;
|
||||
uio_GPFileExtra extra;
|
||||
/* extra internal data for some filesystem types */
|
||||
};
|
||||
|
||||
|
||||
static inline uio_bool
|
||||
uio_GPDirEntry_isReg(uio_GPDirEntry *gPDirEntry) {
|
||||
return (gPDirEntry->flags & uio_GPDirEntry_TYPEMASK) ==
|
||||
uio_GPDirEntry_TYPE_REG;
|
||||
}
|
||||
|
||||
static inline uio_bool
|
||||
uio_GPDirEntry_isDir(uio_GPDirEntry *gPDirEntry) {
|
||||
return (gPDirEntry->flags & uio_GPDirEntry_TYPEMASK) ==
|
||||
uio_GPDirEntry_TYPE_DIR;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void uio_GPDirEntry_print(FILE *outStream, uio_GPDirEntry *gPDirEntry);
|
||||
void uio_GPDir_print(FILE *outStream, uio_GPDir *gPDir);
|
||||
void uio_GPFile_print(FILE *outStream, uio_GPFile *pFile);
|
||||
#endif
|
||||
|
||||
uio_NativeEntriesContext uio_GPDir_openEntries(uio_PDirHandle *pDirHandle);
|
||||
int uio_GPDir_readEntries(uio_NativeEntriesContext *iterator,
|
||||
char *buf, size_t len);
|
||||
void uio_GPDir_closeEntries(uio_NativeEntriesContext iterator);
|
||||
int uio_GPDir_entryCount(const uio_GPDir *gPDir);
|
||||
|
||||
int uio_gPDirFlagsFromPRootFlags(int flags);
|
||||
int uio_gPFileFlagsFromPRootFlags(int flags);
|
||||
uio_PRoot *uio_GPRoot_makePRoot(uio_FileSystemHandler *handler, int pRootFlags,
|
||||
uio_GPRoot_Operations *ops, uio_GPRootExtra gPRootExtra, int gPRootFlags,
|
||||
uio_Handle *handle, uio_GPDirExtra gPDirExtra, int gPDirFlags);
|
||||
int uio_GPRoot_umount(uio_PRoot *pRoot);
|
||||
|
||||
uio_GPDir *uio_GPDir_prepareSubDir(uio_GPDir *gPDir, const char *dirName);
|
||||
void uio_GPDir_commitSubDir(uio_GPDir *gPDir, const char *dirName,
|
||||
uio_GPDir *subDir);
|
||||
void uio_GPDir_addFile(uio_GPDir *gPDir, const char *fileName,
|
||||
uio_GPFile *file);
|
||||
void uio_GPDir_removeFile(uio_GPDir *gPDir, const char *fileName);
|
||||
void uio_GPDir_removeSubDir(uio_GPDir *gPDir, const char *dirName);
|
||||
void uio_GPDir_setComplete(uio_GPDir *gPDir, uio_bool flag);
|
||||
uio_GPDirEntry *uio_GPDir_getGPDirEntry(uio_GPDir *gPDir,
|
||||
const char *name);
|
||||
uio_PDirEntryHandle *uio_GPDir_getPDirEntryHandle(
|
||||
const uio_PDirHandle *pDirHandle, const char *name);
|
||||
int uio_walkGPPath(uio_GPDir *startGPDir, const char *path,
|
||||
size_t pathLen, uio_GPDir **endGPDir, const char **pathRest);
|
||||
uio_PDirHandle *uio_GPDir_makePDirHandle(uio_GPDir *gPDir);
|
||||
|
||||
void uio_GPDir_fill(uio_GPDir *gPDir);
|
||||
void uio_GPRoot_deleteGPRootExtra(uio_GPRoot *gPRoot);
|
||||
void uio_GPDir_deleteGPDirExtra(uio_GPDir *gPDir);
|
||||
void uio_GPFile_deleteGPFileExtra(uio_GPFile *gPFile);
|
||||
|
||||
void uio_GPDirHandle_delete(uio_GPDirHandle *gPDirHandle);
|
||||
void uio_GPFileHandle_delete(uio_GPFileHandle *gPFileHandle);
|
||||
void uio_GPDirEntry_delete(uio_GPDirEntry *gPDirEntry);
|
||||
uio_GPRoot *uio_GPRoot_new(uio_GPRoot_Operations *ops, uio_GPRootExtra extra,
|
||||
int flags);
|
||||
void uio_GPRoot_delete(uio_GPRoot *gPRoot);
|
||||
uio_GPDir *uio_GPDir_new(uio_PRoot *pRoot, uio_GPDirExtra extra, int flags);
|
||||
void uio_GPDir_delete(uio_GPDir *gPDir);
|
||||
uio_GPFile *uio_GPFile_new(uio_PRoot *pRoot, uio_GPFileExtra extra, int flags);
|
||||
void uio_GPFile_delete(uio_GPFile *gPFile);
|
||||
|
||||
|
||||
static inline void
|
||||
uio_GPDirEntry_ref(uio_GPDirEntry *gPDirEntry) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
if (uio_GPDirEntry_isDir(gPDirEntry)) {
|
||||
uio_MemDebug_debugRef(uio_GPDir, (void *) gPDirEntry);
|
||||
} else {
|
||||
uio_MemDebug_debugRef(uio_GPFile, (void *) gPDirEntry);
|
||||
}
|
||||
#endif
|
||||
gPDirEntry->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPDirEntry_unref(uio_GPDirEntry *gPDirEntry) {
|
||||
assert(gPDirEntry->ref > 0);
|
||||
#ifdef uio_MEM_DEBUG
|
||||
if (uio_GPDirEntry_isDir(gPDirEntry)) {
|
||||
uio_MemDebug_debugUnref(uio_GPDir, (void *) gPDirEntry);
|
||||
} else {
|
||||
uio_MemDebug_debugUnref(uio_GPFile, (void *) gPDirEntry);
|
||||
}
|
||||
#endif
|
||||
gPDirEntry->ref--;
|
||||
if (gPDirEntry->ref == 0)
|
||||
uio_GPDirEntry_delete(gPDirEntry);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPDir_ref(uio_GPDir *gPDir) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugRef(uio_GPDir, (void *) gPDir);
|
||||
#endif
|
||||
gPDir->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPDir_unref(uio_GPDir *gPDir) {
|
||||
assert(gPDir->ref > 0);
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugUnref(uio_GPDir, (void *) gPDir);
|
||||
#endif
|
||||
gPDir->ref--;
|
||||
if (gPDir->ref == 0)
|
||||
uio_GPDir_delete(gPDir);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPFile_ref(uio_GPFile *gPFile) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugRef(uio_GPFile, (void *) gPFile);
|
||||
#endif
|
||||
gPFile->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_GPFile_unref(uio_GPFile *gPFile) {
|
||||
assert(gPFile->ref > 0);
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugUnref(uio_GPFile, (void *) gPFile);
|
||||
#endif
|
||||
gPFile->ref--;
|
||||
if (gPFile->ref == 0)
|
||||
uio_GPFile_delete(gPFile);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _GPHYS_H */
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HASHTABLE_INTERNAL
|
||||
// If HASHTABLE_INTERNAL is already defined, this file is included
|
||||
// as a template. In this case hashtable.h has already been included.
|
||||
# define HASHTABLE_INTERNAL
|
||||
# include "hashtable.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mem.h"
|
||||
#include "uioport.h"
|
||||
|
||||
static void HASHTABLE_(setup)(HASHTABLE_(HashTable) *HashTable,
|
||||
uio_uint32 size);
|
||||
static void HASHTABLE_(resize)(HASHTABLE_(HashTable) *hashTable);
|
||||
static inline uio_uint32 nextPower2(uio_uint32 x);
|
||||
|
||||
static inline HASHTABLE_(HashTable) *HASHTABLE_(allocHashTable)(void);
|
||||
static inline HASHTABLE_(HashEntry) *HASHTABLE_(newHashEntry)(uio_uint32 hash,
|
||||
HASHTABLE_(Key) *key, HASHTABLE_(Value) *value,
|
||||
HASHTABLE_(HashEntry) *next);
|
||||
static inline HASHTABLE_(HashEntry) *HASHTABLE_(allocHashEntry)(void);
|
||||
static inline void HASHTABLE_(freeHashEntry)(
|
||||
HASHTABLE_(HashEntry) *entry);
|
||||
|
||||
HASHTABLE_(HashTable) *
|
||||
HASHTABLE_(newHashTable)(
|
||||
HASHTABLE_(HashFunction) hashFunction,
|
||||
HASHTABLE_(EqualFunction) equalFunction,
|
||||
HASHTABLE_(CopyFunction) copyFunction,
|
||||
HASHTABLE_(FreeFunction) freeFunction,
|
||||
uio_uint32 initialSize,
|
||||
double minFillQuotient,
|
||||
double maxFillQuotient) {
|
||||
HASHTABLE_(HashTable) *hashTable;
|
||||
|
||||
assert(maxFillQuotient >= minFillQuotient);
|
||||
|
||||
hashTable = HASHTABLE_(allocHashTable)();
|
||||
hashTable->hashFunction = hashFunction;
|
||||
hashTable->equalFunction = equalFunction;
|
||||
hashTable->copyFunction = copyFunction;
|
||||
hashTable->freeFunction = freeFunction;
|
||||
|
||||
hashTable->minFillQuotient = minFillQuotient;
|
||||
hashTable->maxFillQuotient = maxFillQuotient;
|
||||
HASHTABLE_(setup)(hashTable, initialSize);
|
||||
|
||||
return hashTable;
|
||||
}
|
||||
|
||||
uio_bool
|
||||
HASHTABLE_(add)(HASHTABLE_(HashTable) *hashTable,
|
||||
const HASHTABLE_(Key) *key, HASHTABLE_(Value) *value) {
|
||||
uio_uint32 hash;
|
||||
struct HASHTABLE_(HashEntry) *entry;
|
||||
|
||||
hash = HASHTABLE_(HASH)(hashTable, key);
|
||||
entry = hashTable->entries[hash & hashTable->hashMask];
|
||||
while (entry != NULL) {
|
||||
if (HASHTABLE_(EQUAL)(hashTable, key, entry->key)) {
|
||||
// key is already present
|
||||
return false;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
#ifdef HashTable_PROFILE
|
||||
if (hashTable->entries[hash & hashTable->hashMask] != NULL)
|
||||
hashTable->numCollisions++;
|
||||
#endif
|
||||
hashTable->entries[hash & hashTable->hashMask] =
|
||||
HASHTABLE_(newHashEntry)(hash,
|
||||
HASHTABLE_(COPY)(hashTable, key), value,
|
||||
hashTable->entries[hash & hashTable->hashMask]);
|
||||
|
||||
hashTable->numEntries++;
|
||||
if (hashTable->numEntries > hashTable->maxSize)
|
||||
HASHTABLE_(resize)(hashTable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uio_bool
|
||||
HASHTABLE_(remove)(HASHTABLE_(HashTable) *hashTable,
|
||||
const HASHTABLE_(Key) *key) {
|
||||
uio_uint32 hash;
|
||||
struct HASHTABLE_(HashEntry) **entry, *next;
|
||||
|
||||
hash = HASHTABLE_(HASH)(hashTable, key);
|
||||
entry = &hashTable->entries[hash & hashTable->hashMask];
|
||||
while (1) {
|
||||
if (*entry == NULL)
|
||||
return false;
|
||||
if (HASHTABLE_(EQUAL)(hashTable, key, (*entry)->key)) {
|
||||
// found the key
|
||||
break;
|
||||
}
|
||||
entry = &(*entry)->next;
|
||||
}
|
||||
next = (*entry)->next;
|
||||
HASHTABLE_(FREE)(hashTable, (*entry)->key);
|
||||
HASHTABLE_(freeHashEntry)(*entry);
|
||||
*entry = next;
|
||||
|
||||
hashTable->numEntries--;
|
||||
if (hashTable->numEntries < hashTable->minSize)
|
||||
HASHTABLE_(resize)(hashTable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HASHTABLE_(Value) *
|
||||
HASHTABLE_(find)(HASHTABLE_(HashTable) *hashTable,
|
||||
const HASHTABLE_(Key) *key) {
|
||||
uio_uint32 hash;
|
||||
struct HASHTABLE_(HashEntry) *entry;
|
||||
|
||||
hash = HASHTABLE_(HASH)(hashTable, key);
|
||||
entry = hashTable->entries[hash & hashTable->hashMask];
|
||||
while (entry != NULL) {
|
||||
if (HASHTABLE_(EQUAL)(hashTable, key, entry->key)) {
|
||||
// found the key
|
||||
return entry->value;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uio_uint32
|
||||
HASHTABLE_(count)(const HASHTABLE_(HashTable) *hashTable) {
|
||||
return hashTable->numEntries;
|
||||
}
|
||||
|
||||
static void
|
||||
HASHTABLE_(setup)(HASHTABLE_(HashTable) *hashTable, uio_uint32 initialSize) {
|
||||
if (initialSize < 4)
|
||||
initialSize = 4;
|
||||
hashTable->size = nextPower2((uio_uint32) ceil(
|
||||
((double) initialSize) / hashTable->maxFillQuotient));
|
||||
hashTable->hashMask = hashTable->size - 1;
|
||||
hashTable->minSize = (uio_uint32) ceil(((double) (hashTable->size >> 1))
|
||||
* hashTable->minFillQuotient);
|
||||
hashTable->maxSize = (uio_uint32) floor(((double) hashTable->size)
|
||||
* hashTable->maxFillQuotient);
|
||||
hashTable->entries = uio_calloc(hashTable->size,
|
||||
sizeof (HASHTABLE_(HashEntry) *));
|
||||
memset(hashTable->entries, '\0',
|
||||
hashTable->size * sizeof (HASHTABLE_(HashEntry) *));
|
||||
hashTable->numEntries = 0;
|
||||
#ifdef HashTable_PROFILE
|
||||
hashTable->numCollisions = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
HASHTABLE_(resize)(HASHTABLE_(HashTable) *hashTable) {
|
||||
HASHTABLE_(HashEntry) **oldEntries;
|
||||
HASHTABLE_(HashEntry) *entry, *next;
|
||||
HASHTABLE_(HashEntry) **newLocation;
|
||||
uio_uint32 oldNumEntries;
|
||||
uio_uint32 i;
|
||||
|
||||
oldNumEntries = hashTable->numEntries;
|
||||
oldEntries = hashTable->entries;
|
||||
|
||||
HASHTABLE_(setup)(hashTable, hashTable->numEntries);
|
||||
hashTable->numEntries = oldNumEntries;
|
||||
|
||||
i = 0;
|
||||
while (oldNumEntries > 0) {
|
||||
entry = oldEntries[i];
|
||||
while (entry != NULL) {
|
||||
next = entry->next;
|
||||
newLocation = &hashTable->entries[entry->hash &
|
||||
hashTable->hashMask];
|
||||
#ifdef HashTable_PROFILE
|
||||
if (*newLocation != NULL)
|
||||
hashTable->numCollisions++;
|
||||
#endif
|
||||
entry->next = *newLocation;
|
||||
*newLocation = entry;
|
||||
oldNumEntries--;
|
||||
entry = next;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
uio_free(oldEntries);
|
||||
}
|
||||
|
||||
// Adapted from "Hackers Delight"
|
||||
// Returns the smallest power of two greater or equal to x.
|
||||
static inline uio_uint32
|
||||
nextPower2(uio_uint32 x) {
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
// NB: Iterator should be considered invalid if the HashTable is changed.
|
||||
// TODO: change this (make it thread-safe)
|
||||
// this can be done by only marking items as deleted when
|
||||
// there are outstanding iterators.
|
||||
HASHTABLE_(Iterator) *
|
||||
HASHTABLE_(getIterator)(const HASHTABLE_(HashTable) *hashTable) {
|
||||
HASHTABLE_(Iterator) *result;
|
||||
uio_uint32 i;
|
||||
|
||||
result = uio_malloc(sizeof (HASHTABLE_(Iterator)));
|
||||
result->hashTable = hashTable;
|
||||
i = 0;
|
||||
while (i < hashTable->size &&
|
||||
hashTable->entries[i] == NULL)
|
||||
i++;
|
||||
result->bucketNr = i;
|
||||
result->entry = hashTable->entries[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
HASHTABLE_(iteratorDone)(const HASHTABLE_(Iterator) *iterator) {
|
||||
return iterator->bucketNr >= iterator->hashTable->size;
|
||||
}
|
||||
|
||||
HASHTABLE_(Key) *
|
||||
HASHTABLE_(iteratorKey)(HASHTABLE_(Iterator) *iterator) {
|
||||
return iterator->entry->key;
|
||||
}
|
||||
|
||||
HASHTABLE_(Value) *
|
||||
HASHTABLE_(iteratorValue)(HASHTABLE_(Iterator) *iterator) {
|
||||
return iterator->entry->value;
|
||||
}
|
||||
|
||||
HASHTABLE_(Iterator) *
|
||||
HASHTABLE_(iteratorNext)(HASHTABLE_(Iterator) *iterator) {
|
||||
uio_uint32 i;
|
||||
|
||||
if (iterator->entry != NULL) {
|
||||
iterator->entry = iterator->entry->next;
|
||||
if (iterator->entry != NULL)
|
||||
return iterator;
|
||||
}
|
||||
|
||||
i = iterator->bucketNr + 1;
|
||||
while (i < iterator->hashTable->size &&
|
||||
iterator->hashTable->entries[i] == NULL)
|
||||
i++;
|
||||
iterator->bucketNr = i;
|
||||
iterator->entry = iterator->hashTable->entries[i];
|
||||
return iterator;
|
||||
}
|
||||
|
||||
void
|
||||
HASHTABLE_(freeIterator)(HASHTABLE_(Iterator) *iterator) {
|
||||
uio_free(iterator);
|
||||
}
|
||||
|
||||
static inline HASHTABLE_(HashTable) *
|
||||
HASHTABLE_(allocHashTable)(void) {
|
||||
return uio_malloc(sizeof (HASHTABLE_(HashTable)));
|
||||
}
|
||||
|
||||
static inline HASHTABLE_(HashEntry) *
|
||||
HASHTABLE_(newHashEntry)(uio_uint32 hash, HASHTABLE_(Key) *key,
|
||||
HASHTABLE_(Value) *value, HASHTABLE_(HashEntry) *next) {
|
||||
HASHTABLE_(HashEntry) *result;
|
||||
|
||||
result = HASHTABLE_(allocHashEntry)();
|
||||
result->hash = hash;
|
||||
result->key = key;
|
||||
result->value = value;
|
||||
result->next = next;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline HASHTABLE_(HashEntry) *
|
||||
HASHTABLE_(allocHashEntry)(void) {
|
||||
return uio_malloc(sizeof (HASHTABLE_(HashEntry)));
|
||||
}
|
||||
|
||||
void
|
||||
HASHTABLE_(deleteHashTable)(HASHTABLE_(HashTable) *hashTable) {
|
||||
uio_uint32 i;
|
||||
HASHTABLE_(HashEntry) *entry, *next;
|
||||
HASHTABLE_(HashEntry) **bucketPtr;
|
||||
|
||||
i = hashTable->numEntries;
|
||||
bucketPtr = hashTable->entries;
|
||||
while (i > 0) {
|
||||
entry = *bucketPtr;
|
||||
while (entry != NULL) {
|
||||
next = entry->next;
|
||||
HASHTABLE_(FREE)(hashTable, entry->key);
|
||||
HASHTABLE_(freeHashEntry)(entry);
|
||||
entry = next;
|
||||
i--;
|
||||
}
|
||||
bucketPtr++;
|
||||
}
|
||||
uio_free(hashTable->entries);
|
||||
uio_free(hashTable);
|
||||
}
|
||||
|
||||
static inline void
|
||||
HASHTABLE_(freeHashEntry)(HASHTABLE_(HashEntry) *entry) {
|
||||
uio_free(entry);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
// The 'already included' check must be done slightly more complicated
|
||||
// than usually. This file may be included directly only once,
|
||||
// but it may be included my derivative HashTable definitions that use
|
||||
// this file as a template more than once.
|
||||
#if !defined(_HASHTABLE_H) || defined(HASHTABLE_GENERIC)
|
||||
#if defined(HASHTABLE_)
|
||||
# define HASHTABLE_GENERIC
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "uioport.h"
|
||||
|
||||
// Define to enable profiling.
|
||||
#define HashTable_PROFILE
|
||||
|
||||
// You can use inline hash functions for extra speed, by using this file as
|
||||
// a template.
|
||||
// To do this, make a new .h and .c file. In the .h file, define the macros
|
||||
// (and typedefs) from the HASHTABLE_ block below.
|
||||
// In the .c file, #define HASHTABLE_INTERNAL, #include the .h file
|
||||
// and hashtable.c (in this order), and add the necessary functions.
|
||||
#ifndef HASHTABLE_
|
||||
# define HASHTABLE_(identifier) HashTable ## _ ## identifier
|
||||
typedef void HashTable_Key;
|
||||
typedef void HashTable_Value;
|
||||
# define HashTable_HASH(hashTable, hashValue) \
|
||||
(hashTable)->hashFunction(hashValue)
|
||||
# define HashTable_EQUAL(hashTable, hashKey1, hashKey2) \
|
||||
(hashTable)->equalFunction(hashKey1, hashKey2)
|
||||
# define HashTable_COPY(hashTable, hashKey) \
|
||||
(hashTable)->copyFunction(hashKey)
|
||||
# define HashTable_FREE(hashTable, hashKey) \
|
||||
(hashTable)->copyFunction(hashKey)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef uio_uint32 (*HASHTABLE_(HashFunction))(const HASHTABLE_(Key) *);
|
||||
typedef uio_bool (*HASHTABLE_(EqualFunction))(const HASHTABLE_(Key) *,
|
||||
const HASHTABLE_(Key) *);
|
||||
typedef HASHTABLE_(Value) *(*HASHTABLE_(CopyFunction))(
|
||||
const HASHTABLE_(Value) *);
|
||||
typedef void (*HASHTABLE_(FreeFunction))(HASHTABLE_(Value) *);
|
||||
|
||||
typedef struct HASHTABLE_(HashTable) HASHTABLE_(HashTable);
|
||||
typedef struct HASHTABLE_(HashEntry) HASHTABLE_(HashEntry);
|
||||
typedef struct HASHTABLE_(Iterator) HASHTABLE_(Iterator);
|
||||
|
||||
struct HASHTABLE_(HashTable) {
|
||||
HASHTABLE_(HashFunction) hashFunction;
|
||||
HASHTABLE_(EqualFunction) equalFunction;
|
||||
HASHTABLE_(CopyFunction) copyFunction;
|
||||
HASHTABLE_(FreeFunction) freeFunction;
|
||||
|
||||
double minFillQuotient;
|
||||
// How much of half of the hashtable needs to be filled
|
||||
// before resizing to size/2.
|
||||
double maxFillQuotient;
|
||||
// How much of the hashTable needs to be filled before
|
||||
// resizing to size*2.
|
||||
uio_uint32 minSize;
|
||||
// Resize to size/2 when below this size.
|
||||
uio_uint32 maxSize;
|
||||
// Resize to size*2 when above this size.
|
||||
uio_uint32 size;
|
||||
// The number of buckets in the hash table.
|
||||
uio_uint32 hashMask;
|
||||
// Mask to take on a the calculated hash value, to make it
|
||||
// fit into the table.
|
||||
|
||||
HASHTABLE_(HashEntry) **entries;
|
||||
// The actual entries
|
||||
|
||||
uio_uint32 numEntries;
|
||||
#ifdef HashTable_PROFILE
|
||||
uio_uint32 numCollisions;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct HASHTABLE_(HashEntry) {
|
||||
uio_uint32 hash;
|
||||
HASHTABLE_(Key) *key;
|
||||
HASHTABLE_(Value) *value;
|
||||
HASHTABLE_(HashEntry) *next;
|
||||
};
|
||||
|
||||
struct HASHTABLE_(Iterator) {
|
||||
const HASHTABLE_(HashTable) *hashTable;
|
||||
uio_uint32 bucketNr;
|
||||
HASHTABLE_(HashEntry) *entry;
|
||||
};
|
||||
|
||||
HASHTABLE_(HashTable) *HASHTABLE_(newHashTable)(
|
||||
HASHTABLE_(HashFunction) hashFunction,
|
||||
HASHTABLE_(EqualFunction) equalFunction,
|
||||
HASHTABLE_(CopyFunction) copyFunction,
|
||||
HASHTABLE_(FreeFunction) freeFunction, uio_uint32 initialSize,
|
||||
double minFillQuotient, double maxFillQuotient);
|
||||
uio_bool HASHTABLE_(add)(HASHTABLE_(HashTable) *hashTable,
|
||||
const HASHTABLE_(Key) *key, HASHTABLE_(Value) *value);
|
||||
uio_bool HASHTABLE_(remove)(HASHTABLE_(HashTable) *hashTable,
|
||||
const HASHTABLE_(Key) *key);
|
||||
HASHTABLE_(Value) *HASHTABLE_(find)(
|
||||
HASHTABLE_(HashTable) *hashTable, const HASHTABLE_(Key) *key);
|
||||
uio_uint32 HASHTABLE_(count)(const HASHTABLE_(HashTable) *hashTable);
|
||||
void HASHTABLE_(deleteHashTable)(HASHTABLE_(HashTable) *hashTable);
|
||||
HASHTABLE_(Iterator) *HASHTABLE_(getIterator)(
|
||||
const HASHTABLE_(HashTable) *hashTable);
|
||||
int HASHTABLE_(iteratorDone)(const HASHTABLE_(Iterator) *iterator);
|
||||
HASHTABLE_(Key) *HASHTABLE_(iteratorKey)(HASHTABLE_(Iterator) *iterator);
|
||||
HASHTABLE_(Value) *HASHTABLE_(iteratorValue)(HASHTABLE_(Iterator) *iterator);
|
||||
HASHTABLE_(Iterator) *HASHTABLE_(iteratorNext)(HASHTABLE_(Iterator) *iterator);
|
||||
void HASHTABLE_(freeIterator)(HASHTABLE_(Iterator) *iterator);
|
||||
|
||||
#ifndef HASHTABLE_INTERNAL
|
||||
# undef HASHTABLE_
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_HASHTABLE_H) || defined(HASHTABLE_GENERIC) */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IO_H
|
||||
#define _IO_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef struct uio_Handle uio_Handle;
|
||||
typedef struct uio_DirHandle uio_DirHandle;
|
||||
typedef struct uio_DirList uio_DirList;
|
||||
typedef struct uio_MountHandle uio_MountHandle;
|
||||
|
||||
typedef enum {
|
||||
uio_MOUNT_BOTTOM = (0 << 2),
|
||||
uio_MOUNT_TOP = (1 << 2),
|
||||
uio_MOUNT_BELOW = (2 << 2),
|
||||
uio_MOUNT_ABOVE = (3 << 2)
|
||||
} uio_MountLocation;
|
||||
|
||||
#include "match.h"
|
||||
#include "fstypes.h"
|
||||
#include "mount.h"
|
||||
#include "mounttree.h"
|
||||
#include "uiostream.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct uio_AutoMount {
|
||||
const char *pattern;
|
||||
match_MatchType matchType;
|
||||
uio_FileSystemID fileSystemID;
|
||||
int mountFlags;
|
||||
// uio_AutoMount **autoMount;
|
||||
// automount rules to apply to file systems automounted
|
||||
// because of this automount rule.
|
||||
};
|
||||
|
||||
#ifndef uio_INTERNAL
|
||||
struct uio_DirList {
|
||||
const char **names;
|
||||
int numNames;
|
||||
// The rest of the fields are not visible from the outside
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// Initialise the resource system
|
||||
void uio_init(void);
|
||||
|
||||
// Uninitialise the resource system
|
||||
void uio_unInit(void);
|
||||
|
||||
// Open a repository.
|
||||
uio_Repository *uio_openRepository(int flags);
|
||||
|
||||
// Close a repository opened by uio_openRepository().
|
||||
void uio_closeRepository(uio_Repository *repository);
|
||||
|
||||
// Mount a directory into a repository
|
||||
uio_MountHandle *uio_mountDir(uio_Repository *destRep, const char *mountPoint,
|
||||
uio_FileSystemID fsType,
|
||||
uio_DirHandle *sourceDir, const char *sourcePath,
|
||||
const char *inPath, uio_AutoMount **autoMount, int flags,
|
||||
uio_MountHandle *relative);
|
||||
|
||||
// Unmount a previously mounted dir.
|
||||
int uio_unmountDir(uio_MountHandle *mountHandle);
|
||||
|
||||
// Unmount all previously mounted dirs.
|
||||
int uio_unmountAllDirs(uio_Repository *repository);
|
||||
|
||||
// Open a file
|
||||
uio_Handle *uio_open(uio_DirHandle *dir, const char *file, int flags,
|
||||
mode_t mode);
|
||||
|
||||
// Close a file descriptor for a file opened by uio_open
|
||||
int uio_close(uio_Handle *handle);
|
||||
|
||||
// Fstat a file descriptor
|
||||
int uio_fstat(uio_Handle *handle, struct stat *statBuf);
|
||||
|
||||
int uio_stat(uio_DirHandle *dir, const char *path, struct stat *statBuf);
|
||||
|
||||
int uio_mkdir(uio_DirHandle *dir, const char *name, mode_t mode);
|
||||
|
||||
ssize_t uio_read(uio_Handle *handle, void *buf, size_t count);
|
||||
|
||||
int uio_rmdir(uio_DirHandle *dirHandle, const char *path);
|
||||
|
||||
int uio_lseek(uio_Handle *handle, off_t offset, int whence);
|
||||
|
||||
int uio_write(uio_Handle *handle, const void *buf, size_t count);
|
||||
|
||||
int uio_unlink(uio_DirHandle *dirHandle, const char *path);
|
||||
|
||||
// Get a directory handle.
|
||||
uio_DirHandle *uio_openDir(uio_Repository *repository, const char *path,
|
||||
int flags);
|
||||
#define uio_OD_ROOT 1
|
||||
|
||||
// Get a directory handle using a path relative to another handle.
|
||||
uio_DirHandle *uio_openDirRelative(uio_DirHandle *base, const char *path,
|
||||
int flags);
|
||||
|
||||
// Release a directory handle
|
||||
int uio_closeDir(uio_DirHandle *dirHandle);
|
||||
|
||||
uio_DirList *uio_getDirList(uio_DirHandle *dirHandle, const char *path,
|
||||
const char *pattern, match_MatchType matchType);
|
||||
void uio_freeDirList(uio_DirList *dirList);
|
||||
|
||||
// For debugging purposes
|
||||
void uio_DirHandle_print(const uio_DirHandle *dirHandle, FILE *out);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
# define uio_DEBUG
|
||||
#endif
|
||||
|
||||
#endif /* _IO_H */
|
||||
|
||||
@@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
// auxiliary functions for use by io.c
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "ioaux.h"
|
||||
#include "iointrn.h"
|
||||
#include "uioport.h"
|
||||
#include "paths.h"
|
||||
|
||||
static int copyError(int error,
|
||||
uio_FileSystemHandler *fromHandler, uio_Handle *fromHandle,
|
||||
uio_FileSystemHandler *toHandler, uio_Handle *toHandle,
|
||||
uio_PDirHandle *toDir, const char *toName, char *buf);
|
||||
|
||||
/*
|
||||
* Follow a path starting from a specified physical dir as long as possible.
|
||||
* When you can get no further, 'endPDirHandle' will be filled in with a
|
||||
* reference to the dir where you ended up, and 'pathRest' will point into
|
||||
* the original path. to the beginning of the part that was not matched.
|
||||
* It is allowed to have endPDirHandle point to pDirHandle and/or restPath
|
||||
* point to path when calling this function. Just take care to keep a
|
||||
* reference to the original so you can decrement the ref counter.
|
||||
* returns: 0 if the complete path was matched
|
||||
* ENOENT if some component (the next one) didn't exists
|
||||
* ENODIR if a component (the next one) exists but isn't a dir
|
||||
*/
|
||||
int
|
||||
uio_walkPhysicalPath(uio_PDirHandle *startPDirHandle, const char *path,
|
||||
size_t pathLen, uio_PDirHandle **endPDirHandle,
|
||||
const char **pathRest) {
|
||||
const char *pathEnd;
|
||||
const char *partStart, *partEnd;
|
||||
char *tempBuf;
|
||||
uio_PDirHandle *pDirHandle;
|
||||
uio_PDirEntryHandle *entry;
|
||||
int retVal;
|
||||
|
||||
uio_PDirHandle_ref(startPDirHandle);
|
||||
pDirHandle = startPDirHandle;
|
||||
tempBuf = uio_alloca(strlen(path) + 1);
|
||||
pathEnd = path + pathLen;
|
||||
getFirstPathComponent(path, pathEnd, &partStart, &partEnd);
|
||||
while (1) {
|
||||
if (partStart == pathEnd) {
|
||||
retVal = 0;
|
||||
break;
|
||||
}
|
||||
memcpy(tempBuf, partStart, partEnd - partStart);
|
||||
tempBuf[partEnd - partStart] = '\0';
|
||||
|
||||
entry = uio_getPDirEntryHandle(pDirHandle, tempBuf);
|
||||
if (entry == NULL) {
|
||||
retVal = ENOENT;
|
||||
break;
|
||||
}
|
||||
if (!uio_PDirEntryHandle_isDir(entry)) {
|
||||
uio_PDirEntryHandle_unref(entry);
|
||||
retVal = ENOTDIR;
|
||||
break;
|
||||
}
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
pDirHandle = (uio_PDirHandle *) entry;
|
||||
getNextPathComponent(pathEnd, &partStart, &partEnd);
|
||||
}
|
||||
|
||||
*pathRest = partStart;
|
||||
*endPDirHandle = pDirHandle;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// Make a all directory components of a path, inside a physical directory.
|
||||
uio_PDirHandle *
|
||||
uio_makePath(uio_PDirHandle *pDirHandle, const char *path, size_t pathLen,
|
||||
mode_t mode) {
|
||||
const char *rest, *start, *end;
|
||||
uio_PDirHandle *(*mkdirFun)(uio_PDirHandle *, const char *, mode_t);
|
||||
char *buf;
|
||||
const char *pathEnd;
|
||||
uio_PDirHandle *newPDirHandle;
|
||||
|
||||
mkdirFun = pDirHandle->pRoot->handler->mkdir;
|
||||
if (mkdirFun == NULL) {
|
||||
errno = ENOSYS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pathEnd = path + pathLen;
|
||||
|
||||
buf = uio_alloca(pathLen + 1);
|
||||
// worst case length
|
||||
|
||||
uio_walkPhysicalPath(pDirHandle, path, pathLen, &pDirHandle, &rest);
|
||||
// The reference to the original pDirHandle is still kept
|
||||
// by the calling function; uio_PDirHandle_unref should not
|
||||
// be called for it.
|
||||
// Rest now points into 'path' to the part from where no physical
|
||||
// dir exists.
|
||||
|
||||
getFirstPathComponent(rest, pathEnd, &start, &end);
|
||||
while (start < pathEnd) {
|
||||
memcpy(buf, start, end - start);
|
||||
buf[end - start] = '\0';
|
||||
|
||||
newPDirHandle = mkdirFun(pDirHandle, buf, mode);
|
||||
if (newPDirHandle == NULL) {
|
||||
int saveErrno = errno;
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
errno = saveErrno;
|
||||
return NULL;
|
||||
}
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
pDirHandle = newPDirHandle;
|
||||
getNextPathComponent(pathEnd, &start, &end);
|
||||
}
|
||||
return pDirHandle;
|
||||
}
|
||||
|
||||
/*
|
||||
* permissions should already have been checked
|
||||
*
|
||||
* The new file will have the same permissions as the old.
|
||||
* If an error occurs during copying, an attempt will be made to
|
||||
* remove the copy.
|
||||
*/
|
||||
int
|
||||
uio_copyFilePhysical(uio_PDirHandle *fromDir, const char *fromName,
|
||||
uio_PDirHandle *toDir, const char *toName) {
|
||||
uio_FileSystemHandler *fromHandler, *toHandler;
|
||||
uio_Handle *fromHandle;
|
||||
uio_Handle *toHandle;
|
||||
#define BUFSIZE 0x10000
|
||||
struct stat statBuf;
|
||||
char *buf, *bufPtr;
|
||||
ssize_t numInBuf, numWritten;
|
||||
|
||||
fromHandler = fromDir->pRoot->handler;
|
||||
toHandler = toDir->pRoot->handler;
|
||||
if (toHandler->write == NULL || fromHandler->fstat == NULL ||
|
||||
toHandler->unlink == NULL) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fromHandle = fromHandler->open(fromDir, fromName, O_RDONLY, 0);
|
||||
if (fromHandle == NULL) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fromHandler->fstat(fromHandle, &statBuf) == -1)
|
||||
return copyError(errno, fromHandler, fromHandle,
|
||||
toHandler, NULL, NULL, NULL, NULL);
|
||||
|
||||
toHandle = toHandler->open(toDir, toName, O_WRONLY | O_CREAT | O_EXCL,
|
||||
statBuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
|
||||
if (toHandle == NULL)
|
||||
return copyError(errno, fromHandler, fromHandle,
|
||||
toHandler, NULL, NULL, NULL, NULL);
|
||||
|
||||
buf = uio_malloc(BUFSIZE);
|
||||
// not allocated on the stack, as this function may be called
|
||||
// from a thread with little stack space.
|
||||
while (1) {
|
||||
numInBuf = fromHandler->read(fromHandle, buf, BUFSIZE);
|
||||
if (numInBuf == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return copyError (errno, fromHandler, fromHandle,
|
||||
toHandler, toHandle, toDir, toName, buf);
|
||||
}
|
||||
if (numInBuf == 0)
|
||||
break;
|
||||
|
||||
bufPtr = buf;
|
||||
do {
|
||||
numWritten = toHandler->write(toHandle, bufPtr, numInBuf);
|
||||
if (numWritten == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return copyError (errno, fromHandler, fromHandle,
|
||||
toHandler, toHandle, toDir, toName, buf);
|
||||
}
|
||||
numInBuf -= numWritten;
|
||||
bufPtr += numWritten;
|
||||
} while (numInBuf > 0);
|
||||
}
|
||||
|
||||
uio_free(buf);
|
||||
toHandler->close(toHandle);
|
||||
fromHandler->close(fromHandle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes fromHandle if it's not -1.
|
||||
* Closes fromHandle if it's not -1.
|
||||
* Removes 'toName' from 'toDir' if it's not NULL.
|
||||
* Frees 'buf' if not NULL.
|
||||
* Always returns -1.
|
||||
*/
|
||||
static int
|
||||
copyError(int error,
|
||||
uio_FileSystemHandler *fromHandler, uio_Handle *fromHandle,
|
||||
uio_FileSystemHandler *toHandler, uio_Handle *toHandle,
|
||||
uio_PDirHandle *toDir, const char *toName, char *buf) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error while copying: %s\n", strerror(error));
|
||||
#endif
|
||||
|
||||
if (fromHandle != NULL)
|
||||
fromHandler->close(fromHandle);
|
||||
|
||||
if (toHandle != NULL)
|
||||
toHandler->close(toHandle);
|
||||
|
||||
if (toName != NULL)
|
||||
toHandler->unlink(toDir, toName);
|
||||
|
||||
if (buf != NULL)
|
||||
uio_free(buf);
|
||||
|
||||
errno = error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description: find PDirHandle and MountInfo structures for reading and
|
||||
* writing for a path from a DirHandle.
|
||||
* This can be used for opening a file and creating directories.
|
||||
* Arguments: dirHandle - the directory to which the path is relative.
|
||||
* path - the path to the component that is to be accessed.
|
||||
* The last component does not have to exist.
|
||||
* flags - used to specify what kind of access is requested
|
||||
* Either O_RDONLY, O_RDWR, O_WRONLY. They may be
|
||||
* OR'd with other values accepted by open(). These
|
||||
* are ignored.
|
||||
* mountInfoReadPtr - pointer to location where the pointer
|
||||
* to the MountInfo structure for the reading location
|
||||
* should be stored.
|
||||
* readPDirHandlePtr - pointer to the location where the pointer
|
||||
* to the PDirHandle used for reading should be stored.
|
||||
* mountInfoWritePtr - pointer to location where the pointer
|
||||
* to the MountInfo structure for the writing location
|
||||
* should be stored.
|
||||
* writePDirHandlePtr - pointer to the location where the pointer
|
||||
* to the PDirHandle used for writing should be stored.
|
||||
* NULL if O_RDONLY was specified.
|
||||
* If this is the same dir as the one refered
|
||||
* to by readPDirHandlePtr, the handles will be the
|
||||
* same too.
|
||||
* restPtr - pointer to a newly created string with as contents
|
||||
* the last component of 'path'.
|
||||
* The caller is responsible for freeing this.
|
||||
* Returns: 0 - success
|
||||
* -1 - failure (errno set)
|
||||
* NB: This is the function that would most benefit from
|
||||
* the introduction of LDirs.
|
||||
* This is also the most messy function. It could
|
||||
* use some more comments, or a cleanup (if possible).
|
||||
*/
|
||||
int
|
||||
uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path,
|
||||
int flags,
|
||||
uio_MountInfo **mountInfoReadPtr, uio_PDirHandle **readPDirHandlePtr,
|
||||
uio_MountInfo **mountInfoWritePtr, uio_PDirHandle **writePDirHandlePtr,
|
||||
char **restPtr) {
|
||||
char *fullPath; // path from dirHandle with 'path' added
|
||||
const char *pRootPath; // path from the pRoot of a physical tree
|
||||
const char *rest, *readRest;
|
||||
uio_MountTree *tree;
|
||||
uio_MountTreeItem *item;
|
||||
uio_MountTreeItem *readItem, *writeItem;
|
||||
uio_PDirHandle *readPDirHandle, *writePDirHandle, *pDirHandle;
|
||||
int retVal;
|
||||
uio_bool entryExists;
|
||||
// Set if the entry pointed to by path exists (including
|
||||
// the last component of the path)
|
||||
|
||||
// Determine the absolute path from 'path' which is relative to dirHandle.
|
||||
if (uio_resolvePath(dirHandle, path, strlen(path), &fullPath) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the MountTree effective for the path
|
||||
uio_findMountTree(dirHandle->repository->mountTree, fullPath,
|
||||
&tree, &rest);
|
||||
|
||||
readItem = NULL;
|
||||
readPDirHandle = NULL;
|
||||
writeItem = NULL;
|
||||
writePDirHandle = NULL;
|
||||
readRest = NULL;
|
||||
// Satisfy compiler.
|
||||
entryExists = false;
|
||||
// try all the MountInfo structures in effect for this MountTree
|
||||
for (item = tree->pLocs; item != NULL; item = item->next) {
|
||||
pRootPath = uio_mountTreeItemRestPath(item, tree->lastComp, fullPath);
|
||||
retVal = uio_walkPhysicalPath(item->mountInfo->pDirHandle, pRootPath,
|
||||
strlen(pRootPath), &pDirHandle, &rest);
|
||||
// rest points inside fullPath
|
||||
if (retVal == 0) {
|
||||
// even the last component appeared to be a dir
|
||||
// As the last component did exist, we don't go on.
|
||||
uio_free(fullPath);
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
if (readPDirHandle != NULL)
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
// check if this MountTreeItem is suitable for writing
|
||||
if (writeItem == NULL && !uio_mountInfoIsReadOnly(item->mountInfo))
|
||||
writeItem = item;
|
||||
if (strchr(rest, '/') == NULL) {
|
||||
// There's only dir component that was not matched.
|
||||
uio_PDirEntryHandle *entry;
|
||||
|
||||
// This MountInfo will do for reading, if the file from the last
|
||||
// component is present in this dir.
|
||||
entry = uio_getPDirEntryHandle(pDirHandle, rest);
|
||||
if (entry != NULL) {
|
||||
// Entry is not a dir, as otherwise uio_getPDirEntryHandle
|
||||
// wouldn't have stopped where it did.
|
||||
uio_PDirEntryHandle_unref(entry);
|
||||
readItem = item;
|
||||
if (readPDirHandle != NULL)
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
readPDirHandle = pDirHandle;
|
||||
readRest = rest;
|
||||
entryExists = true;
|
||||
break;
|
||||
} else {
|
||||
if (readItem == NULL) {
|
||||
// Keep the first one.
|
||||
readItem = item;
|
||||
assert(readPDirHandle == NULL);
|
||||
readPDirHandle = pDirHandle;
|
||||
readRest = rest;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// There is more than one dir component that was not matched.
|
||||
// If the first component of the non-matched part is a file,
|
||||
// stop here and don't check lower dirs.
|
||||
if (retVal == ENOTDIR) {
|
||||
uio_free(fullPath);
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
if (readPDirHandle != NULL)
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
} // for
|
||||
// readItem is set to the first readItem for which the path completely
|
||||
// exists (including the final component). If there's no such readItem,
|
||||
// it is set to the first path for which the path exists, but without
|
||||
// the final component (entryExists is false in this case). If there's
|
||||
// no such path either, it's set to NULL.
|
||||
|
||||
if (readItem == NULL) {
|
||||
uio_free(fullPath);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
// write access is not needed
|
||||
*mountInfoReadPtr = readItem->mountInfo;
|
||||
*readPDirHandlePtr = readPDirHandle;
|
||||
// Don't touch mountInfoWritePtr and writePDirHandlePtr.
|
||||
// they'd be NULL.
|
||||
*restPtr = uio_strdup(readRest);
|
||||
uio_free(fullPath);
|
||||
return 0;
|
||||
} else {
|
||||
if (!entryExists && !(flags & O_CREAT)) {
|
||||
// Though the path to the entry existed (readPDirHandle is set to
|
||||
// it), the entry itself doesn't, so we can't use it unless we
|
||||
// intend to create it.
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
uio_free(fullPath);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (writeItem == readItem) {
|
||||
// The read directory is usable as write directory too.
|
||||
*mountInfoReadPtr = readItem->mountInfo;
|
||||
*readPDirHandlePtr = readPDirHandle;
|
||||
*mountInfoWritePtr = writeItem->mountInfo;
|
||||
// writeItem == readItem
|
||||
uio_PDirHandle_ref(readPDirHandle);
|
||||
*writePDirHandlePtr = readPDirHandle;
|
||||
// No copy&paste error, the read PDirHandle is the write
|
||||
// pDirHandle too.
|
||||
*restPtr = uio_strdup(readRest);
|
||||
uio_free(fullPath);
|
||||
return 0;
|
||||
}
|
||||
if (writeItem == NULL) {
|
||||
uio_free(fullPath);
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
errno = EPERM;
|
||||
// readItem is not NULL, so ENOENT would not be correct here.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// There exists no path for a write dir, so it will have to be created.
|
||||
// writeMountInfo indicates the physical tree where it should end up.
|
||||
pRootPath = uio_mountTreeItemRestPath(writeItem, tree->lastComp,
|
||||
fullPath);
|
||||
|
||||
rest = strrchr(pRootPath, '/');
|
||||
// rest points inside fullPath
|
||||
if (rest == NULL) {
|
||||
rest = pRootPath;
|
||||
uio_PDirHandle_ref(writeItem->mountInfo->pDirHandle);
|
||||
writePDirHandle = writeItem->mountInfo->pDirHandle;
|
||||
} else {
|
||||
writePDirHandle = uio_makePath(writeItem->mountInfo->pDirHandle,
|
||||
pRootPath, rest - pRootPath, 0777);
|
||||
if (writePDirHandle == NULL) {
|
||||
int saveErrno;
|
||||
if (errno == ENOSYS) {
|
||||
// mkdir not supported. We want to report that we failed
|
||||
// because of an error in the underlying layer.
|
||||
// EIO sounds like the best choice.
|
||||
errno = EIO;
|
||||
}
|
||||
saveErrno = errno;
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
uio_free(fullPath);
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
rest++; // skip the '/'
|
||||
}
|
||||
|
||||
if (!entryExists) {
|
||||
// The path to the read dir exists, but the entry itself doesn't.
|
||||
// After we created the write dir, the same thing holds for
|
||||
// the write dir. As it occurs in an earlier MountItem, we'll use
|
||||
// the writeItem (and writePDirHandle) for reading too.
|
||||
readItem = writeItem;
|
||||
uio_PDirHandle_ref(writePDirHandle);
|
||||
uio_PDirHandle_unref(readPDirHandle);
|
||||
readPDirHandle = writePDirHandle;
|
||||
}
|
||||
|
||||
*mountInfoReadPtr = readItem->mountInfo;
|
||||
*readPDirHandlePtr = readPDirHandle;
|
||||
*mountInfoReadPtr = writeItem->mountInfo;
|
||||
*writePDirHandlePtr = writePDirHandle;
|
||||
*restPtr = uio_strdup(rest);
|
||||
uio_free(fullPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get handles to the (existing) physical dirs that are effective in a
|
||||
// path 'path' relative from 'dirHandle'
|
||||
// returns the PDirHandles through 'pDirHandles'. It is NULL if none were
|
||||
// found.
|
||||
// numPDirHandles will contain the number of PDirHandles found.
|
||||
// returns 0 if everything went ok.
|
||||
// returns -1 in case of an error; errno is set.
|
||||
int
|
||||
uio_getPathPhysicalDirs(uio_DirHandle *dirHandle, const char *path,
|
||||
size_t pathLen, uio_PDirHandle ***resPDirHandles,
|
||||
int *resNumPDirHandles, uio_MountTreeItem ***resItems) {
|
||||
uio_PDirHandle **pDirHandles;
|
||||
char *fullPath; // path from dirHandle with 'path' added
|
||||
uio_MountTree *tree;
|
||||
const char *rest;
|
||||
uio_MountTreeItem *item, **items;
|
||||
const char *pRootPath; // path from the pRoot of a physical tree
|
||||
int numPDirHandles;
|
||||
int pDirI; // PDirHandle iterator
|
||||
|
||||
// Determine the absolute path from 'path', which is relative to dirHandle.
|
||||
if (uio_resolvePath(dirHandle, path, pathLen, &fullPath) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the MountTree effective for the path
|
||||
uio_findMountTree(dirHandle->repository->mountTree, fullPath,
|
||||
&tree, &rest);
|
||||
|
||||
// fill pDirHandles with all the PDirHandles for the path
|
||||
numPDirHandles = uio_mountTreeCountPLocs(tree);
|
||||
pDirHandles = uio_malloc(numPDirHandles * sizeof (uio_PDirHandle *));
|
||||
if (resItems != NULL) {
|
||||
items = uio_malloc(numPDirHandles * sizeof (uio_MountTreeItem *));
|
||||
} else {
|
||||
items = NULL; // satisfy compiler
|
||||
}
|
||||
pDirI = 0;
|
||||
for (item = tree->pLocs; item != NULL; item = item->next) {
|
||||
uio_PDirHandle *pDirHandle;
|
||||
|
||||
pRootPath = uio_mountTreeItemRestPath(item, tree->lastComp, fullPath);
|
||||
switch (uio_walkPhysicalPath(item->mountInfo->pDirHandle, pRootPath,
|
||||
strlen(pRootPath), &pDirHandle, &rest)) {
|
||||
case 0:
|
||||
// complete path was matched
|
||||
pDirHandles[pDirI] = pDirHandle;
|
||||
if (resItems != NULL)
|
||||
items[pDirI] = item;
|
||||
pDirI++;
|
||||
continue;
|
||||
case ENOENT:
|
||||
// some component couldn't be matched
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
continue;
|
||||
case ENOTDIR:
|
||||
// next component was not a dir
|
||||
// Don't look further at other mount Items.
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
numPDirHandles = pDirI;
|
||||
|
||||
uio_free(fullPath);
|
||||
|
||||
*resPDirHandles = uio_realloc(pDirHandles,
|
||||
numPDirHandles * sizeof (uio_PDirHandle *));
|
||||
if (resItems != NULL)
|
||||
*resItems = uio_realloc(items,
|
||||
numPDirHandles * sizeof (uio_MountTreeItem *));
|
||||
*resNumPDirHandles = numPDirHandles;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns 0 if the path is valid and exists
|
||||
// returns -1 if the path is not valid or does not exist.
|
||||
// in this case errno will be set to:
|
||||
// ENOENT if some component didn't exist
|
||||
// ENOTDIR is some component exists, but is not a dir
|
||||
// something else (like EPATHTOOLONG) for internal errors
|
||||
// 'resolvedPath' will be set to the absolute path as returned by
|
||||
// uio_resolvePath.
|
||||
int
|
||||
uio_verifyPath(uio_DirHandle *dirHandle, const char *path,
|
||||
char **resolvedPath) {
|
||||
uio_MountTree *tree;
|
||||
uio_MountTreeItem *item;
|
||||
const char *rest;
|
||||
int retVal;
|
||||
|
||||
// TODO: "////", "/somedir//", and "//somedir" are accepted as valid
|
||||
|
||||
// Determine the absolute path from 'path' which is relative to dirHandle.
|
||||
if (uio_resolvePath(dirHandle, path, strlen(path), resolvedPath) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the MountTree effective for the path
|
||||
uio_findMountTree(dirHandle->repository->mountTree, *resolvedPath,
|
||||
&tree, &rest);
|
||||
|
||||
if (rest[0] == '\0') {
|
||||
// Complete match. Even if there are no pLocs in effect here
|
||||
// (which can only happen in case the mount Tree is empty and
|
||||
// we're viewing '/').
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try all the MountInfo structures in effect for this MountTree
|
||||
for (item = tree->pLocs; item != NULL; item = item->next) {
|
||||
const char *pRootPath;
|
||||
uio_PDirHandle *pDirHandle;
|
||||
|
||||
pRootPath = uio_mountTreeItemRestPath(item, tree->lastComp,
|
||||
*resolvedPath);
|
||||
retVal = uio_walkPhysicalPath(item->mountInfo->pDirHandle, pRootPath,
|
||||
strlen(pRootPath), &pDirHandle, &rest);
|
||||
uio_PDirHandle_unref(pDirHandle);
|
||||
switch (retVal) {
|
||||
case 0:
|
||||
// complete match. We're done.
|
||||
return 0;
|
||||
case ENOTDIR:
|
||||
// A component is matched, but not as a dir. Failed.
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
case ENOENT:
|
||||
// no match; try next pLoc
|
||||
continue;
|
||||
default:
|
||||
// Unknown error. Let's bail out just to be safe.
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Warning: Unknown error from "
|
||||
"uio_walkPhysicalPath: %s\n", strerror(retVal));
|
||||
#endif
|
||||
errno = retVal;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// No match, exit with ENOENT.
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the absolute path pointed to by 'path' relative to 'dirHandle'
|
||||
// The new path will be put in '*destPath', which will be newly allocated.
|
||||
// It will be \0-terminated, and the length will be returned.
|
||||
// On error, -1 will be returned, and errno will be set.
|
||||
ssize_t
|
||||
uio_resolvePath(uio_DirHandle *dirHandle, const char *path, size_t pathLen,
|
||||
char **destPath) {
|
||||
size_t len;
|
||||
const char *pathEnd, *start, *end;
|
||||
int numUp; // number of ".." dirs still need to be matched.
|
||||
char *buffer;
|
||||
char *endBufPtr;
|
||||
uio_bool absolute;
|
||||
|
||||
absolute = path[0] == '/';
|
||||
pathEnd = path + pathLen;
|
||||
|
||||
// Pass 1: count the amount of space needed
|
||||
len = 0;
|
||||
numUp = 0;
|
||||
for (getLastPathComponent(path, pathEnd, &start, &end);
|
||||
end > path;
|
||||
getPreviousPathComponent(path, &start, &end)) {
|
||||
if (start[0] == '.') {
|
||||
if (start + 1 == end) {
|
||||
// "." matched
|
||||
continue;
|
||||
}
|
||||
if (start[1] == '.' && start + 2 == end) {
|
||||
// ".." matched
|
||||
numUp++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (numUp > 0) {
|
||||
// last 'numUp' components were ".."
|
||||
numUp--;
|
||||
continue;
|
||||
}
|
||||
len += (end - start) + 1;
|
||||
// the 1 is for the '/'
|
||||
}
|
||||
|
||||
// The part from 'dirHandle->path' to 'dirHandle->rootEnd' is
|
||||
// always copied (for a valid path). The rest we'll have to count.
|
||||
// (Note the 'rootEnd' in the initialiser of the for loop.)
|
||||
len += (dirHandle->rootEnd - dirHandle->path);
|
||||
if (!absolute) {
|
||||
for (getLastPath0Component(dirHandle->rootEnd, &start, &end);
|
||||
end > dirHandle->rootEnd;
|
||||
getPreviousPath0Component(dirHandle->rootEnd, &start, &end)) {
|
||||
if (numUp > 0) {
|
||||
numUp--;
|
||||
continue;
|
||||
}
|
||||
len += (end - start) + 1;
|
||||
// the 1 is for the '/'
|
||||
}
|
||||
}
|
||||
if (numUp > 0) {
|
||||
// too many ".."
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
*destPath = uio_malloc(1);
|
||||
(*destPath)[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// len--; // we don't want a '/' at the start
|
||||
// len++; // for the terminating '\0'
|
||||
buffer = uio_malloc(len);
|
||||
|
||||
// Pass 2: fill the buffer
|
||||
endBufPtr = buffer + len - 1;
|
||||
*endBufPtr = '\0';
|
||||
numUp = 0;
|
||||
for (getLastPathComponent(path, pathEnd, &start, &end);
|
||||
end > path;
|
||||
getPreviousPathComponent(path, &start, &end)) {
|
||||
if (start[0] == '.') {
|
||||
if (start + 1 == end) {
|
||||
// "." matched
|
||||
continue;
|
||||
}
|
||||
if (start[1] == '.' && start + 2 == end) {
|
||||
// ".." matched
|
||||
numUp++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (numUp > 0) {
|
||||
// last 'numUp' components were ".."
|
||||
numUp--;
|
||||
continue;
|
||||
}
|
||||
endBufPtr -= (end - start);
|
||||
memcpy(endBufPtr, start, end - start);
|
||||
if (endBufPtr != buffer) {
|
||||
// We want no '/' at the beginning
|
||||
endBufPtr--;
|
||||
*endBufPtr = '/';
|
||||
} else {
|
||||
// We're already done. Might as well take advantage of
|
||||
// the fact that we know that and exit immediatly:
|
||||
*destPath = buffer;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
// copy the part from dirHandle->path to dirHandle->rootEnd
|
||||
endBufPtr -= (dirHandle->rootEnd - dirHandle->path);
|
||||
memcpy(endBufPtr, dirHandle->path, dirHandle->rootEnd - dirHandle->path);
|
||||
if (!absolute) {
|
||||
// copy (some of) the components from dirHandle->rootEnd on.
|
||||
for (getLastPath0Component(dirHandle->rootEnd, &start, &end);
|
||||
end > dirHandle->rootEnd;
|
||||
getPreviousPath0Component(dirHandle->rootEnd, &start, &end)) {
|
||||
if (numUp > 0) {
|
||||
numUp--;
|
||||
continue;
|
||||
}
|
||||
endBufPtr -= (end - start);
|
||||
memcpy(endBufPtr, start, end - start);
|
||||
if (endBufPtr != buffer) {
|
||||
// We want no '/' at the beginning
|
||||
endBufPtr--;
|
||||
*endBufPtr = '/';
|
||||
} else {
|
||||
// We're already done. Might as well take advantage of
|
||||
// the fact that we know that and exit immediatly:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*destPath = buffer;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IOAUX_H
|
||||
#define _IOAUX_H
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "physical.h"
|
||||
#include "uioport.h"
|
||||
|
||||
int uio_walkPhysicalPath(uio_PDirHandle *startPDirHandle, const char *path,
|
||||
size_t pathLen, uio_PDirHandle **endPDirHandle,
|
||||
const char **pathRest);
|
||||
uio_PDirHandle *uio_makePath(uio_PDirHandle *pDirHandle, const char *path,
|
||||
size_t pathLen, mode_t mode);
|
||||
int uio_copyFilePhysical(uio_PDirHandle *fromDir, const char *fromName,
|
||||
uio_PDirHandle *toDir, const char *toName);
|
||||
int uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path,
|
||||
int flags, uio_MountInfo **mountInfoReadPtr,
|
||||
uio_PDirHandle **readPDirHandlePtr, uio_MountInfo **mountInfoWritePtr,
|
||||
uio_PDirHandle **writePDirHandlePtr, char **restPtr);
|
||||
int uio_getPathPhysicalDirs(uio_DirHandle *dirHandle, const char *path,
|
||||
size_t pathLen, uio_PDirHandle ***resPDirHandles,
|
||||
int *resNumPDirHandles, uio_MountTreeItem ***resItems);
|
||||
int uio_verifyPath(uio_DirHandle *dirHandle, const char *path,
|
||||
char **resolvedPath);
|
||||
ssize_t uio_resolvePath(uio_DirHandle *dirHandle, const char *path,
|
||||
size_t pathLen, char **destPath);
|
||||
|
||||
|
||||
#endif /* _IOAUX_H */
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IOINTERN_H
|
||||
#define _IOINTERN_H
|
||||
|
||||
#define uio_INTERNAL
|
||||
|
||||
typedef struct uio_PDirEntryHandle uio_PDirEntryHandle;
|
||||
typedef struct uio_PDirHandle uio_PDirHandle;
|
||||
typedef struct uio_PFileHandle uio_PFileHandle;
|
||||
typedef struct uio_EntriesContext uio_EntriesContext;
|
||||
|
||||
#ifndef uio_INTERNAL_PHYSICAL
|
||||
typedef void *uio_PDirHandleExtra;
|
||||
typedef void *uio_PFileHandleExtra;
|
||||
#endif
|
||||
|
||||
#include "io.h"
|
||||
#include "uioport.h"
|
||||
#include "physical.h"
|
||||
#include "mount.h"
|
||||
#include "mounttree.h"
|
||||
#include "match.h"
|
||||
#include "mem.h"
|
||||
|
||||
struct uio_Handle {
|
||||
int ref;
|
||||
struct uio_PRoot *root;
|
||||
uio_NativeHandle native;
|
||||
int openFlags;
|
||||
// need to know whether the handle is a RO or RW handle.
|
||||
};
|
||||
|
||||
struct uio_DirHandle {
|
||||
struct uio_Repository *repository;
|
||||
char *path;
|
||||
// does not contain any '.' or '..'
|
||||
char *rootEnd;
|
||||
// points to the end of the part of path that is considered
|
||||
// the root dir. (you can't use '..' to get above the root dir)
|
||||
};
|
||||
|
||||
struct uio_MountHandle {
|
||||
struct uio_Repository *repository;
|
||||
struct uio_MountInfo *mountInfo;
|
||||
};
|
||||
|
||||
struct uio_DirList {
|
||||
const char **names;
|
||||
int numNames;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
|
||||
#define uio_PHandle_COMMON \
|
||||
int flags; \
|
||||
int ref; \
|
||||
uio_PRoot *pRoot;
|
||||
|
||||
#define uio_PDirEntryHandle_TYPE_REG 0x0000
|
||||
#define uio_PDirEntryHandle_TYPE_DIR 0x0001
|
||||
#define uio_PDirEntryHandle_TYPEMASK 0x0001
|
||||
|
||||
struct uio_PDirEntryHandle {
|
||||
uio_PHandle_COMMON
|
||||
};
|
||||
|
||||
struct uio_PDirHandle {
|
||||
uio_PHandle_COMMON
|
||||
uio_PDirHandleExtra extra;
|
||||
};
|
||||
|
||||
struct uio_PFileHandle {
|
||||
uio_PHandle_COMMON
|
||||
uio_PFileHandleExtra extra;
|
||||
};
|
||||
|
||||
struct uio_EntriesContext {
|
||||
uio_PRoot *pRoot;
|
||||
uio_NativeEntriesContext native;
|
||||
};
|
||||
|
||||
|
||||
uio_Handle *uio_Handle_new(uio_PRoot *root, uio_NativeHandle native,
|
||||
int openFlags);
|
||||
void uio_Handle_delete(uio_Handle *handle);
|
||||
|
||||
uio_PDirEntryHandle *uio_getPDirEntryHandle(
|
||||
const uio_PDirHandle *dirHandle, const char *name);
|
||||
void uio_PDirHandle_deletePDirHandleExtra(uio_PDirHandle *pDirHandle);
|
||||
void uio_PFileHandle_deletePFileHandleExtra(uio_PFileHandle *pFileHandle);
|
||||
|
||||
uio_PDirHandle *uio_PDirHandle_new(uio_PRoot *pRoot,
|
||||
uio_PDirHandleExtra extra);
|
||||
uio_PFileHandle *uio_PFileHandle_new(uio_PRoot *pRoot,
|
||||
uio_PFileHandleExtra extra);
|
||||
void uio_PDirEntryHandle_delete(uio_PDirEntryHandle *pDirEntryHandle);
|
||||
void uio_PDirHandle_delete(uio_PDirHandle *pDirHandle);
|
||||
void uio_PFileHandle_delete(uio_PFileHandle *pFileHandle);
|
||||
|
||||
|
||||
static inline void
|
||||
uio_Handle_ref(uio_Handle *handle) {
|
||||
handle->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_Handle_unref(uio_Handle *handle) {
|
||||
assert(handle->ref > 0);
|
||||
handle->ref--;
|
||||
if (handle->ref == 0)
|
||||
uio_Handle_delete(handle);
|
||||
}
|
||||
|
||||
static inline uio_bool
|
||||
uio_PDirEntryHandle_isDir(const uio_PDirEntryHandle *handle) {
|
||||
return (handle->flags & uio_PDirEntryHandle_TYPEMASK) ==
|
||||
uio_PDirEntryHandle_TYPE_DIR;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PDirEntryHandle_ref(uio_PDirEntryHandle *handle) {
|
||||
handle->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PDirEntryHandle_unref(uio_PDirEntryHandle *handle) {
|
||||
assert(handle->ref > 0);
|
||||
handle->ref--;
|
||||
if (handle->ref == 0)
|
||||
uio_PDirEntryHandle_delete(handle);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PDirHandle_ref(uio_PDirHandle *handle) {
|
||||
handle->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PDirHandle_unref(uio_PDirHandle *handle) {
|
||||
assert(handle->ref > 0);
|
||||
handle->ref--;
|
||||
if (handle->ref == 0)
|
||||
uio_PDirHandle_delete(handle);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PFileHandle_ref(uio_PFileHandle *handle) {
|
||||
handle->ref++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PFileHandle_unref(uio_PFileHandle *handle) {
|
||||
assert(handle->ref > 0);
|
||||
handle->ref--;
|
||||
if (handle->ref == 0)
|
||||
uio_PFileHandle_delete(handle);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _IOINTERN_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,546 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "match.h"
|
||||
#include "mem.h"
|
||||
#include "uioport.h"
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
# include <fnmatch.h>
|
||||
#endif
|
||||
|
||||
|
||||
static inline match_MatchContext *match_allocMatchContext(void);
|
||||
static inline void match_freeMatchContext(match_MatchContext *context);
|
||||
|
||||
static inline match_LitteralContext *match_newLitteralContext(char *pattern);
|
||||
static inline match_LitteralContext *match_allocLitteralContext(void);
|
||||
static inline void match_freeLitteralContext(match_LitteralContext *context);
|
||||
static inline match_PrefixContext *match_newPrefixContext(char *pattern);
|
||||
static inline match_PrefixContext *match_allocPrefixContext(void);
|
||||
static inline void match_freePrefixContext(match_PrefixContext *context);
|
||||
static inline match_SuffixContext *match_newSuffixContext(
|
||||
char *pattern, size_t len);
|
||||
static inline match_SuffixContext *match_allocSuffixContext(void);
|
||||
static inline void match_freeSuffixContext(match_SuffixContext *context);
|
||||
static inline match_SubStringContext *match_newSubStringContext(
|
||||
char *pattern);
|
||||
static inline match_SubStringContext *match_allocSubStringContext(void);
|
||||
static inline void match_freeSubStringContext(match_SubStringContext *context);
|
||||
#ifdef HAVE_GLOB
|
||||
static inline match_GlobContext *match_newGlobContext(char *pattern);
|
||||
static inline match_GlobContext *match_allocGlobContext(void);
|
||||
static inline void match_freeGlobContext(match_GlobContext *context);
|
||||
#endif /* HAVE_GLOB */
|
||||
#ifdef HAVE_REGEX
|
||||
static inline match_RegexContext *match_newRegexContext(void);
|
||||
static inline match_RegexContext *match_allocRegexContext(void);
|
||||
static inline void match_freeRegexContext(match_RegexContext *context);
|
||||
#endif /* HAVE_REGEX */
|
||||
|
||||
|
||||
// *** General part ***
|
||||
|
||||
// NB: Even if this function fails, *contextPtr contains a context
|
||||
// which needs to be freed.
|
||||
match_Result
|
||||
match_prepareContext(const char *pattern, match_MatchContext **contextPtr,
|
||||
match_MatchType type) {
|
||||
match_Result result;
|
||||
|
||||
*contextPtr = match_allocMatchContext();
|
||||
(*contextPtr)->type = type;
|
||||
switch (type) {
|
||||
case match_MATCH_LITTERAL:
|
||||
result = match_prepareLitteral(pattern,
|
||||
&(*contextPtr)->u.litteral);
|
||||
break;
|
||||
case match_MATCH_PREFIX:
|
||||
result = match_preparePrefix(pattern, &(*contextPtr)->u.prefix);
|
||||
break;
|
||||
case match_MATCH_SUFFIX:
|
||||
result = match_prepareSuffix(pattern, &(*contextPtr)->u.suffix);
|
||||
break;
|
||||
case match_MATCH_SUBSTRING:
|
||||
result = match_prepareSubString(pattern,
|
||||
&(*contextPtr)->u.subString);
|
||||
break;
|
||||
#ifdef HAVE_GLOB
|
||||
case match_MATCH_GLOB:
|
||||
result = match_prepareGlob(pattern, &(*contextPtr)->u.glob);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
case match_MATCH_REGEX:
|
||||
result = match_prepareRegex(pattern, &(*contextPtr)->u.regex);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "match_prepareContext called with unsupported "
|
||||
"type %d matching.\n", type);
|
||||
#endif
|
||||
return match_ENOSYS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchPattern(match_MatchContext *context, const char *string) {
|
||||
switch (context->type) {
|
||||
case match_MATCH_LITTERAL:
|
||||
return match_matchLitteral(context->u.litteral, string);
|
||||
case match_MATCH_PREFIX:
|
||||
return match_matchPrefix(context->u.prefix, string);
|
||||
case match_MATCH_SUFFIX:
|
||||
return match_matchSuffix(context->u.suffix, string);
|
||||
case match_MATCH_SUBSTRING:
|
||||
return match_matchSubString(context->u.subString, string);
|
||||
#ifdef HAVE_GLOB
|
||||
case match_MATCH_GLOB:
|
||||
return match_matchGlob(context->u.glob, string);
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
case match_MATCH_REGEX:
|
||||
return match_matchRegex(context->u.regex, string);
|
||||
#endif
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
match_errorString(match_MatchContext *context, match_Result result) {
|
||||
switch (result) {
|
||||
case match_OK:
|
||||
case match_MATCH:
|
||||
// case match_NOMATCH: // same value as match_OK
|
||||
return "Success";
|
||||
case match_ENOSYS:
|
||||
return "Not implemented";
|
||||
case match_ENOTINIT:
|
||||
return "Uninitialised use";
|
||||
case match_ECUSTOM:
|
||||
// Depends on match type.
|
||||
break;
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
switch (context->type) {
|
||||
#if 0
|
||||
case match_MATCH_LITTERAL:
|
||||
return match_errorStringLitteral(context->u.litteral, result);
|
||||
case match_MATCH_PREFIX:
|
||||
return match_errorStringPrefix(context->u.prefix, result);
|
||||
case match_MATCH_SUFFIX:
|
||||
return match_errorStringSuffix(context->u.suffix, result);
|
||||
case match_MATCH_SUBSTRING:
|
||||
return match_errorStringSubString(context->u.subString, result);
|
||||
#ifdef HAVE_GLOB
|
||||
case match_MATCH_GLOB:
|
||||
return match_errorStringGlob(context->u.glob, result);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
case match_MATCH_REGEX:
|
||||
return match_errorStringRegex(context->u.regex, result);
|
||||
#endif
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
match_freeContext(match_MatchContext *context) {
|
||||
switch (context->type) {
|
||||
case match_MATCH_LITTERAL:
|
||||
match_freeLitteral(context->u.litteral);
|
||||
break;
|
||||
case match_MATCH_PREFIX:
|
||||
match_freePrefix(context->u.prefix);
|
||||
break;
|
||||
case match_MATCH_SUFFIX:
|
||||
match_freeSuffix(context->u.suffix);
|
||||
break;
|
||||
case match_MATCH_SUBSTRING:
|
||||
match_freeSubString(context->u.subString);
|
||||
break;
|
||||
#ifdef HAVE_GLOB
|
||||
case match_MATCH_GLOB:
|
||||
match_freeGlob(context->u.glob);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
case match_MATCH_REGEX:
|
||||
match_freeRegex(context->u.regex);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
match_freeMatchContext(context);
|
||||
}
|
||||
|
||||
static inline match_MatchContext *
|
||||
match_allocMatchContext(void) {
|
||||
return uio_malloc(sizeof (match_MatchContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freeMatchContext(match_MatchContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
|
||||
|
||||
// *** Litteral part ***
|
||||
|
||||
match_Result
|
||||
match_prepareLitteral(const char *pattern,
|
||||
match_LitteralContext **contextPtr) {
|
||||
*contextPtr = match_newLitteralContext(uio_strdup(pattern));
|
||||
return match_OK;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchLitteral(match_LitteralContext *context, const char *string) {
|
||||
return (strcmp(context->pattern, string) == 0) ?
|
||||
match_MATCH : match_NOMATCH;
|
||||
}
|
||||
|
||||
void
|
||||
match_freeLitteral(match_LitteralContext *context) {
|
||||
uio_free(context->pattern);
|
||||
match_freeLitteralContext(context);
|
||||
}
|
||||
|
||||
static inline match_LitteralContext *
|
||||
match_newLitteralContext(char *pattern) {
|
||||
match_LitteralContext *result;
|
||||
|
||||
result = match_allocLitteralContext();
|
||||
result->pattern = pattern;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline match_LitteralContext *
|
||||
match_allocLitteralContext(void) {
|
||||
return uio_malloc(sizeof (match_LitteralContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freeLitteralContext(match_LitteralContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
|
||||
|
||||
// *** Prefix part ***
|
||||
|
||||
match_Result
|
||||
match_preparePrefix(const char *pattern,
|
||||
match_PrefixContext **contextPtr) {
|
||||
*contextPtr = match_newPrefixContext(uio_strdup(pattern));
|
||||
return match_OK;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchPrefix(match_PrefixContext *context, const char *string) {
|
||||
char *patPtr;
|
||||
|
||||
patPtr = context->pattern;
|
||||
while (1) {
|
||||
if (*patPtr == '\0') {
|
||||
// prefix has completely matched
|
||||
return match_MATCH;
|
||||
}
|
||||
if (*string == '\0') {
|
||||
// no more string left, and still prefix to match
|
||||
return match_NOMATCH;
|
||||
}
|
||||
if (*patPtr != *string)
|
||||
return match_NOMATCH;
|
||||
patPtr++;
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
match_freePrefix(match_PrefixContext *context) {
|
||||
uio_free(context->pattern);
|
||||
match_freePrefixContext(context);
|
||||
}
|
||||
|
||||
static inline match_PrefixContext *
|
||||
match_newPrefixContext(char *pattern) {
|
||||
match_PrefixContext *result;
|
||||
|
||||
result = match_allocPrefixContext();
|
||||
result->pattern = pattern;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline match_PrefixContext *
|
||||
match_allocPrefixContext(void) {
|
||||
return uio_malloc(sizeof (match_PrefixContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freePrefixContext(match_PrefixContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
|
||||
|
||||
// *** Suffix part ***
|
||||
|
||||
match_Result
|
||||
match_prepareSuffix(const char *pattern,
|
||||
match_SuffixContext **contextPtr) {
|
||||
*contextPtr = match_newSuffixContext(
|
||||
uio_strdup(pattern), strlen(pattern));
|
||||
return match_OK;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchSuffix(match_SuffixContext *context, const char *string) {
|
||||
size_t stringLen;
|
||||
|
||||
stringLen = strlen(string);
|
||||
if (stringLen < context->len) {
|
||||
// Supplied suffix is larger than string
|
||||
return match_NOMATCH;
|
||||
}
|
||||
|
||||
return memcmp(string + stringLen - context->len, context->pattern,
|
||||
context->len) == 0 ? match_MATCH : match_NOMATCH;
|
||||
}
|
||||
|
||||
void
|
||||
match_freeSuffix(match_SuffixContext *context) {
|
||||
uio_free(context->pattern);
|
||||
match_freeSuffixContext(context);
|
||||
}
|
||||
|
||||
static inline match_SuffixContext *
|
||||
match_newSuffixContext(char *pattern, size_t len) {
|
||||
match_SuffixContext *result;
|
||||
|
||||
result = match_allocSuffixContext();
|
||||
result->pattern = pattern;
|
||||
result->len = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline match_SuffixContext *
|
||||
match_allocSuffixContext(void) {
|
||||
return uio_malloc(sizeof (match_SuffixContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freeSuffixContext(match_SuffixContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
|
||||
|
||||
// *** SubString part ***
|
||||
|
||||
match_Result
|
||||
match_prepareSubString(const char *pattern,
|
||||
match_SubStringContext **contextPtr) {
|
||||
*contextPtr = match_newSubStringContext(uio_strdup(pattern));
|
||||
return match_OK;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchSubString(match_SubStringContext *context, const char *string) {
|
||||
return strstr(string, context->pattern) != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
match_freeSubString(match_SubStringContext *context) {
|
||||
uio_free(context->pattern);
|
||||
match_freeSubStringContext(context);
|
||||
}
|
||||
|
||||
static inline match_SubStringContext *
|
||||
match_newSubStringContext(char *pattern) {
|
||||
match_SubStringContext *result;
|
||||
|
||||
result = match_allocSubStringContext();
|
||||
result->pattern = pattern;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline match_SubStringContext *
|
||||
match_allocSubStringContext(void) {
|
||||
return uio_malloc(sizeof (match_SubStringContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freeSubStringContext(match_SubStringContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
|
||||
|
||||
// *** Glob part ***
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
match_Result
|
||||
match_prepareGlob(const char *pattern, match_GlobContext **contextPtr) {
|
||||
*contextPtr = match_newGlobContext(uio_strdup(pattern));
|
||||
return match_OK;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchGlob(match_GlobContext *context, const char *string) {
|
||||
int retval;
|
||||
|
||||
retval = fnmatch(context->pattern, string, 0);
|
||||
switch (retval) {
|
||||
case 0:
|
||||
return match_MATCH;
|
||||
case FNM_NOMATCH:
|
||||
return match_NOMATCH;
|
||||
#if 0
|
||||
case FNM_NOSYS:
|
||||
return match_ENOSYS;
|
||||
#endif
|
||||
default:
|
||||
return match_EUNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
match_freeGlob(match_GlobContext *context) {
|
||||
uio_free(context->pattern);
|
||||
match_freeGlobContext(context);
|
||||
}
|
||||
|
||||
static inline match_GlobContext *
|
||||
match_newGlobContext(char *pattern) {
|
||||
match_GlobContext *result;
|
||||
|
||||
result = match_allocGlobContext();
|
||||
result->pattern = pattern;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline match_GlobContext *
|
||||
match_allocGlobContext(void) {
|
||||
return uio_malloc(sizeof (match_GlobContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freeGlobContext(match_GlobContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
#endif /* HAVE_GLOB */
|
||||
|
||||
|
||||
// *** Regex part ***
|
||||
|
||||
#ifdef HAVE_REGEX
|
||||
match_Result
|
||||
match_prepareRegex(const char *pattern, match_RegexContext **contextPtr) {
|
||||
*contextPtr = match_newRegexContext();
|
||||
(*contextPtr)->errorCode = regcomp(&(*contextPtr)->native, pattern,
|
||||
REG_EXTENDED | REG_NOSUB);
|
||||
if ((*contextPtr)->errorCode == 0) {
|
||||
(*contextPtr)->flags = match_REGEX_INITIALISED;
|
||||
return match_OK;
|
||||
}
|
||||
return match_ECUSTOM;
|
||||
}
|
||||
|
||||
match_Result
|
||||
match_matchRegex(match_RegexContext *context, const char *string) {
|
||||
int retval;
|
||||
|
||||
if ((context->flags & match_REGEX_INITIALISED) !=
|
||||
match_REGEX_INITIALISED) {
|
||||
return match_ENOTINIT;
|
||||
}
|
||||
if (context->errorString) {
|
||||
uio_free(context->errorString);
|
||||
context->errorString = NULL;
|
||||
}
|
||||
retval = regexec(&context->native, string, 0, NULL, 0);
|
||||
switch (retval) {
|
||||
case 0:
|
||||
return match_MATCH;
|
||||
case REG_NOMATCH:
|
||||
return match_NOMATCH;
|
||||
default:
|
||||
context->errorCode = retval;
|
||||
return match_ECUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
match_errorStringRegex(match_RegexContext *context, int errorCode) {
|
||||
size_t errorStringLength;
|
||||
|
||||
if (context->errorString != NULL)
|
||||
uio_free(context->errorString);
|
||||
|
||||
errorStringLength = regerror(context->errorCode, &context->native,
|
||||
NULL, 0);
|
||||
context->errorString = uio_malloc(errorStringLength);
|
||||
regerror(context->errorCode, &context->native,
|
||||
context->errorString, errorStringLength);
|
||||
|
||||
(void) errorCode;
|
||||
return context->errorString;
|
||||
}
|
||||
|
||||
void
|
||||
match_freeRegex(match_RegexContext *context) {
|
||||
regfree(&context->native);
|
||||
if (context->errorString)
|
||||
uio_free(context->errorString);
|
||||
match_freeRegexContext(context);
|
||||
}
|
||||
|
||||
static inline match_RegexContext *
|
||||
match_newRegexContext(void) {
|
||||
match_RegexContext *result;
|
||||
result = match_allocRegexContext();
|
||||
result->errorString = NULL;
|
||||
result->errorCode = 0;
|
||||
result->flags = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline match_RegexContext *
|
||||
match_allocRegexContext(void) {
|
||||
return uio_malloc(sizeof (match_RegexContext));
|
||||
}
|
||||
|
||||
static inline void
|
||||
match_freeRegexContext(match_RegexContext *context) {
|
||||
uio_free(context);
|
||||
}
|
||||
#endif /* HAVE_REGEX */
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MATCH_H
|
||||
#define _MATCH_H
|
||||
|
||||
typedef struct match_MatchContext match_MatchContext;
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
// TODO: make this into a configurable option
|
||||
//#define HAVE_REGEX
|
||||
//#define HAVE_GLOB
|
||||
|
||||
|
||||
typedef enum {
|
||||
match_MATCH_LITTERAL = 0,
|
||||
match_MATCH_PREFIX,
|
||||
match_MATCH_SUFFIX,
|
||||
match_MATCH_SUBSTRING,
|
||||
#ifdef HAVE_GLOB
|
||||
match_MATCH_GLOB,
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
match_MATCH_REGEX,
|
||||
#endif
|
||||
} match_MatchType;
|
||||
|
||||
typedef int match_Result;
|
||||
#define match_NOMATCH 0
|
||||
#define match_MATCH 1
|
||||
#define match_OK 0
|
||||
#define match_EUNKNOWN -1
|
||||
#define match_ENOSYS -2
|
||||
#define match_ECUSTOM -3
|
||||
#define match_ENOTINIT -4
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_REGEX
|
||||
# include <regex.h>
|
||||
#endif
|
||||
|
||||
typedef struct match_LitteralContext match_LitteralContext;
|
||||
typedef struct match_PrefixContext match_PrefixContext;
|
||||
typedef struct match_SuffixContext match_SuffixContext;
|
||||
typedef struct match_SubStringContext match_SubStringContext;
|
||||
#ifdef HAVE_GLOB
|
||||
typedef struct match_GlobContext match_GlobContext;
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
typedef struct match_RegexContext match_RegexContext;
|
||||
#endif
|
||||
|
||||
match_Result match_prepareContext(const char *pattern,
|
||||
match_MatchContext **contextPtr, match_MatchType type);
|
||||
match_Result match_matchPattern(match_MatchContext *context,
|
||||
const char *string);
|
||||
const char *match_errorString(match_MatchContext *context,
|
||||
match_Result result);
|
||||
void match_freeContext(match_MatchContext *context);
|
||||
|
||||
|
||||
/* *** Internal definitions follow *** */
|
||||
#ifdef uio_INTERNAL
|
||||
|
||||
#include "uioport.h"
|
||||
|
||||
struct match_MatchContext {
|
||||
match_MatchType type;
|
||||
union {
|
||||
match_LitteralContext *litteral;
|
||||
match_PrefixContext *prefix;
|
||||
match_SuffixContext *suffix;
|
||||
match_SubStringContext *subString;
|
||||
#ifdef HAVE_GLOB
|
||||
match_GlobContext *glob;
|
||||
#endif
|
||||
#ifdef HAVE_REGEX
|
||||
match_RegexContext *regex;
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
struct match_LitteralContext {
|
||||
char *pattern;
|
||||
};
|
||||
|
||||
struct match_PrefixContext {
|
||||
char *pattern;
|
||||
};
|
||||
|
||||
struct match_SuffixContext {
|
||||
char *pattern;
|
||||
size_t len;
|
||||
// for speed
|
||||
};
|
||||
|
||||
struct match_SubStringContext {
|
||||
char *pattern;
|
||||
};
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
struct match_GlobContext {
|
||||
char *pattern;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REGEX
|
||||
struct match_RegexContext {
|
||||
regex_t native;
|
||||
char *errorString;
|
||||
int errorCode;
|
||||
int flags;
|
||||
#define match_REGEX_INITIALISED 1
|
||||
};
|
||||
#endif
|
||||
|
||||
match_Result match_prepareLitteral(const char *pattern,
|
||||
match_LitteralContext **contextPtr);
|
||||
match_Result match_matchLitteral(match_LitteralContext *context,
|
||||
const char *string);
|
||||
void match_freeLitteral(match_LitteralContext *context);
|
||||
|
||||
match_Result match_preparePrefix(const char *pattern,
|
||||
match_PrefixContext **contextPtr);
|
||||
match_Result match_matchPrefix(match_PrefixContext *context,
|
||||
const char *string);
|
||||
void match_freePrefix(match_PrefixContext *context);
|
||||
|
||||
match_Result match_prepareSuffix(const char *pattern,
|
||||
match_SuffixContext **contextPtr);
|
||||
match_Result match_matchSuffix(match_SuffixContext *context,
|
||||
const char *string);
|
||||
void match_freeSuffix(match_SuffixContext *context);
|
||||
|
||||
match_Result match_prepareSubString(const char *pattern,
|
||||
match_SubStringContext **contextPtr);
|
||||
match_Result match_matchSubString(match_SubStringContext *context,
|
||||
const char *string);
|
||||
void match_freeSubString(match_SubStringContext *context);
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
match_Result match_prepareGlob(const char *pattern,
|
||||
match_GlobContext **contextPtr);
|
||||
match_Result match_matchGlob(match_GlobContext *context,
|
||||
const char *string);
|
||||
void match_freeGlob(match_GlobContext *context);
|
||||
#endif /* HAVE_GLOB */
|
||||
|
||||
#ifdef HAVE_REGEX
|
||||
match_Result match_prepareRegex(const char *pattern,
|
||||
match_RegexContext **contextPtr);
|
||||
match_Result match_matchRegex(match_RegexContext *context,
|
||||
const char *string);
|
||||
const char *match_errorStringRegex(match_RegexContext *context,
|
||||
int errorCode);
|
||||
void match_freeRegex(match_RegexContext *context);
|
||||
#endif
|
||||
|
||||
#endif /* uio_INTERNAL */
|
||||
|
||||
#endif /* _MATCH_H */
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MEM_H
|
||||
#define _MEM_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
# include <malloc.h>
|
||||
# define alloca _alloca
|
||||
#elif defined (__linux__)
|
||||
# include <alloca.h>
|
||||
#endif
|
||||
#include "uioport.h"
|
||||
|
||||
#define uio_malloc malloc
|
||||
#define uio_realloc realloc
|
||||
#define uio_free free
|
||||
#define uio_calloc calloc
|
||||
#define uio_alloca alloca
|
||||
|
||||
#ifdef uio_MEM_DEBUG
|
||||
// When uio_strdup is defined to the libc strdup, there's no opportunity
|
||||
// to intercept the alloc. Hence this function here.
|
||||
static inline char *
|
||||
uio_strdup(const char *s) {
|
||||
char *result;
|
||||
size_t size;
|
||||
|
||||
size = strlen(s) + 1;
|
||||
result = uio_malloc(size);
|
||||
memcpy(result, s, size);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
# define uio_strdup strdup
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "memdebug.h"
|
||||
#include "hashtable.h"
|
||||
#include "mem.h"
|
||||
#include "uioutils.h"
|
||||
#include "types.h"
|
||||
#include "uioport.h"
|
||||
|
||||
// I'm intentionally not including the .h files. It would only make things
|
||||
// messy, because the second arguments would be other pointers, which
|
||||
// would require typecasts of the functions in uio_MemDebug_logTypeInfo.
|
||||
extern void uio_DirHandle_print(FILE *out, const void *);
|
||||
extern void uio_printMountInfo(FILE *out, const void *);
|
||||
extern void uio_printMountTreeItem(FILE *out, const void *);
|
||||
extern void uio_printPathComp(FILE *out, const void *);
|
||||
|
||||
// Must be in the same order as in uio_MemDebug_LogTypes
|
||||
// Change the third field to have debug info printed for specific actions.
|
||||
// See memdebug.h file the possible values.
|
||||
const uio_MemDebug_LogTypeInfo uio_MemDebug_logTypeInfo[] = {
|
||||
{ "uio_DirHandle", uio_DirHandle_print, 0 },
|
||||
{ "uio_FileSystemInfo", NULL, 0 },
|
||||
{ "uio_GPDir", NULL, 0 },
|
||||
{ "uio_GPFile", NULL, 0 },
|
||||
{ "uio_GPRoot", NULL, 0 },
|
||||
{ "uio_Handle", NULL, 0 },
|
||||
{ "uio_MountHandle", NULL, 0 },
|
||||
{ "uio_MountInfo", uio_printMountInfo, 0 },
|
||||
{ "uio_MountTree", NULL, 0 },
|
||||
{ "uio_MountTreeItem", uio_printMountTreeItem, 0 },
|
||||
{ "uio_PathComp", uio_printPathComp, 0 },
|
||||
{ "uio_PFileHandle", NULL, 0 },
|
||||
{ "uio_PDirHandle", NULL, 0 },
|
||||
{ "uio_PRoot", NULL, 0 },
|
||||
{ "uio_Repository", NULL, 0 },
|
||||
{ "uio_Stream", NULL, 0 },
|
||||
{ "stdio_GPDirData", NULL, 0 },
|
||||
#ifdef HAVE_ZIP
|
||||
{ "zip_GPFileData", NULL, 0 },
|
||||
#endif
|
||||
};
|
||||
|
||||
HashTable_HashTable **uio_MemDebug_logs;
|
||||
|
||||
|
||||
static uio_uint32 uio_MemDebug_pointerHash(const void *ptr);
|
||||
static uio_bool uio_MemDebug_pointerCompare(const void *ptr1, const void *ptr2);
|
||||
static void *uio_MemDebug_pointerCopy(const void *ptr);
|
||||
static void uio_MemDebug_pointerFree(void *ptr);
|
||||
|
||||
static inline uio_MemDebug_PointerInfo *uio_MemDebug_PointerInfo_new(int ref);
|
||||
static inline void uio_MemDebug_PointerInfo_delete(
|
||||
uio_MemDebug_PointerInfo *pointerInfo);
|
||||
static inline uio_MemDebug_PointerInfo *uio_MemDebug_PointerInfo_alloc(void);
|
||||
static inline void uio_MemDebug_PointerInfo_free(
|
||||
uio_MemDebug_PointerInfo *pointerInfo);
|
||||
|
||||
void
|
||||
uio_MemDebug_init(void) {
|
||||
int i;
|
||||
|
||||
assert((int) uio_MemDebug_numLogTypes ==
|
||||
(sizeof uio_MemDebug_logTypeInfo /
|
||||
sizeof uio_MemDebug_logTypeInfo[0]));
|
||||
uio_MemDebug_logs = uio_malloc(uio_MemDebug_numLogTypes *
|
||||
sizeof (HashTable_HashTable *));
|
||||
|
||||
for (i = 0; i < uio_MemDebug_numLogTypes; i++) {
|
||||
uio_MemDebug_logs[i] = HashTable_newHashTable(
|
||||
uio_MemDebug_pointerHash,
|
||||
uio_MemDebug_pointerCompare,
|
||||
uio_MemDebug_pointerCopy,
|
||||
uio_MemDebug_pointerFree,
|
||||
4, 0.85, 0.90);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_unInit(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uio_MemDebug_numLogTypes; i++)
|
||||
HashTable_deleteHashTable(uio_MemDebug_logs[i]);
|
||||
|
||||
uio_free(uio_MemDebug_logs);
|
||||
}
|
||||
|
||||
static uio_uint32
|
||||
uio_MemDebug_pointerHash(const void *ptr) {
|
||||
uio_uintptr ptrInt;
|
||||
|
||||
ptrInt = (uio_uintptr) ptr;
|
||||
return (uio_uint32) (ptrInt ^ (ptrInt >> 10) ^ (ptrInt >> 20));
|
||||
}
|
||||
|
||||
static uio_bool
|
||||
uio_MemDebug_pointerCompare(const void *ptr1, const void *ptr2) {
|
||||
return ptr1 == ptr2;
|
||||
}
|
||||
|
||||
static void *
|
||||
uio_MemDebug_pointerCopy(const void *ptr) {
|
||||
return unconst(ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
uio_MemDebug_pointerFree(void *ptr) {
|
||||
(void) ptr;
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_logAllocation(uio_MemDebug_LogType type, void *ptr) {
|
||||
uio_MemDebug_PointerInfo *pointerInfo;
|
||||
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Fatal: Allocated pointer is (%s *) NULL.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name);
|
||||
abort();
|
||||
}
|
||||
if (uio_MemDebug_logTypeInfo[(int) type].flags & uio_MemDebug_PRINT_ALLOC) {
|
||||
fprintf(stderr, "Alloc ");
|
||||
uio_MemDebug_printPointer(stderr, type, ptr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
pointerInfo = uio_MemDebug_PointerInfo_new(1);
|
||||
HashTable_add(uio_MemDebug_logs[type], ptr, (void *) pointerInfo);
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_logDeallocation(uio_MemDebug_LogType type, void *ptr) {
|
||||
uio_MemDebug_PointerInfo *pointerInfo;
|
||||
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Fatal: Attempt to free (%s *) NULL pointer.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name);
|
||||
abort();
|
||||
}
|
||||
if (uio_MemDebug_logTypeInfo[(int) type].flags & uio_MemDebug_PRINT_FREE) {
|
||||
fprintf(stderr, "Free ");
|
||||
uio_MemDebug_printPointer(stderr, type, ptr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
pointerInfo = HashTable_find(uio_MemDebug_logs[type], ptr);
|
||||
if (pointerInfo == NULL) {
|
||||
fprintf(stderr, "Fatal: Attempt to free unallocated pointer "
|
||||
"(%s *) %p.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name, ptr);
|
||||
abort();
|
||||
}
|
||||
#if 0
|
||||
if (pointerInfo->ref != 0) {
|
||||
fprintf(stderr, "Fatal: Attempt to free pointer with references "
|
||||
"left (%s *) %p.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name, ptr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
uio_MemDebug_PointerInfo_free(pointerInfo);
|
||||
HashTable_remove(uio_MemDebug_logs[type], ptr);
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_logRef(uio_MemDebug_LogType type, void *ptr) {
|
||||
uio_MemDebug_PointerInfo *pointerInfo;
|
||||
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Fatal: Attempt to increment reference to a "
|
||||
"(%s *) NULL pointer.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name);
|
||||
abort();
|
||||
}
|
||||
pointerInfo = HashTable_find(uio_MemDebug_logs[type], ptr);
|
||||
if (pointerInfo == NULL) {
|
||||
fprintf(stderr, "Fatal: Attempt to increment reference to "
|
||||
"unallocated pointer (%s *) %p.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name, ptr);
|
||||
abort();
|
||||
}
|
||||
pointerInfo->pointerRef++;
|
||||
if (uio_MemDebug_logTypeInfo[(int) type].flags & uio_MemDebug_PRINT_REF) {
|
||||
fprintf(stderr, "Ref++ to %d, ", pointerInfo->pointerRef);
|
||||
uio_MemDebug_printPointer(stderr, type, ptr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_logUnref(uio_MemDebug_LogType type, void *ptr) {
|
||||
uio_MemDebug_PointerInfo *pointerInfo;
|
||||
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Fatal: Attempt to decrement reference to a "
|
||||
"(%s *) NULL pointer.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name);
|
||||
abort();
|
||||
}
|
||||
pointerInfo = HashTable_find(uio_MemDebug_logs[type], ptr);
|
||||
if (pointerInfo == NULL) {
|
||||
fprintf(stderr, "Fatal: Attempt to decrement reference to "
|
||||
"unallocated pointer (%s *) %p.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name, ptr);
|
||||
abort();
|
||||
}
|
||||
if (pointerInfo->pointerRef == 0) {
|
||||
fprintf(stderr, "Fatal: Attempt to decrement reference below 0 for "
|
||||
"pointer (%s *) %p.\n",
|
||||
uio_MemDebug_logTypeInfo[(int) type].name, ptr);
|
||||
abort();
|
||||
}
|
||||
pointerInfo->pointerRef--;
|
||||
if (uio_MemDebug_logTypeInfo[(int) type].flags & uio_MemDebug_PRINT_UNREF) {
|
||||
fprintf(stderr, "Ref-- to %d, ", pointerInfo->pointerRef);
|
||||
uio_MemDebug_printPointer(stderr, type, ptr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_printPointer(FILE *out, uio_MemDebug_LogType type, void *ptr) {
|
||||
fprintf(out, "(%s *) %p", uio_MemDebug_logTypeInfo[(int) type].name, ptr);
|
||||
if (uio_MemDebug_logTypeInfo[(int) type].printFunction != NULL) {
|
||||
fprintf(out, ": ");
|
||||
uio_MemDebug_logTypeInfo[(int) type].printFunction(out, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_printPointersType(FILE *out, uio_MemDebug_LogType type) {
|
||||
HashTable_Iterator *iterator;
|
||||
|
||||
for (iterator = HashTable_getIterator(uio_MemDebug_logs[type]);
|
||||
!HashTable_iteratorDone(iterator);
|
||||
iterator = HashTable_iteratorNext(iterator)) {
|
||||
uio_MemDebug_printPointer(out, type, HashTable_iteratorKey(iterator));
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
HashTable_freeIterator(iterator);
|
||||
}
|
||||
|
||||
void
|
||||
uio_MemDebug_printPointers(FILE *out) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uio_MemDebug_numLogTypes; i++)
|
||||
uio_MemDebug_printPointersType(out, i);
|
||||
}
|
||||
|
||||
static inline uio_MemDebug_PointerInfo *
|
||||
uio_MemDebug_PointerInfo_new(int ref) {
|
||||
uio_MemDebug_PointerInfo *result;
|
||||
result = uio_MemDebug_PointerInfo_alloc();
|
||||
result->pointerRef = ref;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_MemDebug_PointerInfo_delete(uio_MemDebug_PointerInfo *pointerInfo) {
|
||||
uio_MemDebug_PointerInfo_free(pointerInfo);
|
||||
}
|
||||
|
||||
static inline uio_MemDebug_PointerInfo *
|
||||
uio_MemDebug_PointerInfo_alloc(void) {
|
||||
return uio_malloc(sizeof (uio_MemDebug_PointerInfo));
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_MemDebug_PointerInfo_free(uio_MemDebug_PointerInfo *pointerInfo) {
|
||||
uio_free(pointerInfo);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MEMDEBUG_H
|
||||
#define _MEMDEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "uioport.h"
|
||||
|
||||
// Important: if you add an item here, add it to uio_MemDebug_LogTypeInfo
|
||||
// too. The order should be the same.
|
||||
typedef enum {
|
||||
uio_MemDebug_LogType_uio_DirHandle,
|
||||
uio_MemDebug_LogType_uio_FileSystemInfo,
|
||||
uio_MemDebug_LogType_uio_GPDir,
|
||||
uio_MemDebug_LogType_uio_GPFile,
|
||||
uio_MemDebug_LogType_uio_GPRoot,
|
||||
uio_MemDebug_LogType_uio_Handle,
|
||||
uio_MemDebug_LogType_uio_MountHandle,
|
||||
uio_MemDebug_LogType_uio_MountInfo,
|
||||
uio_MemDebug_LogType_uio_MountTree,
|
||||
uio_MemDebug_LogType_uio_MountTreeItem,
|
||||
uio_MemDebug_LogType_uio_PathComp,
|
||||
uio_MemDebug_LogType_uio_PFileHandle,
|
||||
uio_MemDebug_LogType_uio_PDirHandle,
|
||||
uio_MemDebug_LogType_uio_PRoot,
|
||||
uio_MemDebug_LogType_uio_Repository,
|
||||
uio_MemDebug_LogType_uio_Stream,
|
||||
uio_MemDebug_LogType_stdio_GPDirData,
|
||||
uio_MemDebug_LogType_zip_GPFileData,
|
||||
|
||||
uio_MemDebug_numLogTypes, /* This needs to be the last entry */
|
||||
} uio_MemDebug_LogType;
|
||||
|
||||
typedef void (uio_MemDebug_PrintFunction)(FILE *out, const void *arg);
|
||||
|
||||
typedef struct uio_MemDebug_LogTypeInfo {
|
||||
const char *name;
|
||||
uio_MemDebug_PrintFunction *printFunction;
|
||||
int flags;
|
||||
#define uio_MemDebug_PRINT_ALLOC 0x1
|
||||
#define uio_MemDebug_PRINT_FREE 0x2
|
||||
#define uio_MemDebug_PRINT_REF 0x4
|
||||
#define uio_MemDebug_PRINT_UNREF 0x8
|
||||
#define uio_MemDebug_PRINT_ALL \
|
||||
(uio_MemDebug_PRINT_ALLOC | uio_MemDebug_PRINT_FREE | \
|
||||
uio_MemDebug_PRINT_REF | uio_MemDebug_PRINT_UNREF)
|
||||
} uio_MemDebug_LogTypeInfo;
|
||||
|
||||
extern const uio_MemDebug_LogTypeInfo uio_MemDebug_logTypeInfo[];
|
||||
|
||||
typedef struct uio_MemDebug_PointerInfo {
|
||||
int pointerRef;
|
||||
// Ref counter for the associated pointer, not the pointerInfo
|
||||
// itself.
|
||||
} uio_MemDebug_PointerInfo;
|
||||
|
||||
void uio_MemDebug_init(void);
|
||||
void uio_MemDebug_unInit(void);
|
||||
void uio_MemDebug_logAllocation(uio_MemDebug_LogType type, void *ptr);
|
||||
void uio_MemDebug_logDeallocation(uio_MemDebug_LogType type, void *ptr);
|
||||
void uio_MemDebug_logRef(uio_MemDebug_LogType type, void *ptr);
|
||||
void uio_MemDebug_logUnref(uio_MemDebug_LogType type, void *ptr);
|
||||
void uio_MemDebug_printPointer(FILE *out, uio_MemDebug_LogType type,
|
||||
void *ptr);
|
||||
void uio_MemDebug_printPointersType(FILE *out, uio_MemDebug_LogType type);
|
||||
void uio_MemDebug_printPointers(FILE *out);
|
||||
|
||||
#define uio_MemDebug_debugAlloc(type, pointer) \
|
||||
uio_MemDebug_logAllocation(uio_MemDebug_LogType_ ## type, pointer)
|
||||
#define uio_MemDebug_debugFree(type, pointer) \
|
||||
uio_MemDebug_logDeallocation(uio_MemDebug_LogType_ ## type, pointer)
|
||||
#define uio_MemDebug_debugRef(type, pointer) \
|
||||
uio_MemDebug_logRef(uio_MemDebug_LogType_ ## type, pointer)
|
||||
#define uio_MemDebug_debugUnref(type, pointer) \
|
||||
uio_MemDebug_logUnref(uio_MemDebug_LogType_ ## type, pointer)
|
||||
|
||||
#endif /* _MEMDEBUG_H */
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "uioport.h"
|
||||
#include "mount.h"
|
||||
#include "mounttree.h"
|
||||
#include "mem.h"
|
||||
#include "uioutils.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
static void uio_deleteRepository(uio_Repository *repository);
|
||||
static uio_Repository *uio_allocRepository(void);
|
||||
static void uio_freeRepository(uio_Repository *repository);
|
||||
|
||||
|
||||
void
|
||||
uio_repositoryAddMount(uio_Repository *repository,
|
||||
uio_MountInfo *mountInfo, uio_MountLocation location,
|
||||
uio_MountInfo *relative) {
|
||||
lockRepository(repository, uio_LOCK_WRITE);
|
||||
switch (location) {
|
||||
case uio_MOUNT_TOP: {
|
||||
uio_MountInfo **newMounts;
|
||||
|
||||
newMounts = uio_malloc(
|
||||
(repository->numMounts + 2) * sizeof (uio_MountInfo *));
|
||||
newMounts[0] = mountInfo;
|
||||
memcpy(&newMounts[1], repository->mounts,
|
||||
(repository->numMounts + 1) * sizeof (uio_MountInfo *));
|
||||
uio_free(repository->mounts);
|
||||
repository->mounts = newMounts;
|
||||
repository->numMounts++;
|
||||
break;
|
||||
}
|
||||
case uio_MOUNT_BOTTOM:
|
||||
repository->mounts = uio_realloc(repository->mounts,
|
||||
(repository->numMounts + 2) * sizeof (uio_MountInfo *));
|
||||
repository->mounts[repository->numMounts] = mountInfo;
|
||||
repository->numMounts++;
|
||||
break;
|
||||
case uio_MOUNT_BELOW: {
|
||||
int i;
|
||||
uio_MountInfo **newMounts;
|
||||
|
||||
i = 0;
|
||||
while (repository->mounts[i] != relative)
|
||||
i++;
|
||||
newMounts = (uio_MountInfo **) insertArrayPointer(
|
||||
(const void **) repository->mounts,
|
||||
repository->numMounts + 1, i, (void *) mountInfo);
|
||||
uio_free(repository->mounts);
|
||||
repository->mounts = newMounts;
|
||||
repository->numMounts++;
|
||||
break;
|
||||
}
|
||||
case uio_MOUNT_ABOVE: {
|
||||
int i;
|
||||
uio_MountInfo **newMounts;
|
||||
|
||||
i = 0;
|
||||
while (repository->mounts[i] != relative)
|
||||
i++;
|
||||
i++;
|
||||
newMounts = (uio_MountInfo **) insertArrayPointer(
|
||||
(const void **) repository->mounts,
|
||||
repository->numMounts + 1, i, (void *) mountInfo);
|
||||
uio_free(repository->mounts);
|
||||
repository->mounts = newMounts;
|
||||
repository->numMounts++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
unlockRepository(repository);
|
||||
}
|
||||
|
||||
void
|
||||
uio_repositoryRemoveMount(uio_Repository *repository, uio_MountInfo *mountInfo) {
|
||||
int i;
|
||||
uio_MountInfo **newMounts;
|
||||
|
||||
lockRepository(repository, uio_LOCK_WRITE);
|
||||
|
||||
i = 0;
|
||||
while (repository->mounts[i] != mountInfo)
|
||||
i++;
|
||||
newMounts = (uio_MountInfo **) excludeArrayPointer(
|
||||
(const void **) repository->mounts, repository->numMounts + 1,
|
||||
i, 1);
|
||||
uio_free(repository->mounts);
|
||||
repository->mounts = newMounts;
|
||||
repository->numMounts--;
|
||||
unlockRepository(repository);
|
||||
}
|
||||
|
||||
// sets ref to 1
|
||||
uio_Repository *
|
||||
uio_newRepository(int flags) {
|
||||
uio_Repository *result;
|
||||
|
||||
result = uio_allocRepository();
|
||||
result->ref = 1;
|
||||
result->flags = flags;
|
||||
result->numMounts = 0;
|
||||
result->mounts = uio_malloc(1 * sizeof (uio_MountInfo *));
|
||||
result->mounts[0] = NULL;
|
||||
result->mountTree = uio_makeRootMountTree();
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
uio_Repository_unref(uio_Repository *repository) {
|
||||
assert(repository->ref > 0);
|
||||
repository->ref--;
|
||||
if (repository->ref == 0)
|
||||
uio_deleteRepository(repository);
|
||||
}
|
||||
|
||||
static uio_Repository *
|
||||
uio_allocRepository(void) {
|
||||
uio_Repository *result = uio_malloc(sizeof (uio_Repository));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_Repository, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
uio_deleteRepository(uio_Repository *repository) {
|
||||
assert(repository->numMounts == 0);
|
||||
uio_free(repository->mounts);
|
||||
uio_deleteMountTree(repository->mountTree);
|
||||
uio_freeRepository(repository);
|
||||
}
|
||||
|
||||
static void
|
||||
uio_freeRepository(uio_Repository *repository) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_Repository, (void *) repository);
|
||||
#endif
|
||||
uio_free(repository);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MOUNT_H
|
||||
#define _MOUNT_H
|
||||
|
||||
|
||||
typedef struct uio_Repository uio_Repository;
|
||||
typedef struct uio_AutoMount uio_AutoMount;
|
||||
#define uio_MOUNT_RDONLY (1 << 1)
|
||||
|
||||
/* *** Internal definitions follow */
|
||||
#ifdef uio_INTERNAL
|
||||
|
||||
#define uio_MOUNT_LOCATION_MASK (3 << 2)
|
||||
|
||||
#include "uioport.h"
|
||||
#include "fstypes.h"
|
||||
#include "mounttree.h"
|
||||
#include "match.h"
|
||||
|
||||
struct uio_Repository {
|
||||
int ref; /* reference counter */
|
||||
int flags;
|
||||
int numMounts;
|
||||
struct uio_MountInfo **mounts;
|
||||
// first in the list is considered the top
|
||||
// last entry is NULL
|
||||
struct uio_MountTree *mountTree;
|
||||
};
|
||||
|
||||
#define lockRepository(repository, prot)
|
||||
#define unlockRepository(repository)
|
||||
|
||||
uio_Repository *uio_newRepository(int flags);
|
||||
void uio_Repository_unref(uio_Repository *repository);
|
||||
void uio_repositoryAddMount(uio_Repository *repository,
|
||||
uio_MountInfo *mountInfo, uio_MountLocation location,
|
||||
uio_MountInfo *relative);
|
||||
void uio_repositoryRemoveMount(uio_Repository *repository,
|
||||
uio_MountInfo *mountInfo);
|
||||
|
||||
|
||||
#endif /* uio_INTERNAL */
|
||||
|
||||
#endif /* _MOUNT_H */
|
||||
|
||||
@@ -0,0 +1,928 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "uioport.h"
|
||||
#include "mounttree.h"
|
||||
#include "paths.h"
|
||||
#include "types.h"
|
||||
#include "mem.h"
|
||||
#include "uioutils.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
static uio_MountTree *uio_mountTreeAddMountInfoRecTree(
|
||||
uio_Repository *repository, uio_MountTree *tree,
|
||||
uio_MountInfo *mountInfo, const char *start, const char *end,
|
||||
uio_PathComp *upComp, uio_MountLocation location,
|
||||
const uio_MountInfo *relative);
|
||||
static inline uio_MountTree *uio_mountTreeAddMountInfoRecTreeSub(
|
||||
uio_Repository *repository, uio_MountTree **tree,
|
||||
uio_MountInfo *mountInfo, const char *start,
|
||||
const char *end, uio_MountLocation location,
|
||||
const uio_MountInfo *relative);
|
||||
static void uio_mountTreeAddMountInfoLocAll(uio_Repository *repository,
|
||||
uio_MountTree *tree, uio_MountInfo *mountInfo, int depth,
|
||||
uio_MountLocation location, const uio_MountInfo *relative);
|
||||
static uio_MountTreeItem *uio_copyMountTreeItems(uio_MountTreeItem *item,
|
||||
int extraDepth);
|
||||
static void uio_addMountTreeItem(uio_Repository *repository,
|
||||
uio_MountTreeItem **pLocs, uio_MountTreeItem *item,
|
||||
uio_MountLocation location, const uio_MountInfo *relative);
|
||||
static uio_MountTree *uio_mountTreeAddNewSubTree(uio_Repository *repository,
|
||||
uio_MountTree *tree, const char *path, uio_MountInfo *mountInfo,
|
||||
uio_PathComp *upComp, uio_MountLocation location,
|
||||
const uio_MountInfo *relative);
|
||||
static void uio_mountTreeAddSub(uio_MountTree *tree, uio_MountTree *sub);
|
||||
static uio_MountTree * uio_splitMountTree(uio_MountTree **tree, uio_PathComp
|
||||
*lastComp, int depth);
|
||||
static void uio_mountTreeRemoveMountInfoRec(uio_MountTree *mountTree,
|
||||
uio_MountInfo *mountInfo);
|
||||
static int uio_countPathComps(const uio_PathComp *comp);
|
||||
static uio_PathComp *uio_lastPathComp(uio_PathComp *comp);
|
||||
static uio_PathComp *uio_makePathComps(const char *path,
|
||||
uio_PathComp *upComp);
|
||||
static void uio_printMount(FILE *outStream, const uio_MountInfo *mountInfo);
|
||||
|
||||
static inline uio_MountTree * uio_newMountTree(uio_MountTree *subTrees,
|
||||
uio_MountTreeItem *pLocs, uio_MountTree *upTree, uio_PathComp
|
||||
*comps, uio_PathComp *lastComp, uio_MountTree *next);
|
||||
static inline uio_MountTreeItem *uio_newMountTreeItem(
|
||||
uio_MountInfo *mountInfo, int depth, uio_MountTreeItem *next);
|
||||
static inline uio_PathComp *uio_newPathComp(char *name, size_t nameLen,
|
||||
uio_PathComp *upComp);
|
||||
|
||||
static inline void uio_deleteMountTreeItem(uio_MountTreeItem *item);
|
||||
static inline void uio_deletePathComp(uio_PathComp *pathComp);
|
||||
|
||||
static inline uio_MountTree *uio_allocMountTree(void);
|
||||
static inline uio_MountTreeItem *uio_allocMountTreeItem(void);
|
||||
static inline uio_MountInfo *uio_allocMountInfo(void);
|
||||
static inline uio_PathComp *uio_allocPathComp(void);
|
||||
|
||||
static inline void uio_freeMountTree(uio_MountTree *mountTree);
|
||||
static inline void uio_freeMountTreeItem(uio_MountTreeItem *mountTreeItem);
|
||||
static inline void uio_freeMountInfo(uio_MountInfo *mountInfo);
|
||||
static inline void uio_freePathComp(uio_PathComp *pathComp);
|
||||
|
||||
|
||||
// make the root mount Tree
|
||||
uio_MountTree *
|
||||
uio_makeRootMountTree(void) {
|
||||
return uio_newMountTree(NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
// Add a MountInfo structure to a MountTree in the place pointed
|
||||
// to by 'path'.
|
||||
// returns the MountTree for the location at the end of the path
|
||||
uio_MountTree *
|
||||
uio_mountTreeAddMountInfo(uio_Repository *repository, uio_MountTree *mountTree,
|
||||
uio_MountInfo *mountInfo, const char *path, uio_MountLocation location,
|
||||
const uio_MountInfo *relative) {
|
||||
const char *start, *end;
|
||||
|
||||
getFirstPath0Component(path, &start, &end);
|
||||
return uio_mountTreeAddMountInfoRecTree(repository, mountTree, mountInfo,
|
||||
start, end, NULL, location, relative);
|
||||
}
|
||||
|
||||
// recursive helper for uio_mountTreeAddMountInfo
|
||||
// returns the MountTree for the location at the end of the path
|
||||
static uio_MountTree *
|
||||
uio_mountTreeAddMountInfoRecTree(uio_Repository *repository, uio_MountTree *tree,
|
||||
uio_MountInfo *mountInfo, const char *start, const char *end,
|
||||
uio_PathComp *upComp,
|
||||
uio_MountLocation location, const uio_MountInfo *relative) {
|
||||
uio_MountTree **sub;
|
||||
|
||||
if (*start == '\0') {
|
||||
// End of the path. Put the MountInfo here and on all subtrees below
|
||||
// this level.
|
||||
uio_mountTreeAddMountInfoLocAll(repository, tree, mountInfo, 0,
|
||||
location, relative);
|
||||
return tree;
|
||||
}
|
||||
|
||||
// Check if sub trees match the path.
|
||||
for (sub = &tree->subTrees; *sub != NULL; sub = &(*sub)->next) {
|
||||
uio_MountTree *resTree;
|
||||
|
||||
resTree = uio_mountTreeAddMountInfoRecTreeSub(repository, sub,
|
||||
mountInfo, start, end, location, relative);
|
||||
if (resTree != NULL) {
|
||||
// handled
|
||||
return resTree;
|
||||
}
|
||||
}
|
||||
// No subtree found matching (part of) 'path'.
|
||||
|
||||
// Need to add a new tree sub
|
||||
return uio_mountTreeAddNewSubTree(repository, tree, start, mountInfo,
|
||||
upComp, location, relative);
|
||||
}
|
||||
|
||||
// recursive helper for uio_mountTreeAddMountInfo
|
||||
// Pre: *start != '\0'
|
||||
// returns the MountTree for the location at the end of the path, if
|
||||
// that falls within this tree. If not, returns NULL.
|
||||
static inline uio_MountTree *
|
||||
uio_mountTreeAddMountInfoRecTreeSub(uio_Repository *repository,
|
||||
uio_MountTree **tree, uio_MountInfo *mountInfo,
|
||||
const char *start, const char *end, uio_MountLocation location,
|
||||
const uio_MountInfo *relative) {
|
||||
uio_PathComp *comp, *lastComp;
|
||||
int depth;
|
||||
|
||||
comp = (*tree)->comps;
|
||||
if (strncmp(comp->name, start, end - start) != 0 ||
|
||||
comp->name[end - start] != '\0') {
|
||||
// first component does not match; this is not the correct subTree
|
||||
return NULL;
|
||||
}
|
||||
|
||||
depth = 1;
|
||||
// try to match all components of the directory path to this subTree.
|
||||
while (1) {
|
||||
getNextPath0Component(&start, &end);
|
||||
lastComp = comp;
|
||||
comp = comp->next;
|
||||
|
||||
if (comp == NULL)
|
||||
break;
|
||||
|
||||
if (*start == '\0') {
|
||||
// end of the path reached
|
||||
// We need to split up the components and insert a new
|
||||
// MountTree here.
|
||||
uio_MountTree *newTree;
|
||||
newTree = uio_splitMountTree(tree, lastComp, depth);
|
||||
|
||||
// Add mountInfo to each of the MountTrees below newTree.
|
||||
uio_mountTreeAddMountInfoLocAll(repository, newTree, mountInfo, 0,
|
||||
location, relative);
|
||||
|
||||
return newTree;
|
||||
}
|
||||
if (strncmp(comp->name, start, end - start) != 0 ||
|
||||
comp->name[end - start] != '\0') {
|
||||
// Some, but not all components matched; we need to split
|
||||
// up the components and add a new subTree here for the
|
||||
// (non-matching) rest of the path.
|
||||
uio_MountTree *newTree;
|
||||
|
||||
newTree = uio_splitMountTree(tree, lastComp, depth);
|
||||
|
||||
// A new Tree is added at the split-point.
|
||||
return uio_mountTreeAddNewSubTree(repository, newTree, start,
|
||||
mountInfo, lastComp, location, relative);
|
||||
}
|
||||
getNextPath0Component(&start, &end);
|
||||
depth++;
|
||||
}
|
||||
|
||||
// All components matched. We can recurse to the next subdir.
|
||||
return uio_mountTreeAddMountInfoRecTree(repository, *tree, mountInfo,
|
||||
start, end, lastComp, location, relative);
|
||||
}
|
||||
|
||||
// Add a MountInfo struct 'mountInfo' to the pLocs fields of all subTrees
|
||||
// starting with 'tree'.
|
||||
// 'depth' is the distance to the MountTree where the MountInfo is located.
|
||||
static void
|
||||
uio_mountTreeAddMountInfoLocAll(uio_Repository *repository, uio_MountTree *tree,
|
||||
uio_MountInfo *mountInfo, int depth, uio_MountLocation location,
|
||||
const uio_MountInfo *relative) {
|
||||
uio_MountTreeItem *newPLoc;
|
||||
uio_MountTree *subTree;
|
||||
int compCount;
|
||||
|
||||
// Add a new PLoc to this mountTree
|
||||
newPLoc = uio_newMountTreeItem(mountInfo, depth, NULL);
|
||||
uio_addMountTreeItem(repository, &tree->pLocs, newPLoc, location, relative);
|
||||
|
||||
// Recurse for subtrees
|
||||
for (subTree = tree->subTrees; subTree != NULL;
|
||||
subTree = subTree->next) {
|
||||
compCount = uio_countPathComps(subTree->comps);
|
||||
uio_mountTreeAddMountInfoLocAll(
|
||||
repository, subTree, mountInfo, depth + compCount,
|
||||
location, relative);
|
||||
}
|
||||
}
|
||||
|
||||
// pre: repository->mounts is already updated
|
||||
// pre: if location is uio_MOUNT_BELOW or uio_MOUNT_ABOVE, 'relative'
|
||||
// exists in repository->mounts
|
||||
static void
|
||||
uio_addMountTreeItem(uio_Repository *repository, uio_MountTreeItem **pLocs,
|
||||
uio_MountTreeItem *item,
|
||||
uio_MountLocation location, const uio_MountInfo *relative) {
|
||||
switch (location) {
|
||||
case uio_MOUNT_TOP:
|
||||
item->next = *pLocs;
|
||||
*pLocs = item;
|
||||
break;
|
||||
case uio_MOUNT_BOTTOM:
|
||||
while (*pLocs != NULL)
|
||||
pLocs = &(*pLocs)->next;
|
||||
item->next = NULL;
|
||||
*pLocs = item;
|
||||
break;
|
||||
case uio_MOUNT_ABOVE: {
|
||||
uio_MountInfo **mountInfo;
|
||||
mountInfo = repository->mounts;
|
||||
while (*mountInfo != relative) {
|
||||
assert(*mountInfo != NULL);
|
||||
if ((*pLocs)->mountInfo == *mountInfo)
|
||||
pLocs = &(*pLocs)->next;
|
||||
mountInfo++;
|
||||
}
|
||||
item->next = *pLocs;
|
||||
*pLocs = item;
|
||||
break;
|
||||
}
|
||||
case uio_MOUNT_BELOW: {
|
||||
uio_MountInfo **mountInfo;
|
||||
mountInfo = repository->mounts;
|
||||
while (*mountInfo != relative) {
|
||||
assert(*mountInfo != NULL);
|
||||
if ((*pLocs)->mountInfo == *mountInfo)
|
||||
pLocs = &(*pLocs)->next;
|
||||
mountInfo++;
|
||||
}
|
||||
item->next = (*pLocs)->next;
|
||||
(*pLocs)->next = item;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy a chain of MountTreeItems, but increase the depth by 'extraDepth'.
|
||||
static uio_MountTreeItem *
|
||||
uio_copyMountTreeItems(uio_MountTreeItem *item, int extraDepth) {
|
||||
uio_MountTreeItem *result, **resPtr;
|
||||
uio_MountTreeItem *newItem;
|
||||
|
||||
resPtr = &result;
|
||||
while (item != NULL) {
|
||||
newItem = uio_newMountTreeItem(
|
||||
item->mountInfo, item->depth + extraDepth, NULL);
|
||||
*resPtr = newItem;
|
||||
resPtr = &newItem->next;
|
||||
item = item->next;
|
||||
}
|
||||
*resPtr = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
// add a new sub tree under a tree 'tree'.
|
||||
// 'path' is the part leading up to the new tree and
|
||||
// 'mountInfo' is the MountInfo structure to at there.
|
||||
// 'upComp' points to the last path component that lead to 'tree'.
|
||||
static uio_MountTree *
|
||||
uio_mountTreeAddNewSubTree(uio_Repository *repository, uio_MountTree *tree,
|
||||
const char *path, uio_MountInfo *mountInfo, uio_PathComp *upComp,
|
||||
uio_MountLocation location, const uio_MountInfo *relative) {
|
||||
uio_MountTreeItem *item, *items;
|
||||
uio_MountTree *newTree;
|
||||
uio_PathComp *compList, *lastComp;
|
||||
int compCount;
|
||||
|
||||
compList = uio_makePathComps(path, upComp);
|
||||
compCount = uio_countPathComps(compList);
|
||||
lastComp = uio_lastPathComp(compList);
|
||||
item = uio_newMountTreeItem(mountInfo, 0, NULL);
|
||||
item->next = NULL;
|
||||
items = uio_copyMountTreeItems(tree->pLocs, compCount);
|
||||
uio_addMountTreeItem(repository, &items, item, location,
|
||||
relative);
|
||||
newTree = uio_newMountTree(
|
||||
NULL /* subTrees */,
|
||||
items /* pLocs */,
|
||||
tree /* upTree */,
|
||||
compList /* comps */,
|
||||
lastComp /* lastComp */,
|
||||
NULL /* next */);
|
||||
uio_mountTreeAddSub(tree, newTree);
|
||||
return newTree;
|
||||
}
|
||||
|
||||
// add a sub structure to the end of the 'subTrees' list of a tree.
|
||||
static void
|
||||
uio_mountTreeAddSub(uio_MountTree *tree, uio_MountTree *sub) {
|
||||
uio_MountTree **subPtr;
|
||||
|
||||
for (subPtr = &tree->subTrees; *subPtr != NULL;
|
||||
subPtr = &(*subPtr)->next) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
*subPtr = sub;
|
||||
}
|
||||
|
||||
// Add a new MountTree structure in between two MountTrees.
|
||||
// Tree points to the pointer for the tree in front of which the new
|
||||
// tree needs to be placed (at depth 'depth').
|
||||
// 'lastComp' is the last pathComp of the part before the splitting point
|
||||
// It returns the new MountTree.
|
||||
static uio_MountTree *
|
||||
uio_splitMountTree(uio_MountTree **tree, uio_PathComp *lastComp, int depth) {
|
||||
uio_MountTree *newTree;
|
||||
uio_MountTreeItem *items;
|
||||
|
||||
items = uio_copyMountTreeItems((*tree)->upTree->pLocs, depth);
|
||||
newTree = uio_newMountTree(
|
||||
*tree /* subTrees */,
|
||||
items /* pLocs */,
|
||||
(*tree)->upTree /* upTree */,
|
||||
(*tree)->comps /* comps */,
|
||||
lastComp /* lastComp */,
|
||||
NULL /* next */);
|
||||
(*tree)->upTree = newTree;
|
||||
(*tree)->comps = lastComp->next;
|
||||
lastComp->next = NULL;
|
||||
*tree = newTree;
|
||||
return newTree;
|
||||
}
|
||||
|
||||
void
|
||||
uio_mountTreeRemoveMountInfo(uio_Repository *repository,
|
||||
uio_MountTree *mountTree, uio_MountInfo *mountInfo) {
|
||||
uio_MountTree **subTreePtr;
|
||||
uio_MountTree *upTree;
|
||||
|
||||
// If the tree has no sub-trees and it has the same items as the
|
||||
// upTree, with 'mountInfo' added, then the tree is a dead end
|
||||
// and can be removed entirely.
|
||||
// First we handle the other case.
|
||||
// Note that if the upTree has exactly one item less than the tree
|
||||
// itself, these items must be the same, plus mountInfo for the
|
||||
// tree itself, as each tree has at least the items of its upTree.
|
||||
if (mountTree->upTree == NULL || mountTree->subTrees != NULL ||
|
||||
uio_mountTreeCountPLocs(mountTree) !=
|
||||
uio_mountTreeCountPLocs(mountTree->upTree) + 1) {
|
||||
// We can't remove the tree itself.
|
||||
// We need to remove the mountInfo from the tree, and all subTrees.
|
||||
// Then we're done.
|
||||
uio_mountTreeRemoveMountInfoRec(mountTree, mountInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
// mountTree itself can be removed.
|
||||
// First remove the tree from the list of subtrees of the upTree.
|
||||
subTreePtr = &mountTree->upTree->subTrees;
|
||||
while (1) {
|
||||
assert(*subTreePtr != NULL);
|
||||
if (*subTreePtr == mountTree)
|
||||
break;
|
||||
subTreePtr = &(*subTreePtr)->next;
|
||||
}
|
||||
*subTreePtr = mountTree->next;
|
||||
|
||||
// Save the upTree for later.
|
||||
upTree = mountTree->upTree;
|
||||
|
||||
// Remove the tree itself.
|
||||
uio_deleteMountTree(mountTree);
|
||||
|
||||
// The upTree itself could have become unnecessary now.
|
||||
// This is the case when upTree now only has one subTree, and upTree
|
||||
// and the subTree have the same items.
|
||||
// Again, same item count implies same items.
|
||||
if (upTree->subTrees == NULL || upTree->subTrees->next != NULL ||
|
||||
uio_mountTreeCountPLocs(upTree) !=
|
||||
uio_mountTreeCountPLocs(upTree->subTrees)) {
|
||||
// upTree is still necessary. We're done.
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge upTree and upTree->subTrees.
|
||||
// It would be easiest to keep upTree, and throw upTree->subTrees away,
|
||||
// but that's not possible as external links point to upTree->subTrees.
|
||||
// First merge the path components:
|
||||
assert(upTree->subTrees->lastComp != NULL);
|
||||
upTree->subTrees->lastComp->next = upTree->subTrees->comps;
|
||||
upTree->subTrees->lastComp = upTree->lastComp;
|
||||
upTree->subTrees->comps = upTree->comps;
|
||||
// Now let the pointer that pointed to upTree, point to upTree->subTrees.
|
||||
// Change upTree->next accordingly.
|
||||
if (upTree->upTree == NULL) {
|
||||
assert(repository->mountTree == upTree);
|
||||
repository->mountTree = upTree->subTrees;
|
||||
// upTree->subTrees->next is already NULL
|
||||
} else {
|
||||
uio_MountTree *next;
|
||||
subTreePtr = &upTree->upTree->subTrees;
|
||||
while (1) {
|
||||
assert(*subTreePtr != NULL);
|
||||
if (*subTreePtr == upTree)
|
||||
break;
|
||||
subTreePtr = &(*subTreePtr)->next;
|
||||
}
|
||||
next = (*subTreePtr)->next;
|
||||
*subTreePtr = upTree->subTrees;
|
||||
upTree->subTrees->next = next;
|
||||
}
|
||||
|
||||
// Now delete the tree itself
|
||||
upTree->subTrees = NULL;
|
||||
upTree->comps = NULL;
|
||||
uio_deleteMountTree(upTree);
|
||||
}
|
||||
|
||||
// pre: mountInfo exists in mountTree->pLocs (and hence in pLocs for
|
||||
// every sub-tree)
|
||||
static void
|
||||
uio_mountTreeRemoveMountInfoRec(uio_MountTree *mountTree,
|
||||
uio_MountInfo *mountInfo) {
|
||||
uio_MountTree *subTree;
|
||||
uio_MountTreeItem **itemPtr, *item;
|
||||
|
||||
// recurse for all subTrees
|
||||
for (subTree = mountTree->subTrees; subTree != NULL;
|
||||
subTree = subTree->next)
|
||||
uio_mountTreeRemoveMountInfoRec(subTree, mountInfo);
|
||||
|
||||
// Find the mount info in this tree.
|
||||
itemPtr = &mountTree->pLocs;
|
||||
while (1) {
|
||||
assert(*itemPtr != NULL);
|
||||
// We know an item with the specified mountInfo
|
||||
// must be here somewhere.
|
||||
if ((*itemPtr)->mountInfo == mountInfo) {
|
||||
// Found it.
|
||||
break;
|
||||
}
|
||||
itemPtr = &(*itemPtr)->next;
|
||||
}
|
||||
|
||||
item = *itemPtr;
|
||||
*itemPtr = item->next;
|
||||
uio_deleteMountTreeItem(item);
|
||||
}
|
||||
|
||||
// Count the number of path components that 'comp' leads to.
|
||||
static int
|
||||
uio_countPathComps(const uio_PathComp *comp) {
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
for (; comp != NULL; comp = comp->next)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
static uio_PathComp *
|
||||
uio_lastPathComp(uio_PathComp *comp) {
|
||||
if (comp == NULL)
|
||||
return NULL;
|
||||
|
||||
while (comp->next != NULL)
|
||||
comp = comp->next;
|
||||
return comp;
|
||||
}
|
||||
|
||||
// Count the number of pLocs in a tree that leads to.
|
||||
int
|
||||
uio_mountTreeCountPLocs(const uio_MountTree *tree) {
|
||||
int count;
|
||||
uio_MountTreeItem *item;
|
||||
|
||||
count = 0;
|
||||
for (item = tree->pLocs; item != NULL; item = item->next)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// make a list of uio_PathComps from a path string
|
||||
static uio_PathComp *
|
||||
uio_makePathComps(const char *path, uio_PathComp *upComp) {
|
||||
const char *start, *end;
|
||||
char *str;
|
||||
uio_PathComp *result;
|
||||
uio_PathComp **compPtr; // Where to put the next PathComp
|
||||
|
||||
compPtr = &result;
|
||||
getFirstPath0Component(path, &start, &end);
|
||||
while (*start != '\0') {
|
||||
str = uio_malloc(end - start + 1);
|
||||
memcpy(str, start, end - start);
|
||||
str[end - start] = '\0';
|
||||
|
||||
*compPtr = uio_newPathComp(str, end - start, upComp);
|
||||
upComp = *compPtr;
|
||||
compPtr = &(*compPtr)->next;
|
||||
getNextPath0Component(&start, &end);
|
||||
}
|
||||
*compPtr = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
// resTree may point to top
|
||||
// pPath may point to path
|
||||
void
|
||||
uio_findMountTree(uio_MountTree *top, const char *path,
|
||||
uio_MountTree **resTree, const char **pPath) {
|
||||
const char *start, *end, *pathFromTree;
|
||||
uio_MountTree *tree, *sub;
|
||||
uio_PathComp *comp;
|
||||
|
||||
getFirstPath0Component(path, &start, &end);
|
||||
tree = top;
|
||||
while(1) {
|
||||
if (*start == '\0') {
|
||||
*resTree = tree;
|
||||
*pPath = start;
|
||||
return;
|
||||
}
|
||||
|
||||
pathFromTree = start;
|
||||
sub = tree->subTrees;
|
||||
while(1) {
|
||||
if (sub == NULL) {
|
||||
// No matching sub Dirs found. So we report back the current
|
||||
// dir.
|
||||
*resTree = tree;
|
||||
*pPath = pathFromTree;
|
||||
return;
|
||||
}
|
||||
comp = sub->comps;
|
||||
if (strncmp(comp->name, start, end - start) == 0 &&
|
||||
comp->name[end - start] == '\0')
|
||||
break;
|
||||
sub = sub->next;
|
||||
}
|
||||
// Found a Sub dir which matches at least partially.
|
||||
|
||||
while (1) {
|
||||
getNextPath0Component(&start, &end);
|
||||
comp = comp->next;
|
||||
if (comp == NULL)
|
||||
break;
|
||||
if (*start == '\0' ||
|
||||
strncmp(comp->name, start, end - start) != 0 ||
|
||||
comp->name[end - start] != '\0') {
|
||||
// either the path ends here, or the path in the tree does.
|
||||
// either way, the last Tree is the one we want.
|
||||
*resTree = tree;
|
||||
*pPath = pathFromTree;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// all components matched until the next MountTree
|
||||
tree = sub;
|
||||
}
|
||||
}
|
||||
|
||||
// finds the path to the MountInfo associated with a mountTreeItem
|
||||
// given a path to the 'item' itself.
|
||||
// 'item' is the mountTreeItem
|
||||
// 'endComp' is the last PathComp leading to 'item'
|
||||
// 'start' is the start of the path to the item
|
||||
char *
|
||||
uio_mountTreeItemRestPath(const uio_MountTreeItem *item,
|
||||
uio_PathComp *endComp, const char *path) {
|
||||
int i;
|
||||
const char *pathPtr;
|
||||
|
||||
i = item->depth;
|
||||
while (i--)
|
||||
endComp = endComp->up;
|
||||
|
||||
pathPtr = path;
|
||||
if (endComp != NULL) {
|
||||
while (1) {
|
||||
pathPtr += endComp->nameLen;
|
||||
endComp = endComp->up;
|
||||
if (endComp == NULL)
|
||||
break;
|
||||
pathPtr++;
|
||||
// for a '/'
|
||||
}
|
||||
}
|
||||
if (*path == '/') {
|
||||
// / at the beginning of the path
|
||||
pathPtr++;
|
||||
}
|
||||
if (*pathPtr == '/') {
|
||||
// / at the end of the path
|
||||
pathPtr++;
|
||||
}
|
||||
// return (char *) pathPtr;
|
||||
// gives warning
|
||||
// return *((char **)((void *) &pathPtr));
|
||||
// not portable
|
||||
return (char *) unconst((const void *) pathPtr);
|
||||
}
|
||||
|
||||
void
|
||||
uio_printMountTree(FILE *outStream, const uio_MountTree *tree, int indent) {
|
||||
uio_MountTree *sub;
|
||||
uio_PathComp *comp;
|
||||
|
||||
fprintf(outStream, "(");
|
||||
uio_printMountTreeItems(outStream, tree->pLocs);
|
||||
fprintf(outStream, ")\n");
|
||||
for (sub = tree->subTrees; sub != NULL; sub = sub->next) {
|
||||
int newIndent;
|
||||
|
||||
newIndent = indent;
|
||||
fprintf(outStream, "%*s", indent, "");
|
||||
for (comp = sub->comps; comp != NULL; comp = comp->next) {
|
||||
fprintf(outStream, "/%s", comp->name);
|
||||
newIndent += 1 + comp->nameLen;
|
||||
}
|
||||
fprintf(outStream, " ");
|
||||
newIndent += 1;
|
||||
uio_printMountTree(outStream, sub, newIndent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_printMountTreeItem(FILE *outStream, const uio_MountTreeItem *item) {
|
||||
uio_printMountInfo(outStream, item->mountInfo);
|
||||
fprintf(outStream, ":%d", item->depth);
|
||||
}
|
||||
|
||||
void
|
||||
uio_printMountTreeItems(FILE *outStream, const uio_MountTreeItem *item) {
|
||||
if (!item)
|
||||
return;
|
||||
while(1) {
|
||||
uio_printMountTreeItem(outStream, item);
|
||||
item = item->next;
|
||||
if (item == NULL)
|
||||
break;
|
||||
fprintf(outStream, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uio_printPathToMountTree(FILE *outStream, const uio_MountTree *tree) {
|
||||
if (tree->upTree == NULL) {
|
||||
fprintf(outStream, "/");
|
||||
} else
|
||||
uio_printPathToComp(outStream, tree->lastComp);
|
||||
}
|
||||
|
||||
void
|
||||
uio_printPathComp(FILE *outStream, const uio_PathComp *comp) {
|
||||
fprintf(outStream, "%s", comp->name);
|
||||
}
|
||||
|
||||
void
|
||||
uio_printPathToComp(FILE *outStream, const uio_PathComp *comp) {
|
||||
if (comp == NULL)
|
||||
return;
|
||||
uio_printPathToComp(outStream, comp->up);
|
||||
fprintf(outStream, "/");
|
||||
uio_printPathComp(outStream, comp);
|
||||
}
|
||||
|
||||
void
|
||||
uio_printMountInfo(FILE *outStream, const uio_MountInfo *mountInfo) {
|
||||
uio_FileSystemInfo *fsInfo;
|
||||
|
||||
fsInfo = uio_getFileSystemInfo(mountInfo->fsID);
|
||||
fprintf(outStream, "%s:/%s", fsInfo->name, mountInfo->dirName);
|
||||
}
|
||||
|
||||
static void
|
||||
uio_printMount(FILE *outStream, const uio_MountInfo *mountInfo) {
|
||||
uio_FileSystemInfo *fsInfo;
|
||||
|
||||
fsInfo = uio_getFileSystemInfo(mountInfo->fsID);
|
||||
fprintf(outStream, "???:%s on ", mountInfo->dirName);
|
||||
uio_printPathToMountTree(outStream, mountInfo->mountTree);
|
||||
fprintf(outStream, " type %s (", fsInfo->name);
|
||||
if (mountInfo->flags & uio_MOUNT_RDONLY) {
|
||||
fprintf(outStream, "ro");
|
||||
} else
|
||||
fprintf(outStream, "rw");
|
||||
fprintf(outStream, ")\n");
|
||||
}
|
||||
|
||||
void
|
||||
uio_printMounts(FILE *outStream, const uio_Repository *repository) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < repository->numMounts; i++) {
|
||||
uio_printMount(outStream, repository->mounts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *** uio_MountTree*** //
|
||||
|
||||
static inline uio_MountTree *
|
||||
uio_newMountTree(uio_MountTree *subTrees, uio_MountTreeItem *pLocs,
|
||||
uio_MountTree *upTree, uio_PathComp *comps, uio_PathComp *lastComp,
|
||||
uio_MountTree *next) {
|
||||
uio_MountTree *result;
|
||||
|
||||
result = uio_allocMountTree();
|
||||
result->subTrees = subTrees;
|
||||
result->pLocs = pLocs;
|
||||
result->upTree = upTree;
|
||||
result->comps = comps;
|
||||
result->lastComp = lastComp;
|
||||
result->next = next;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
uio_deleteMountTree(uio_MountTree *tree) {
|
||||
uio_MountTree *subTree, *nextTree;
|
||||
uio_MountTreeItem *item, *nextItem;
|
||||
|
||||
subTree = tree->subTrees;
|
||||
while (subTree != NULL) {
|
||||
nextTree = subTree->next;
|
||||
uio_deleteMountTree(subTree);
|
||||
subTree = nextTree;
|
||||
}
|
||||
|
||||
item = tree->pLocs;
|
||||
while (item != NULL) {
|
||||
nextItem = item->next;
|
||||
uio_deleteMountTreeItem(item);
|
||||
item = nextItem;
|
||||
}
|
||||
|
||||
if (tree->comps != NULL)
|
||||
uio_deletePathComp(tree->comps);
|
||||
|
||||
uio_freeMountTree(tree);
|
||||
}
|
||||
|
||||
static inline uio_MountTree *
|
||||
uio_allocMountTree(void) {
|
||||
uio_MountTree *result = uio_malloc(sizeof (uio_MountTree));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_MountTree, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_freeMountTree(uio_MountTree *mountTree) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_MountTree, (void *) mountTree);
|
||||
#endif
|
||||
uio_free(mountTree);
|
||||
}
|
||||
|
||||
|
||||
// *** uio_MountTreeItem *** //
|
||||
|
||||
static inline uio_MountTreeItem *
|
||||
uio_newMountTreeItem(uio_MountInfo *mountInfo, int depth,
|
||||
uio_MountTreeItem *next) {
|
||||
uio_MountTreeItem *result;
|
||||
|
||||
result = uio_allocMountTreeItem();
|
||||
result->mountInfo = mountInfo;
|
||||
result->depth = depth;
|
||||
result->next = next;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_deleteMountTreeItem(uio_MountTreeItem *item) {
|
||||
uio_freeMountTreeItem(item);
|
||||
}
|
||||
|
||||
static inline uio_MountTreeItem *
|
||||
uio_allocMountTreeItem(void) {
|
||||
uio_MountTreeItem *result = uio_malloc(sizeof (uio_MountTreeItem));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_MountTreeItem, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_freeMountTreeItem(uio_MountTreeItem *mountTreeItem) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_MountTreeItem, (void *) mountTreeItem);
|
||||
#endif
|
||||
uio_free(mountTreeItem);
|
||||
}
|
||||
|
||||
|
||||
// *** uio_MountInfo *** //
|
||||
|
||||
uio_MountInfo *
|
||||
uio_newMountInfo(uio_FileSystemID fsID, uio_MountTree *mountTree,
|
||||
uio_PDirHandle *pDirHandle, char *dirName, uio_AutoMount **autoMount,
|
||||
uio_MountHandle *mountHandle, int flags) {
|
||||
uio_MountInfo *result;
|
||||
|
||||
result = uio_allocMountInfo();
|
||||
result->fsID = fsID;
|
||||
result->mountTree = mountTree;
|
||||
result->pDirHandle = pDirHandle;
|
||||
result->dirName = dirName;
|
||||
result->autoMount = autoMount;
|
||||
result->mountHandle = mountHandle;
|
||||
result->flags = flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
uio_deleteMountInfo(uio_MountInfo *mountInfo) {
|
||||
uio_free(mountInfo->dirName);
|
||||
uio_PDirHandle_unref(mountInfo->pDirHandle);
|
||||
uio_freeMountInfo(mountInfo);
|
||||
}
|
||||
|
||||
static inline uio_MountInfo *
|
||||
uio_allocMountInfo(void) {
|
||||
uio_MountInfo *result = uio_malloc(sizeof (uio_MountInfo));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_MountInfo, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_freeMountInfo(uio_MountInfo *mountInfo) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_MountInfo, (void *) mountInfo);
|
||||
#endif
|
||||
uio_free(mountInfo);
|
||||
}
|
||||
|
||||
|
||||
// *** uio_PathComp *** //
|
||||
|
||||
// 'name' should be a null terminated string. It is stored in the PathComp,
|
||||
// no copy is made.
|
||||
// 'namelen' should be the length of 'name'
|
||||
static inline uio_PathComp *
|
||||
uio_newPathComp(char *name, size_t nameLen, uio_PathComp *upComp) {
|
||||
uio_PathComp *result;
|
||||
|
||||
result = uio_allocPathComp();
|
||||
result->name = name;
|
||||
result->nameLen = nameLen;
|
||||
result->up = upComp;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_deletePathComp(uio_PathComp *pathComp) {
|
||||
uio_PathComp *next;
|
||||
|
||||
while (pathComp != NULL) {
|
||||
next = pathComp->next;
|
||||
uio_free(pathComp->name);
|
||||
uio_freePathComp(pathComp);
|
||||
pathComp = next;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uio_PathComp *
|
||||
uio_allocPathComp(void) {
|
||||
uio_PathComp *result = uio_malloc(sizeof (uio_PathComp));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_PathComp, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_freePathComp(uio_PathComp *pathComp) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_PathComp, (void *) pathComp);
|
||||
#endif
|
||||
uio_free(pathComp);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MOUNTTREE_H
|
||||
#define _MOUNTTREE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "mount.h"
|
||||
|
||||
void uio_printMounts(FILE *outStream, const uio_Repository *repository);
|
||||
|
||||
/* *** Internal definitions follow *** */
|
||||
#ifdef uio_INTERNAL
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct uio_MountTreeItem uio_MountTreeItem;
|
||||
typedef struct uio_MountTree uio_MountTree;
|
||||
typedef struct uio_PathComp uio_PathComp;
|
||||
typedef struct uio_MountInfo uio_MountInfo;
|
||||
|
||||
#include "physical.h"
|
||||
#include "types.h"
|
||||
#include "uioport.h"
|
||||
|
||||
|
||||
/*
|
||||
* A MountTree describes the relation between dirs (PRoot structures)
|
||||
* mounted in a directory structure.
|
||||
* A MountTree structure represents a node (a dir) in this directory
|
||||
* structure.
|
||||
* It describes what MountInfo structures apply in that dir and below (if
|
||||
* not overrided in subnodes) (the 'pLocs' field).
|
||||
* These path components are also linked together 'up'-wards (towards the
|
||||
* root of the tree) by the 'up' field.
|
||||
*/
|
||||
|
||||
struct uio_MountTreeItem {
|
||||
struct uio_MountInfo *mountInfo;
|
||||
int depth;
|
||||
// 'mountInfo->pDirHandle' and 'depth' together point to a
|
||||
// location in a physical tree. An uio_pDirHandle alone can't be
|
||||
// used as the directory might not exist.
|
||||
// So pDirHandle points to the top dir that was mounted, and
|
||||
// 'depth' indicates how many directory names of the path to
|
||||
// this point in the Mount Tree need to be followed.
|
||||
// Example:
|
||||
// This MountTreeItem is somewhere in a tree /foo/bar/bla
|
||||
// and depth = 1. Then this MountTreeItem points to
|
||||
// /bla in the specified root.
|
||||
struct uio_MountTreeItem *next;
|
||||
// The next MountTreeItem in a MountTree
|
||||
};
|
||||
|
||||
struct uio_PathComp {
|
||||
char *name;
|
||||
// The name of this path component, 0-terminated
|
||||
size_t nameLen;
|
||||
// The length of the 'name' field, for fast lookups.
|
||||
struct uio_PathComp *next;
|
||||
// The next path component leading to a MountTree
|
||||
// If this is NULL, then this was the last component
|
||||
// until the MountTree that
|
||||
struct uio_PathComp *up;
|
||||
// Links to the directory
|
||||
};
|
||||
|
||||
struct uio_MountTree {
|
||||
struct uio_MountTree *subTrees;
|
||||
// Trees for subdirs in this MountTree
|
||||
struct uio_MountTreeItem *pLocs;
|
||||
// The physical locations that have effect in this MountTree.
|
||||
struct uio_MountTree *upTree;
|
||||
// the MountTree that pointed to this MountTree
|
||||
struct uio_PathComp *comps;
|
||||
// the names of the path components that lead to the tree.
|
||||
// Not necessary every PathComp is connected to a MountTree.
|
||||
// If you have /foo and /foo/bar/zut mounted, then
|
||||
// there are MountTrees for /, /foo and /foo/bar/zut,
|
||||
// but there are PathComps for 'foo', 'bar' and 'zut'.
|
||||
struct uio_PathComp *lastComp;
|
||||
// The last PathComp of comps that pointed to this MountTree.
|
||||
// This can be used to trace the path back to the top.
|
||||
struct uio_MountTree *next;
|
||||
// If this tree is a subTree of a tree, 'next' points to the
|
||||
// next subTree of that tree.
|
||||
};
|
||||
|
||||
/*
|
||||
* A MountInfo structure describes how a physical structure was mounted.
|
||||
* A physical structure can be used by several MountInfo structures.
|
||||
*/
|
||||
struct uio_MountInfo {
|
||||
int flags;
|
||||
/* Mount flags */
|
||||
# define uio_MOUNTINFO_RDONLY uio_MOUNT_RDONLY
|
||||
uio_FileSystemID fsID;
|
||||
char *dirName;
|
||||
/* The path inside the mounted fs leading to pDirHandle */
|
||||
uio_PDirHandle *pDirHandle;
|
||||
/* The pDirHandle belonging to this mount type */
|
||||
uio_MountTree *mountTree;
|
||||
/* The MountTree node for the mountpoint */
|
||||
uio_AutoMount **autoMount;
|
||||
uio_MountHandle *mountHandle;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Say we've got mounted (in order):
|
||||
* Bla -> /
|
||||
* Bar -> /foo/bar
|
||||
* Foo -> /foo
|
||||
* Zut -> /zut/123
|
||||
* Fop -> /zut/123
|
||||
*
|
||||
* This will build a tree that looks like this:
|
||||
* (the strings between brackets are the mounted filesystems that have effect
|
||||
* in a dir, in order)
|
||||
*
|
||||
* / (Bar)
|
||||
* foo (Foo, Bla)
|
||||
* bar (Foo, Bar, Bla)
|
||||
* zut/123 (Fop, Zut, Bla)
|
||||
*
|
||||
* The MountTree will look like:
|
||||
* / = {
|
||||
* sub = {
|
||||
* /foo,
|
||||
* /zut/123
|
||||
* },
|
||||
* pLocs = {
|
||||
* BlaDir:/ (0)
|
||||
* }
|
||||
* }
|
||||
* /foo = {
|
||||
* sub = {
|
||||
* /foo/bar
|
||||
* },
|
||||
* pLocs = {
|
||||
* BlaDir:/foo (1),
|
||||
* FooDir:/ (0)
|
||||
* }
|
||||
* }
|
||||
* /foo/bar = {
|
||||
* sub = { },
|
||||
* pLocs = {
|
||||
* BlaDir:/foo/bar (2),
|
||||
* BarDir:/ (0),
|
||||
* FooDir:/bar (1)
|
||||
* }
|
||||
* }
|
||||
* /zut/123 = {
|
||||
* sub = { },
|
||||
* pLocs = {
|
||||
* FooDir:/ (0)
|
||||
* ZutDir:/ (0)
|
||||
* BlaDir:/zut/123 (2)
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* 'BlaDir:/zut/123 (2)' means the pDirHandle is 'Bla', and the dir into
|
||||
* that directory is '/zut/123', but as this is always a postfix of the
|
||||
* path where we are, the number of dirs (the '(2)') is enough to store
|
||||
* (apart from the pDirHandle).
|
||||
*/
|
||||
|
||||
uio_MountTree *uio_makeRootMountTree(void);
|
||||
void uio_deleteMountTree(uio_MountTree *tree);
|
||||
uio_MountTree *uio_mountTreeAddMountInfo(uio_Repository *repository,
|
||||
uio_MountTree *mountTree, uio_MountInfo *mountInfo, const char *path,
|
||||
uio_MountLocation location, const uio_MountInfo *relative);
|
||||
void uio_mountTreeRemoveMountInfo(uio_Repository *repository,
|
||||
uio_MountTree *mountTree, uio_MountInfo *mountInfo);
|
||||
void uio_findMountTree(uio_MountTree *top, const char *path,
|
||||
uio_MountTree **resTree, const char **pPath);
|
||||
char *uio_mountTreeItemRestPath(const uio_MountTreeItem *item,
|
||||
uio_PathComp *endComp, const char *path);
|
||||
int uio_mountTreeCountPLocs(const uio_MountTree *tree);
|
||||
uio_MountInfo *uio_newMountInfo(uio_FileSystemID fsID, uio_MountTree *mountTree,
|
||||
uio_PDirHandle *pDirHandle, char *dirName, uio_AutoMount **autoMount,
|
||||
uio_MountHandle *mountHandle, int flags);
|
||||
void uio_deleteMountInfo(uio_MountInfo *mountInfo);
|
||||
void uio_printMountTree(FILE *outStream, const uio_MountTree *tree, int indent);
|
||||
void uio_printMountTreeItem(FILE *outStream, const uio_MountTreeItem *item);
|
||||
void uio_printMountTreeItems(FILE *outStream, const uio_MountTreeItem *item);
|
||||
void uio_printPathToMountTree(FILE *outStream, const uio_MountTree *tree);
|
||||
void uio_printPathComp(FILE *outStream, const uio_PathComp *comp);
|
||||
void uio_printPathToComp(FILE *outStream, const uio_PathComp *comp);
|
||||
void uio_printMountInfo(FILE *outStream, const uio_MountInfo *mountInfo);
|
||||
|
||||
static inline uio_bool
|
||||
uio_mountInfoIsReadOnly(uio_MountInfo *mountInfo) {
|
||||
return (mountInfo->flags & uio_MOUNTINFO_RDONLY) != 0;
|
||||
}
|
||||
|
||||
#endif /* uio_INTERNAL */
|
||||
|
||||
#endif /* _MOUNTTREE_H */
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "paths.h"
|
||||
#include "uioport.h"
|
||||
#include "mem.h"
|
||||
|
||||
// gets the first dir component of a path
|
||||
// sets '*start' to the start of the first component
|
||||
// sets '*end' to the end of the first component
|
||||
// if *start >= dirEnd, then the end has been reached.
|
||||
void
|
||||
getFirstPathComponent(const char *dir, const char *dirEnd,
|
||||
const char **startComp, const char **endComp) {
|
||||
assert(dir <= dirEnd);
|
||||
*startComp = dir;
|
||||
if (*startComp == dirEnd) {
|
||||
*endComp = *startComp;
|
||||
return;
|
||||
}
|
||||
*endComp = memchr(*startComp, '/', dirEnd - *startComp);
|
||||
if (*endComp == NULL)
|
||||
*endComp = dirEnd;
|
||||
}
|
||||
|
||||
// gets the first dir component of a path
|
||||
// sets '*start' to the start of the first component
|
||||
// sets '*end' to the end of the first component
|
||||
// if **start == '\0', then the end has been reached.
|
||||
void
|
||||
getFirstPath0Component(const char *dir,
|
||||
const char **startComp, const char **endComp) {
|
||||
*startComp = dir;
|
||||
if (**startComp == '\0') {
|
||||
*endComp = *startComp;
|
||||
return;
|
||||
}
|
||||
*endComp = strchr(*startComp, '/');
|
||||
if (*endComp == NULL)
|
||||
*endComp = *startComp + strlen(*startComp);
|
||||
}
|
||||
|
||||
// gets the next component of path
|
||||
// '*start' should be set to the start of the last component
|
||||
// '*end' should be set to the end of the last component
|
||||
// '*start' will be set to the start of the next componentt
|
||||
// '*end' will be set to the end of the next component
|
||||
// if *start >= dirEnd, then the end has been reached.
|
||||
void
|
||||
getNextPathComponent(const char *dirEnd,
|
||||
const char **startComp, const char **endComp) {
|
||||
assert(*endComp <= dirEnd);
|
||||
if (*endComp == dirEnd) {
|
||||
*startComp = *endComp;
|
||||
return;
|
||||
}
|
||||
assert(**endComp == '/');
|
||||
*startComp = *endComp + 1;
|
||||
*endComp = memchr(*startComp, '/', dirEnd - *startComp);
|
||||
if (*endComp == NULL)
|
||||
*endComp = dirEnd;
|
||||
}
|
||||
|
||||
// gets the next component of path
|
||||
// '*start' should be set to the start of the last component
|
||||
// '*end' should be set to the end of the last component
|
||||
// '*start' will be set to the start of the next componentt
|
||||
// '*end' will be set to the end of the next component
|
||||
// if **start == '\0', then the end has been reached.
|
||||
void
|
||||
getNextPath0Component(const char **startComp, const char **endComp) {
|
||||
if (**endComp == '\0') {
|
||||
*startComp = *endComp;
|
||||
return;
|
||||
}
|
||||
assert(**endComp == '/');
|
||||
*startComp = *endComp + 1;
|
||||
*endComp = strchr(*startComp, '/');
|
||||
if (*endComp == NULL)
|
||||
*endComp = *startComp + strlen(*startComp);
|
||||
}
|
||||
|
||||
// if *end == dir, the beginning has been reached
|
||||
void
|
||||
getLastPathComponent(const char *dir, const char *endDir,
|
||||
const char **startComp, const char **endComp) {
|
||||
*endComp = endDir;
|
||||
// if (*(*endComp - 1) == '/')
|
||||
// (*endComp)--;
|
||||
*startComp = *endComp;
|
||||
// TODO: use memrchr where available
|
||||
while ((*startComp) - 1 >= dir && *(*startComp - 1) != '/')
|
||||
(*startComp)--;
|
||||
}
|
||||
|
||||
// if *end == dir, the beginning has been reached
|
||||
// pre: dir is \0-terminated
|
||||
void
|
||||
getLastPath0Component(const char *dir,
|
||||
const char **startComp, const char **endComp) {
|
||||
*endComp = dir + strlen(dir);
|
||||
// if (*(*endComp - 1) == '/')
|
||||
// (*endComp)--;
|
||||
*startComp = *endComp;
|
||||
// TODO: use memrchr where available
|
||||
while ((*startComp) - 1 >= dir && *(*startComp - 1) != '/')
|
||||
(*startComp)--;
|
||||
}
|
||||
|
||||
// if *end == dir, the beginning has been reached
|
||||
void
|
||||
getPreviousPathComponent(const char *dir,
|
||||
const char **startComp, const char **endComp) {
|
||||
if (*startComp == dir) {
|
||||
*endComp = *startComp;
|
||||
return;
|
||||
}
|
||||
*endComp = *startComp - 1;
|
||||
*startComp = *endComp;
|
||||
while ((*startComp) - 1 >= dir && *(*startComp - 1) != '/')
|
||||
(*startComp)--;
|
||||
}
|
||||
|
||||
char *
|
||||
joinPaths(const char *first, const char *second) {
|
||||
char *result, *resPtr;
|
||||
size_t firstLen, secondLen;
|
||||
|
||||
firstLen = strlen(first);
|
||||
if (first[firstLen - 1] == '/')
|
||||
firstLen--;
|
||||
secondLen = strlen(second);
|
||||
result = uio_malloc(firstLen + secondLen + 2);
|
||||
resPtr = result;
|
||||
|
||||
memcpy(resPtr, first, firstLen);
|
||||
resPtr += firstLen;
|
||||
|
||||
*resPtr = '/';
|
||||
resPtr++;
|
||||
|
||||
memcpy(resPtr, second, secondLen);
|
||||
resPtr += secondLen;
|
||||
|
||||
*resPtr = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
uio_bool
|
||||
validPathName(const char *path, size_t len) {
|
||||
const char *pathEnd;
|
||||
const char *start, *end;
|
||||
|
||||
pathEnd = path + len;
|
||||
getFirstPathComponent(path, pathEnd, &start, &end);
|
||||
while (start < pathEnd) {
|
||||
if (end == start || (end - start == 1 && start[0] == '.') ||
|
||||
(end - start == 2 && start[0] == '.' && start[1] == '.'))
|
||||
return false;
|
||||
getNextPathComponent(pathEnd, &start, &end);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PATHS_H
|
||||
#define PATHS_H
|
||||
|
||||
#include "types.h"
|
||||
#include "uioport.h"
|
||||
|
||||
void getFirstPathComponent(const char *dir, const char *dirEnd,
|
||||
const char **startComp, const char **endComp);
|
||||
void getFirstPath0Component(const char *dir, const char **startComp,
|
||||
const char **endComp);
|
||||
void getNextPathComponent(const char *dirEnd,
|
||||
const char **startComp, const char **endComp);
|
||||
void getNextPath0Component(const char **startComp, const char **endComp);
|
||||
void getLastPathComponent(const char *dir, const char *dirEnd,
|
||||
const char **startComp, const char **endComp);
|
||||
void getLastPath0Component(const char *dir, const char **startComp,
|
||||
const char **endComp);
|
||||
void getPreviousPathComponent(const char *dir, const char **startComp,
|
||||
const char **endComp);
|
||||
#define getPreviousPath0Component getPreviousPathComponent
|
||||
char *joinPaths(const char *first, const char *second);
|
||||
|
||||
uio_bool validPathName(const char *path, size_t len);
|
||||
|
||||
#endif /* PATHS_H */
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "physical.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
#include "uioport.h"
|
||||
|
||||
static inline uio_PRoot *uio_PRoot_alloc(void);
|
||||
static inline void uio_PRoot_free(uio_PRoot *pRoot);
|
||||
|
||||
// NB: ref counter is not incremented
|
||||
uio_PDirHandle *
|
||||
uio_PRoot_getRootDirHandle(uio_PRoot *pRoot) {
|
||||
return pRoot->rootDir;
|
||||
}
|
||||
|
||||
void
|
||||
uio_PRoot_deletePRootExtra(uio_PRoot *pRoot) {
|
||||
if (pRoot->extra == NULL)
|
||||
return;
|
||||
assert(pRoot->handler->deletePRootExtra != NULL);
|
||||
pRoot->handler->deletePRootExtra(pRoot->extra);
|
||||
}
|
||||
|
||||
// note: sets refMount count to 1
|
||||
// set handlerRef count to 0
|
||||
uio_PRoot *
|
||||
uio_PRoot_new(uio_PDirHandle *topDirHandle,
|
||||
uio_FileSystemHandler *handler, uio_Handle *handle,
|
||||
uio_PRootExtra extra, int flags) {
|
||||
uio_PRoot *pRoot;
|
||||
|
||||
pRoot = uio_PRoot_alloc();
|
||||
pRoot->mountRef = 1;
|
||||
pRoot->handleRef = 0;
|
||||
pRoot->rootDir = topDirHandle;
|
||||
pRoot->handler = handler;
|
||||
pRoot->handle = handle;
|
||||
pRoot->extra = extra;
|
||||
pRoot->flags = flags;
|
||||
|
||||
return pRoot;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PRoot_delete(uio_PRoot *pRoot) {
|
||||
assert(pRoot->handler->umount != NULL);
|
||||
pRoot->handler->umount(pRoot);
|
||||
if (pRoot->handle)
|
||||
uio_Handle_unref(pRoot->handle);
|
||||
uio_PRoot_deletePRootExtra(pRoot);
|
||||
uio_PRoot_free(pRoot);
|
||||
}
|
||||
|
||||
static inline uio_PRoot *
|
||||
uio_PRoot_alloc(void) {
|
||||
uio_PRoot *result = uio_malloc(sizeof (uio_PRoot));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_PRoot, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_PRoot_free(uio_PRoot *pRoot) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_PRoot, (void *) pRoot);
|
||||
#endif
|
||||
uio_free(pRoot);
|
||||
}
|
||||
|
||||
void
|
||||
uio_PRoot_refHandle(uio_PRoot *pRoot) {
|
||||
pRoot->handleRef++;
|
||||
}
|
||||
|
||||
void
|
||||
uio_PRoot_unrefHandle(uio_PRoot *pRoot) {
|
||||
assert(pRoot->handleRef > 0);
|
||||
pRoot->handleRef--;
|
||||
if (pRoot->handleRef == 0 && pRoot->mountRef == 0)
|
||||
uio_PRoot_delete(pRoot);
|
||||
}
|
||||
|
||||
void
|
||||
uio_PRoot_refMount(uio_PRoot *pRoot) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugRef(uio_PRoot, (void *) pRoot);
|
||||
#endif
|
||||
pRoot->handleRef++;
|
||||
}
|
||||
|
||||
void
|
||||
uio_PRoot_unrefMount(uio_PRoot *pRoot) {
|
||||
assert(pRoot->mountRef > 0);
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugUnref(uio_PRoot, (void *) pRoot);
|
||||
#endif
|
||||
pRoot->mountRef--;
|
||||
if (pRoot->mountRef == 0 && pRoot->handleRef == 0)
|
||||
uio_PRoot_delete(pRoot);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PHYSICAL_H
|
||||
#define _PHYSICAL_H
|
||||
|
||||
#ifndef uio_INTERNAL_PHYSICAL
|
||||
typedef void *uio_PRootExtra;
|
||||
typedef void *uio_NativeEntriesContext;
|
||||
#endif
|
||||
|
||||
// 'forward' declarations
|
||||
typedef struct uio_PRoot uio_PRoot;
|
||||
|
||||
|
||||
#include "iointrn.h"
|
||||
#include "uioport.h"
|
||||
#include "fstypes.h"
|
||||
|
||||
|
||||
/*
|
||||
* Represents the root of a physical directory structure.
|
||||
*/
|
||||
struct uio_PRoot {
|
||||
int mountRef;
|
||||
/* Number of times this structure is referenced from
|
||||
* mount trees. */
|
||||
int handleRef;
|
||||
/* Number of file or directory handles that point inside the
|
||||
* physical directory strucure of this pRoot.
|
||||
*/
|
||||
struct uio_PDirHandle *rootDir;
|
||||
struct uio_FileSystemHandler *handler;
|
||||
/* How to handle files in this PRoot tree */
|
||||
int flags;
|
||||
# define uio_PRoot_NOCACHE 0x0002
|
||||
struct uio_Handle *handle;
|
||||
/* The handle through which this PRoot is opened,
|
||||
* this is NULL for the top PRoot */
|
||||
// TODO: move this to extra?
|
||||
uio_PRootExtra extra;
|
||||
/* extra internal data for some filesystem types */
|
||||
};
|
||||
|
||||
void uio_PRoot_deletePRootExtra(uio_PRoot *pRoot);
|
||||
uio_PRoot *uio_PRoot_new(uio_PDirHandle *topDirHandle,
|
||||
uio_FileSystemHandler *handler, uio_Handle *handle,
|
||||
uio_PRootExtra extra, int flags);
|
||||
uio_PDirHandle *uio_PRoot_getRootDirHandle(uio_PRoot *pRoot);
|
||||
void uio_PRoot_refHandle(uio_PRoot *pRoot);
|
||||
void uio_PRoot_unrefHandle(uio_PRoot *pRoot);
|
||||
void uio_PRoot_refMount(uio_PRoot *pRoot);
|
||||
void uio_PRoot_unrefMount(uio_PRoot *pRoot);
|
||||
|
||||
#endif /* _PHYSICAL_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
uqm_CFILES="stdio.c"
|
||||
|
||||
|
||||
@@ -0,0 +1,729 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "./stdio.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
# define _POSIX_THREAD_SAFEFUNCTIONS
|
||||
// for readdir_r
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../uioport.h"
|
||||
#include "../paths.h"
|
||||
#include "../mem.h"
|
||||
#include "../physical.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "../memdebug.h"
|
||||
#endif
|
||||
|
||||
static inline uio_GPFile *stdio_addFile(uio_GPDir *gPDir,
|
||||
const char *fileName);
|
||||
static inline uio_GPDir *stdio_addDir(uio_GPDir *gPDir, const char *dirName);
|
||||
static char *stdio_getPath(uio_GPDir *gPDir);
|
||||
static stdio_GPDirData *stdio_GPDirData_new(char *name, char *cachedPath,
|
||||
uio_GPDir *upDir);
|
||||
static void stdio_GPDirData_delete(stdio_GPDirData *gPDirData);
|
||||
static inline stdio_GPDirData *stdio_GPDirData_alloc(void);
|
||||
static inline void stdio_GPDirData_free(stdio_GPDirData *gPDirData);
|
||||
static inline stdio_EntriesIterator *stdio_EntriesIterator_alloc(void);
|
||||
static inline void stdio_EntriesIterator_free(
|
||||
stdio_EntriesIterator *iterator);
|
||||
|
||||
uio_FileSystemHandler stdio_fileSystemHandler = {
|
||||
/* .init = */ NULL,
|
||||
/* .unInit = */ NULL,
|
||||
/* .cleanup = */ NULL,
|
||||
|
||||
/* .mount = */ stdio_mount,
|
||||
/* .umount = */ uio_GPRoot_umount,
|
||||
|
||||
/* .close = */ stdio_close,
|
||||
/* .fstat = */ stdio_fstat,
|
||||
/* .stat = */ stdio_stat,
|
||||
/* .mkdir = */ stdio_mkdir,
|
||||
/* .open = */ stdio_open,
|
||||
/* .read = */ stdio_read,
|
||||
/* .rmdir = */ stdio_rmdir,
|
||||
/* .seek = */ stdio_seek,
|
||||
/* .write = */ stdio_write,
|
||||
/* .unlink = */ stdio_unlink,
|
||||
|
||||
/* .openEntries = */ stdio_openEntries,
|
||||
/* .readEntries = */ stdio_readEntries,
|
||||
/* .closeEntries = */ stdio_closeEntries,
|
||||
|
||||
/* .getPDirEntryHandle = */ stdio_getPDirEntryHandle,
|
||||
/* .deletePRootExtra = */ uio_GPRoot_delete,
|
||||
/* .deletePDirHandleExtra = */ uio_GPDirHandle_delete,
|
||||
/* .deletePFileHandleExtra = */ uio_GPFileHandle_delete,
|
||||
};
|
||||
|
||||
uio_GPRoot_Operations stdio_GPRootOperations = {
|
||||
/* .fillGPDir = */ NULL,
|
||||
/* .deleteGPRootExtra = */ NULL,
|
||||
/* .deleteGPDirExtra = */ stdio_GPDirData_delete,
|
||||
/* .deleteGPFileExtra = */ NULL,
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
stdio_close(uio_Handle *handle) {
|
||||
int fd;
|
||||
int result;
|
||||
|
||||
fd = handle->native->fd;
|
||||
uio_free(handle->native);
|
||||
|
||||
while (1) {
|
||||
result = close(fd);
|
||||
if (result == 0)
|
||||
break;
|
||||
if (errno != EINTR) {
|
||||
fprintf(stderr, "Warning: Error while closing socket: %s\n",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
stdio_fstat(uio_Handle *handle, struct stat *statBuf) {
|
||||
return fstat(handle->native->fd, statBuf);
|
||||
}
|
||||
|
||||
int
|
||||
stdio_stat(uio_PDirHandle *pDirHandle, const char *name,
|
||||
struct stat *statBuf) {
|
||||
char *path;
|
||||
int result;
|
||||
|
||||
path = joinPaths(stdio_getPath(pDirHandle->extra), name);
|
||||
if (path == NULL) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = stat(path, statBuf);
|
||||
if (result == -1) {
|
||||
int saveErrno = errno;
|
||||
uio_free(path);
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uio_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
uio_PDirHandle *
|
||||
stdio_mkdir(uio_PDirHandle *pDirHandle, const char *name, mode_t mode) {
|
||||
char *path;
|
||||
uio_GPDir *newGPDir;
|
||||
|
||||
path = joinPaths(stdio_getPath(pDirHandle->extra), name);
|
||||
if (path == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mkdir(path, mode) == -1) {
|
||||
int saveErrno = errno;
|
||||
uio_free(path);
|
||||
errno = saveErrno;
|
||||
return NULL;
|
||||
}
|
||||
uio_free(path);
|
||||
|
||||
newGPDir = stdio_addDir(pDirHandle->extra, name);
|
||||
uio_GPDir_ref(newGPDir);
|
||||
return uio_PDirHandle_new(pDirHandle->pRoot, newGPDir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function name: stdio_open
|
||||
* Description: open a file from a normal stdio environment
|
||||
* Arguments: gPDir - the dir where to open the file
|
||||
* file - the name of the file to open
|
||||
* flags - flags, as to stdio open()
|
||||
* mode - mode, as to stdio open()
|
||||
* Returns: handle, for use in functions accessing the opened file.
|
||||
* If failed, errno is set and handle is -1.
|
||||
*/
|
||||
uio_Handle *
|
||||
stdio_open(uio_PDirHandle *pDirHandle, const char *file, int flags,
|
||||
mode_t mode) {
|
||||
stdio_Handle *handle;
|
||||
char *path;
|
||||
int fd;
|
||||
|
||||
path = joinPaths(stdio_getPath(pDirHandle->extra), file);
|
||||
if (path == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd = open(path, flags, mode);
|
||||
if (fd == -1) {
|
||||
int save_errno;
|
||||
|
||||
save_errno = errno;
|
||||
uio_free(path);
|
||||
errno = save_errno;
|
||||
return NULL;
|
||||
}
|
||||
uio_free(path);
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
if (uio_GPDir_getGPDirEntry(pDirHandle->extra, file) == NULL)
|
||||
stdio_addFile(pDirHandle->extra, file);
|
||||
}
|
||||
|
||||
handle = uio_malloc(sizeof (stdio_Handle));
|
||||
handle->fd = fd;
|
||||
|
||||
return uio_Handle_new(pDirHandle->pRoot, handle, flags);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
stdio_read(uio_Handle *handle, void *buf, size_t count) {
|
||||
return read(handle->native->fd, buf, count);
|
||||
}
|
||||
|
||||
int
|
||||
stdio_rmdir(uio_PDirHandle *pDirHandle, const char *name) {
|
||||
char *path;
|
||||
int result;
|
||||
|
||||
path = joinPaths(stdio_getPath(pDirHandle->extra), name);
|
||||
if (path == NULL) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = rmdir(path);
|
||||
if (result == -1) {
|
||||
int saveErrno = errno;
|
||||
uio_free(path);
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uio_free(path);
|
||||
|
||||
uio_GPDir_removeSubDir(pDirHandle->extra, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
off_t
|
||||
stdio_seek(uio_Handle *handle, off_t offset, int whence) {
|
||||
return lseek(handle->native->fd, offset, whence);
|
||||
}
|
||||
|
||||
int
|
||||
stdio_write(uio_Handle *handle, const void *buf, size_t count) {
|
||||
return write(handle->native->fd, buf, count);
|
||||
}
|
||||
|
||||
int
|
||||
stdio_unlink(uio_PDirHandle *pDirHandle, const char *name) {
|
||||
char *path;
|
||||
int result;
|
||||
|
||||
path = joinPaths(stdio_getPath(pDirHandle->extra), name);
|
||||
if (path == NULL) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = unlink(path);
|
||||
if (result == -1) {
|
||||
int saveErrno = errno;
|
||||
uio_free(path);
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uio_free(path);
|
||||
|
||||
uio_GPDir_removeFile(pDirHandle->extra, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uio_PDirEntryHandle *
|
||||
stdio_getPDirEntryHandle(const uio_PDirHandle *pDirHandle, const char *name) {
|
||||
uio_PDirEntryHandle *result;
|
||||
const char *pathUpTo;
|
||||
char *path;
|
||||
struct stat statBuf;
|
||||
#ifdef WIN32
|
||||
char driveName[3];
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
if (pDirHandle->extra->extra->upDir == NULL) {
|
||||
// Top dir. Contains only drive letters.
|
||||
if (!isalpha(name[0]) || name[1] != ':' || name[2] != '\0')
|
||||
return NULL;
|
||||
driveName[0] = tolower(name[0]);
|
||||
driveName[1] = ':';
|
||||
driveName[2] = '\0';
|
||||
name = driveName;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = uio_GPDir_getPDirEntryHandle(pDirHandle, name);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
#ifdef WIN32
|
||||
if (name == driveName) {
|
||||
// Need to create a 'directory' for the drive letter.
|
||||
// It's no problem if we happen to create a dir for a non-existing
|
||||
// drive. It should just produce an empty dir.
|
||||
uio_GPDir *gPDir;
|
||||
|
||||
gPDir = stdio_addDir(pDirHandle->extra, name);
|
||||
uio_GPDir_ref(gPDir);
|
||||
return (uio_PDirEntryHandle *) uio_PDirHandle_new(
|
||||
pDirHandle->pRoot, gPDir);
|
||||
}
|
||||
#endif
|
||||
|
||||
pathUpTo = stdio_getPath(pDirHandle->extra);
|
||||
if (pathUpTo == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
path = joinPaths(pathUpTo, name);
|
||||
if (path == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stat(path, &statBuf) == -1) {
|
||||
uio_free(path);
|
||||
return NULL;
|
||||
}
|
||||
uio_free(path);
|
||||
|
||||
if (S_ISREG(statBuf.st_mode)) {
|
||||
uio_GPFile *gPFile;
|
||||
|
||||
gPFile = stdio_addFile(pDirHandle->extra, name);
|
||||
uio_GPFile_ref(gPFile);
|
||||
return (uio_PDirEntryHandle *) uio_PFileHandle_new(
|
||||
pDirHandle->pRoot, gPFile);
|
||||
} else if (S_ISDIR(statBuf.st_mode)) {
|
||||
uio_GPDir *gPDir;
|
||||
|
||||
gPDir = stdio_addDir(pDirHandle->extra, name);
|
||||
uio_GPDir_ref(gPDir);
|
||||
return (uio_PDirEntryHandle *) uio_PDirHandle_new(
|
||||
pDirHandle->pRoot, gPDir);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Warning: Attempt to access '%s' from '%s', "
|
||||
"which is not a regular file, nor a directory.\n", name,
|
||||
pathUpTo);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uio_PRoot *
|
||||
stdio_mount(uio_Handle *handle, int flags) {
|
||||
uio_PRoot *result;
|
||||
stdio_GPDirData *extra;
|
||||
|
||||
assert (handle == NULL);
|
||||
extra = stdio_GPDirData_new(
|
||||
uio_strdup("") /* name */,
|
||||
#ifdef WIN32
|
||||
// In MS Windows, full paths start with a drive letter.
|
||||
uio_strdup("") /* cached path */,
|
||||
#else
|
||||
uio_strdup("/") /* cached path */,
|
||||
#endif
|
||||
NULL /* parent dir */);
|
||||
|
||||
result = uio_GPRoot_makePRoot(
|
||||
uio_getFileSystemHandler(uio_FSTYPE_STDIO), flags,
|
||||
&stdio_GPRootOperations, NULL, uio_GPRoot_PERSISTENT,
|
||||
handle, extra, 0);
|
||||
|
||||
uio_GPDir_setComplete(result->rootDir->extra, true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
stdio_EntriesIterator *
|
||||
stdio_openEntries(uio_PDirHandle *pDirHandle) {
|
||||
const char *dirPath;
|
||||
char path[PATH_MAX];
|
||||
char *pathEnd;
|
||||
size_t dirPathLen;
|
||||
stdio_EntriesIterator *iterator;
|
||||
|
||||
// uio_GPDir_access(pDirHandle->extra);
|
||||
|
||||
dirPath = stdio_getPath(pDirHandle->extra);
|
||||
if (dirPath == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dirPathLen = strlen(dirPath);
|
||||
if (dirPathLen > PATH_MAX - 3) {
|
||||
// dirPath ++ '/' ++ '*' ++ '\0'
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(path, dirPath, dirPathLen);
|
||||
pathEnd = path + dirPathLen;
|
||||
pathEnd[0] = '/';
|
||||
pathEnd[1] = '*';
|
||||
pathEnd[2] = '\0';
|
||||
iterator = stdio_EntriesIterator_new(0);
|
||||
iterator->dirHandle = _findfirst(path, &iterator->findData);
|
||||
if (iterator->dirHandle == 1) {
|
||||
if (errno != ENOENT) {
|
||||
stdio_EntriesIterator_delete(iterator);
|
||||
return NULL;
|
||||
}
|
||||
iterator->status = 1;
|
||||
} else
|
||||
iterator->status = 0;
|
||||
return iterator;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
stdio_EntriesIterator *
|
||||
stdio_openEntries(uio_PDirHandle *pDirHandle) {
|
||||
const char *dirPath;
|
||||
DIR *dirHandle;
|
||||
stdio_EntriesIterator *result;
|
||||
|
||||
// uio_GPDir_access(pDirHandle->extra);
|
||||
|
||||
dirPath = stdio_getPath(pDirHandle->extra);
|
||||
if (dirPath == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dirHandle = opendir(dirPath);
|
||||
if (dirHandle == NULL) {
|
||||
// errno is set;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = stdio_EntriesIterator_new(dirHandle);
|
||||
result->status = readdir_r(dirHandle, result->direntBuffer,
|
||||
&result->entry);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// the start of 'buf' will be filled with pointers to strings
|
||||
// those strings are stored elsewhere in buf.
|
||||
// The function returns the number of strings passed along, or -1 for error.
|
||||
// If there are no more entries, the last pointer will be NULL.
|
||||
// (this pointer counts towards the return value)
|
||||
int
|
||||
stdio_readEntries(stdio_EntriesIterator **iteratorPtr,
|
||||
char *buf, size_t len) {
|
||||
char *end;
|
||||
char **start;
|
||||
int num;
|
||||
const char *name;
|
||||
size_t nameLen;
|
||||
stdio_EntriesIterator *iterator;
|
||||
|
||||
iterator = *iteratorPtr;
|
||||
|
||||
// buf will be filled like this:
|
||||
// The start of buf will contain pointers to char *,
|
||||
// the end will contain the actual char[] that those pointers point to.
|
||||
// The start and the end will grow towards eachother.
|
||||
start = (char **) buf;
|
||||
end = buf + len;
|
||||
num = 0;
|
||||
#ifdef WIN32
|
||||
for (; iterator->status == 0;
|
||||
iterator->status = _findnext(iterator->dirHandle,
|
||||
&iterator->findData))
|
||||
#else
|
||||
for (; iterator->status == 0 && iterator->entry != NULL;
|
||||
iterator->status = readdir_r(iterator->dirHandle,
|
||||
iterator->direntBuffer, &iterator->entry))
|
||||
#endif
|
||||
{
|
||||
#ifdef WIN32
|
||||
name = iterator->findData.name;
|
||||
#else
|
||||
name = iterator->entry->d_name;
|
||||
#endif
|
||||
if (name[0] == '.' &&
|
||||
(name[1] == '\0' ||
|
||||
(name[1] == '.' && name[2] == '\0'))) {
|
||||
// skip directories "." and ".."
|
||||
continue;
|
||||
}
|
||||
nameLen = strlen(name) + 1;
|
||||
|
||||
// Does this work with systems that need memory access to be
|
||||
// aligned on a certain number of bytes?
|
||||
if ((size_t) (sizeof (char *) + nameLen) >
|
||||
(size_t) (end - (char *) start)) {
|
||||
// Not enough room to fit the pointer (at the beginning) and
|
||||
// the string (at the end).
|
||||
return num;
|
||||
}
|
||||
end -= nameLen;
|
||||
memcpy(end, name, nameLen);
|
||||
*start = end;
|
||||
start++;
|
||||
num++;
|
||||
}
|
||||
#ifndef WIN32
|
||||
# ifdef DEBUG
|
||||
if (iterator->status != 0) {
|
||||
fprintf(stderr, "Warning: readdir() failed: %s\n",
|
||||
strerror(iterator->status));
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (sizeof (char *) > (size_t) (end - (char *) start)) {
|
||||
// not enough room to fit the NULL pointer.
|
||||
// It will have to be reported seperately the next time.
|
||||
return num;
|
||||
}
|
||||
*start = NULL;
|
||||
num++;
|
||||
return num;
|
||||
}
|
||||
|
||||
void
|
||||
stdio_closeEntries(stdio_EntriesIterator *iterator) {
|
||||
#ifdef WIN32
|
||||
_findclose(iterator->dirHandle);
|
||||
#else
|
||||
closedir(iterator->dirHandle);
|
||||
#endif
|
||||
stdio_EntriesIterator_delete(iterator);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
stdio_EntriesIterator *
|
||||
stdio_EntriesIterator_new(long dirHandle) {
|
||||
stdio_EntriesIterator *result;
|
||||
|
||||
result = stdio_EntriesIterator_alloc();
|
||||
result->dirHandle = dirHandle;
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
stdio_EntriesIterator *
|
||||
stdio_EntriesIterator_new(DIR *dirHandle) {
|
||||
stdio_EntriesIterator *result;
|
||||
|
||||
result = stdio_EntriesIterator_alloc();
|
||||
result->dirHandle = dirHandle;
|
||||
|
||||
// Linux's and FreeBSD's struct dirent are defined with a
|
||||
// maximum d_name field (NAME_MAX).
|
||||
// However, POSIX doesn't require this, and in fact
|
||||
// at least QNX defines struct dirent with an empty d_name field.
|
||||
// This should take care of it:
|
||||
result->direntBuffer = uio_malloc(
|
||||
sizeof (struct dirent)
|
||||
- ((sizeof (((struct dirent *) 0)->d_name) + 3) & 3)
|
||||
+ (((NAME_MAX + 1) + 3) & 3));
|
||||
// Take the length of the dirent structure as it is defined,
|
||||
// subtract the length of the d_name field, and add the length
|
||||
// of the maximum length d_name field (NAME_MAX plus 1 for
|
||||
// the '\0').
|
||||
// The '(... +3) & 3' is to take into account that fields
|
||||
// will be aligned on 4 bytes.
|
||||
// (What about 64 bits machines?)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
stdio_EntriesIterator_delete(stdio_EntriesIterator *iterator) {
|
||||
#ifndef WIN32
|
||||
uio_free(iterator->direntBuffer);
|
||||
#endif
|
||||
stdio_EntriesIterator_free(iterator);
|
||||
}
|
||||
|
||||
static inline stdio_EntriesIterator *
|
||||
stdio_EntriesIterator_alloc(void) {
|
||||
return uio_malloc(sizeof (stdio_EntriesIterator));
|
||||
}
|
||||
|
||||
static inline void
|
||||
stdio_EntriesIterator_free(stdio_EntriesIterator *iterator) {
|
||||
uio_free(iterator);
|
||||
}
|
||||
|
||||
static inline uio_GPFile *
|
||||
stdio_addFile(uio_GPDir *gPDir, const char *fileName) {
|
||||
uio_GPFile *file;
|
||||
|
||||
file = uio_GPFile_new(gPDir->pRoot, NULL,
|
||||
uio_gPFileFlagsFromPRootFlags(gPDir->pRoot->flags));
|
||||
uio_GPDir_addFile(gPDir, fileName, file);
|
||||
return file;
|
||||
}
|
||||
|
||||
// called by fillGPDir when a subdir is found
|
||||
static inline uio_GPDir *
|
||||
stdio_addDir(uio_GPDir *gPDir, const char *dirName) {
|
||||
uio_GPDir *subDir;
|
||||
|
||||
subDir = uio_GPDir_prepareSubDir(gPDir, dirName);
|
||||
if (subDir->extra == NULL) {
|
||||
// It's a new dir, we'll need to add our own data.
|
||||
uio_GPDir_ref(gPDir);
|
||||
subDir->extra = stdio_GPDirData_new(uio_strdup(dirName),
|
||||
NULL, gPDir);
|
||||
uio_GPDir_setComplete(subDir, true);
|
||||
// fillPDir should not be called.
|
||||
}
|
||||
uio_GPDir_commitSubDir(gPDir, dirName, subDir);
|
||||
return subDir;
|
||||
}
|
||||
|
||||
// returns a pointer to gPDir->extra->cachedPath
|
||||
// pointer should not be stored, the memory it points to can be freed
|
||||
// lateron. TODO: not threadsafe.
|
||||
static char *
|
||||
stdio_getPath(uio_GPDir *gPDir) {
|
||||
if (gPDir->extra->cachedPath == NULL) {
|
||||
char *upPath;
|
||||
size_t upPathLen, nameLen;
|
||||
|
||||
if (gPDir->extra->upDir == NULL) {
|
||||
#ifdef WIN32
|
||||
// Drive letter still needs to follow follow.
|
||||
gPDir->extra->cachedPath = uio_malloc(1);
|
||||
gPDir->extra->cachedPath[0] = '\0';
|
||||
#else
|
||||
gPDir->extra->cachedPath = uio_malloc(2);
|
||||
gPDir->extra->cachedPath[0] = '/';
|
||||
gPDir->extra->cachedPath[1] = '\0';
|
||||
#endif
|
||||
return gPDir->extra->cachedPath;
|
||||
}
|
||||
|
||||
upPath = stdio_getPath(gPDir->extra->upDir);
|
||||
if (upPath == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (upPath[0] == '\0') {
|
||||
// The up dir is the root dir. Directly below the root dir are
|
||||
// only dirs for drive letters. No '/' needs to be attached.
|
||||
gPDir->extra->cachedPath = uio_strdup(gPDir->extra->name);
|
||||
return gPDir->extra->cachedPath;
|
||||
}
|
||||
#endif
|
||||
upPathLen = strlen(upPath);
|
||||
#ifndef WIN32
|
||||
if (upPath[upPathLen - 1] == '/') {
|
||||
// should only happen for "/"
|
||||
upPathLen--;
|
||||
}
|
||||
#endif
|
||||
nameLen = strlen(gPDir->extra->name);
|
||||
if (upPathLen + nameLen + 1 >= PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
gPDir->extra->cachedPath = uio_malloc(upPathLen + nameLen + 2);
|
||||
memcpy(gPDir->extra->cachedPath, upPath, upPathLen);
|
||||
gPDir->extra->cachedPath[upPathLen] = '/';
|
||||
memcpy(gPDir->extra->cachedPath + upPathLen + 1,
|
||||
gPDir->extra->name, nameLen);
|
||||
gPDir->extra->cachedPath[upPathLen + nameLen + 1] = '\0';
|
||||
}
|
||||
return gPDir->extra->cachedPath;
|
||||
}
|
||||
|
||||
static stdio_GPDirData *
|
||||
stdio_GPDirData_new(char *name, char *cachedPath, uio_GPDir *upDir) {
|
||||
stdio_GPDirData *result;
|
||||
|
||||
result = stdio_GPDirData_alloc();
|
||||
result->name = name;
|
||||
result->cachedPath = cachedPath;
|
||||
result->upDir = upDir;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
stdio_GPDirData_delete(stdio_GPDirData *gPDirData) {
|
||||
if (gPDirData->upDir != NULL)
|
||||
uio_GPDir_unref(gPDirData->upDir);
|
||||
stdio_GPDirData_free(gPDirData);
|
||||
}
|
||||
|
||||
static inline stdio_GPDirData *
|
||||
stdio_GPDirData_alloc(void) {
|
||||
stdio_GPDirData *result;
|
||||
|
||||
result = uio_malloc(sizeof (stdio_GPDirData));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(stdio_GPDirData, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
stdio_GPDirData_free(stdio_GPDirData *gPDirData) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(stdio_GPDirData, (void *) gPDirData);
|
||||
#endif
|
||||
uio_free(gPDirData->name);
|
||||
if (gPDirData->cachedPath != NULL)
|
||||
uio_free(gPDirData->cachedPath);
|
||||
uio_free(gPDirData);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct stdio_Handle *uio_NativeHandle;
|
||||
typedef void *uio_GPRootExtra;
|
||||
typedef struct stdio_GPDirData *uio_GPDirExtra;
|
||||
typedef void *uio_GPFileExtra;
|
||||
typedef struct stdio_EntriesIterator stdio_EntriesIterator;
|
||||
typedef stdio_EntriesIterator *uio_NativeEntriesContext;
|
||||
|
||||
|
||||
#define uio_INTERNAL_PHYSICAL
|
||||
|
||||
#include "../gphys.h"
|
||||
#include "../iointrn.h"
|
||||
#include "../uioport.h"
|
||||
#include "../fstypes.h"
|
||||
#include "../physical.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#ifndef WIN32
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct stdio_GPDirData {
|
||||
// The reason that names are stored is that in the system filesystem
|
||||
// you need names to refer to files and directories.
|
||||
// (you could keep a file descriptor to each one, but that would
|
||||
// mean a lot of open file descriptors, and for some it won't even
|
||||
// be enough).
|
||||
// This is not needed for all filesystems; therefor this info is not
|
||||
// in uio_GPDir itself.
|
||||
// The reasons for including upDir here are similar.
|
||||
char *name;
|
||||
char *cachedPath;
|
||||
uio_GPDir *upDir;
|
||||
} stdio_GPDirData;
|
||||
|
||||
typedef struct stdio_Handle {
|
||||
int fd;
|
||||
} stdio_Handle;
|
||||
|
||||
#ifdef WIN32
|
||||
struct stdio_EntriesIterator {
|
||||
long dirHandle;
|
||||
struct _finddata_t findData;
|
||||
int status;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
struct stdio_EntriesIterator {
|
||||
DIR *dirHandle;
|
||||
struct dirent *entry;
|
||||
struct dirent *direntBuffer;
|
||||
int status;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
uio_PRoot *stdio_mount(uio_Handle *handle, int flags);
|
||||
int stdio_umount(uio_PRoot *);
|
||||
uio_PDirHandle *stdio_mkdir(uio_PDirHandle *pDirHandle, const char *name,
|
||||
mode_t mode);
|
||||
uio_Handle *stdio_open(uio_PDirHandle *pDirHandle, const char *file, int flags,
|
||||
mode_t mode);
|
||||
void stdio_close(uio_Handle *handle);
|
||||
int stdio_fstat(uio_Handle *handle, struct stat *statBuf);
|
||||
int stdio_stat(uio_PDirHandle *pDirHandle, const char *name,
|
||||
struct stat *statBuf);
|
||||
ssize_t stdio_read(uio_Handle *handle, void *buf, size_t count);
|
||||
int stdio_rmdir(uio_PDirHandle *pDirHandle, const char *name);
|
||||
off_t stdio_seek(uio_Handle *handle, off_t offset, int whence);
|
||||
int stdio_write(uio_Handle *handle, const void *buf, size_t count);
|
||||
int stdio_unlink(uio_PDirHandle *pDirHandle, const char *name);
|
||||
|
||||
stdio_EntriesIterator *stdio_openEntries(uio_PDirHandle *pDirHandle);
|
||||
int stdio_readEntries(stdio_EntriesIterator **iterator,
|
||||
char *buf, size_t len);
|
||||
void stdio_closeEntries(stdio_EntriesIterator *iterator);
|
||||
#ifdef WIN32
|
||||
stdio_EntriesIterator *stdio_EntriesIterator_new(long dirHandle);
|
||||
#else
|
||||
stdio_EntriesIterator *stdio_EntriesIterator_new(DIR *dirHandle);
|
||||
#endif
|
||||
void stdio_EntriesIterator_delete(stdio_EntriesIterator *iterator);
|
||||
uio_PDirEntryHandle *stdio_getPDirEntryHandle(
|
||||
const uio_PDirHandle *pDirHandle, const char *name);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _uio_TYPES_H
|
||||
#define _uio_TYPES_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
false = 0,
|
||||
true
|
||||
} uio_bool;
|
||||
|
||||
typedef unsigned char uio_uint8;
|
||||
typedef signed char uio_sint8;
|
||||
typedef unsigned short uio_uint16;
|
||||
typedef signed short uio_sint16;
|
||||
typedef unsigned int uio_uint32;
|
||||
typedef signed int uio_sint32;
|
||||
|
||||
typedef unsigned long uio_uintptr;
|
||||
// Needs to be adapted for 64 bits systems
|
||||
|
||||
#endif /* _uio_TYPES_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UIOPORT_H
|
||||
#define _UIOPORT_H
|
||||
|
||||
#ifdef WIN32
|
||||
# include <stdlib.h>
|
||||
# define PATH_MAX _MAX_PATH
|
||||
# define NAME_MAX _MAX_FNAME
|
||||
// _MAX_DIR and FILENAME_MAX could also be candidates.
|
||||
// If anyone can tell me which one matches NAME_MAX, please
|
||||
// let me know.
|
||||
# define inline __inline
|
||||
typedef short uid_t;
|
||||
typedef short gid_t;
|
||||
#else
|
||||
# include <limits.h>
|
||||
/* PATH_MAX is per POSIX defined in <limits.h> */
|
||||
# define inline __inline__
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
# include <io.h>
|
||||
#define mkdir MS_INSANE_MKDIR
|
||||
// direct.h would give a bad definition of mkdir(). Now it gives
|
||||
// a bad definition of MS_INSANE_MKDIR(), which we won't use.
|
||||
// Yes, it's a hack, but this way the hack will stay local to
|
||||
// the MS-specific stuff.
|
||||
# include <direct.h>
|
||||
#undef mkdir
|
||||
# include <sys/stat.h>
|
||||
typedef int ssize_t;
|
||||
typedef unsigned short mode_t;
|
||||
# define access _access
|
||||
# define F_OK 0
|
||||
# define W_OK 2
|
||||
# define R_OK 4
|
||||
# define open _open
|
||||
static inline int
|
||||
mkdir(const char *pathname, mode_t mode) {
|
||||
(void) mode;
|
||||
return _mkdir(pathname);
|
||||
}
|
||||
# define read _read
|
||||
# define rmdir _rmdir
|
||||
# define lseek _lseek
|
||||
# define lstat _lstat
|
||||
# define fstat _fstat
|
||||
# define S_IRUSR S_IREAD
|
||||
# define S_IWUSR S_IWRITE
|
||||
# define S_IXUSR S_IEXEC
|
||||
# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
|
||||
# define S_IRGRP 0
|
||||
# define S_IWGRP 0
|
||||
# define S_IXGRP 0
|
||||
# define S_IROTH 0
|
||||
# define S_IWOTH 0
|
||||
# define S_IXOTH 0
|
||||
# define S_IRWXG 0
|
||||
# define S_IRWXO 0
|
||||
# define S_ISUID 0
|
||||
# define S_ISGID 0
|
||||
# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
|
||||
# define S_IFMT _S_IFMT
|
||||
# define S_IFREG _S_IFREG
|
||||
# define S_IFCHR _S_IFCHR
|
||||
# define S_IFDIR _S_IFDIR
|
||||
# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISREG(mode) (((mode) & _S_IFMT) == _S_IFREG)
|
||||
# define write _write
|
||||
# define stat _stat
|
||||
# define unlink _unlink
|
||||
#elif defined (__MINGW32__)
|
||||
typedef int ssize_t;
|
||||
typedef unsigned short mode_t;
|
||||
# define S_IRUSR S_IREAD
|
||||
# define S_IWUSR S_IWRITE
|
||||
# define S_IXUSR S_IEXEC
|
||||
# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
|
||||
# define S_IRGRP 0
|
||||
# define S_IWGRP 0
|
||||
# define S_IXGRP 0
|
||||
# define S_IROTH 0
|
||||
# define S_IWOTH 0
|
||||
# define S_IXOTH 0
|
||||
# define S_IRWXG 0
|
||||
# define S_IRWXO 0
|
||||
# define S_ISUID 0
|
||||
# define S_ISGID 0
|
||||
# define S_IFMT _S_IFMT
|
||||
# define S_IFREG _S_IFREG
|
||||
# define S_IFCHR _S_IFCHR
|
||||
# define S_IFDIR _S_IFDIR
|
||||
# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISREG(mode) (((mode) & _S_IFMT) == _S_IFREG)
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _UIOPORT_H */
|
||||
|
||||
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uioport.h"
|
||||
#include "iointrn.h"
|
||||
#include "uiostream.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "uioutils.h"
|
||||
#ifdef uio_MEM_DEBUG
|
||||
# include "memdebug.h"
|
||||
#endif
|
||||
|
||||
#define uio_Stream_BLOCK_SIZE 1024
|
||||
// The alignment of file reads as well as the buffer size.
|
||||
#define uio_Stream_BLOCK_PAGE_START(offset) \
|
||||
((offset) & ~(uio_Stream_BLOCK_SIZE - 1))
|
||||
|
||||
static inline uio_Stream *uio_Stream_new(uio_Handle *handle, int openFlags);
|
||||
static inline void uio_Stream_delete(uio_Stream *stream);
|
||||
static inline uio_Stream *uio_Stream_alloc(void);
|
||||
static inline void uio_Stream_free(uio_Stream *stream);
|
||||
static int uio_Stream_fillReadBuffer(uio_Stream *stream);
|
||||
static int uio_Stream_alignReadBuffer(uio_Stream *stream);
|
||||
static int uio_Stream_flushWriteBuffer(uio_Stream *stream);
|
||||
|
||||
|
||||
uio_Stream *
|
||||
uio_fopen(uio_DirHandle *dir, const char *path, const char *mode) {
|
||||
int openFlags;
|
||||
uio_Handle *handle;
|
||||
uio_Stream *stream;
|
||||
|
||||
switch (*mode) {
|
||||
case 'r':
|
||||
openFlags = O_RDONLY;
|
||||
break;
|
||||
case 'w':
|
||||
openFlags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
break;
|
||||
case 'a':
|
||||
openFlags = O_WRONLY| O_CREAT | O_APPEND;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
fprintf(stderr, "Invalid mode string in call to uio_fopen().\n");
|
||||
return NULL;
|
||||
}
|
||||
mode++;
|
||||
|
||||
// 'b' may either be the second or the third character.
|
||||
if (*mode == 'b') {
|
||||
mode++;
|
||||
#ifdef WIN32
|
||||
openFlags |= O_BINARY;
|
||||
#endif
|
||||
if (*mode == '+') {
|
||||
mode++;
|
||||
openFlags = (openFlags & ~O_ACCMODE) | O_RDWR;
|
||||
}
|
||||
} else
|
||||
if (*mode == '+') {
|
||||
mode++;
|
||||
openFlags = (openFlags & ~O_ACCMODE) | O_RDWR;
|
||||
}
|
||||
|
||||
// Any characters in the mode string that might follow are ignored.
|
||||
|
||||
handle = uio_open(dir, path, openFlags, S_IRUSR | S_IWUSR |
|
||||
S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (handle == NULL) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream = uio_Stream_new(handle, openFlags);
|
||||
return stream;
|
||||
}
|
||||
|
||||
int
|
||||
uio_fclose(uio_Stream *stream) {
|
||||
if (stream->writeStart != NULL)
|
||||
uio_Stream_flushWriteBuffer(stream);
|
||||
uio_close(stream->handle);
|
||||
uio_Stream_delete(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If less than nmembs could be read, or an error occurs, the file pointer
|
||||
// is undefined. clearerr() followed by fseek() need to be called before
|
||||
// attempting to read or write again.
|
||||
// I don't have the C standard myself, but I suspect this is the
|
||||
// official behaviour for fread() and fwrite().
|
||||
size_t
|
||||
uio_fread(void *buf, size_t size, size_t nmemb, uio_Stream *stream) {
|
||||
size_t bytesToRead;
|
||||
size_t bytesRead;
|
||||
|
||||
bytesToRead = size * nmemb;
|
||||
bytesRead = 0;
|
||||
|
||||
assert((stream->openFlags & O_ACCMODE) != O_WRONLY);
|
||||
if (stream->writeStart != NULL) {
|
||||
if (uio_Stream_flushWriteBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (stream->readEnd - stream->bufPtr > 0) {
|
||||
// First use what's in the buffer.
|
||||
size_t numRead;
|
||||
|
||||
numRead = minu(stream->readEnd - stream->bufPtr, bytesToRead);
|
||||
memcpy(buf, stream->bufPtr, numRead);
|
||||
(char *) buf += numRead;
|
||||
stream->bufPtr += numRead;
|
||||
bytesToRead -= numRead;
|
||||
bytesRead += numRead;
|
||||
}
|
||||
if (bytesToRead == 0) {
|
||||
// Done already
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
{
|
||||
ssize_t numRead;
|
||||
numRead = uio_read(stream->handle, buf, bytesToRead);
|
||||
if (numRead == -1) {
|
||||
stream->status = uio_Stream_STATUS_ERROR;
|
||||
goto out;
|
||||
}
|
||||
bytesRead += numRead;
|
||||
stream->seekLow += numRead;
|
||||
if ((size_t) numRead < bytesToRead) {
|
||||
// End of file
|
||||
stream->status = uio_Stream_STATUS_EOF;
|
||||
goto out;
|
||||
}
|
||||
uio_Stream_alignReadBuffer(stream);
|
||||
}
|
||||
|
||||
out:
|
||||
if (bytesToRead == 0)
|
||||
return nmemb;
|
||||
return bytesRead / size;
|
||||
}
|
||||
|
||||
char *
|
||||
uio_fgets(char *s, int size, uio_Stream *stream) {
|
||||
int orgSize;
|
||||
char *buf;
|
||||
|
||||
assert((stream->openFlags & O_ACCMODE) != O_WRONLY);
|
||||
|
||||
if (stream->writeStart != NULL) {
|
||||
if (uio_Stream_flushWriteBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size--;
|
||||
orgSize = size;
|
||||
buf = s;
|
||||
while (size > 0) {
|
||||
size_t maxRead;
|
||||
const char *newLinePos;
|
||||
|
||||
// Fill buffer if empty.
|
||||
if (stream->bufPtr >= stream->readEnd) {
|
||||
if (uio_Stream_fillReadBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
stream->status = uio_Stream_STATUS_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
if (stream->bufPtr == stream->readEnd) {
|
||||
// End-of-file
|
||||
stream->status = uio_Stream_STATUS_EOF;
|
||||
if (size == orgSize) {
|
||||
// Nothing was read.
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (stream->bufPtr < stream->readEnd);
|
||||
|
||||
// Search in buffer
|
||||
maxRead = minu(stream->readEnd - stream->bufPtr, size);
|
||||
newLinePos = memchr(stream->bufPtr, '\n', maxRead);
|
||||
if (newLinePos != NULL) {
|
||||
// Newline found.
|
||||
maxRead = newLinePos + 1 - stream->bufPtr;
|
||||
memcpy(buf, stream->bufPtr, maxRead);
|
||||
stream->bufPtr += maxRead;
|
||||
buf[maxRead] = '\0';
|
||||
return buf;
|
||||
}
|
||||
// No newline present.
|
||||
memcpy(buf, stream->bufPtr, maxRead);
|
||||
stream->bufPtr += maxRead;
|
||||
buf += maxRead;
|
||||
size -= maxRead;
|
||||
}
|
||||
|
||||
*buf = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
uio_fgetc(uio_Stream *stream) {
|
||||
int result;
|
||||
|
||||
assert((stream->openFlags & O_ACCMODE) != O_WRONLY);
|
||||
|
||||
if (stream->writeStart != NULL) {
|
||||
if (uio_Stream_flushWriteBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->bufPtr >= stream->readEnd) {
|
||||
if (uio_Stream_fillReadBuffer(stream) == -1) {
|
||||
stream->status = uio_Stream_STATUS_ERROR;
|
||||
return (int) EOF;
|
||||
}
|
||||
if (stream->bufPtr == stream->readEnd) {
|
||||
// End-of-file
|
||||
stream->status = uio_Stream_STATUS_EOF;
|
||||
return (int) EOF;
|
||||
}
|
||||
}
|
||||
assert(stream->bufPtr < stream->readEnd);
|
||||
|
||||
result = (int) *((unsigned char *) stream->bufPtr);
|
||||
stream->bufPtr++;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Only one character pushback is guaranteed, just like with stdio ungetc().
|
||||
int
|
||||
uio_ungetc(int c, uio_Stream *stream) {
|
||||
assert((stream->openFlags & O_ACCMODE) != O_WRONLY);
|
||||
assert(c >= 0 && c <= 255);
|
||||
|
||||
return (int) EOF;
|
||||
// not implemented
|
||||
// return c;
|
||||
}
|
||||
|
||||
int
|
||||
uio_fputc(int c, uio_Stream *stream) {
|
||||
assert((stream->openFlags & O_ACCMODE) != O_RDONLY);
|
||||
assert(c >= 0 && c <= 255);
|
||||
|
||||
if (stream->writeStart == NULL)
|
||||
stream->writeStart = stream->bufPtr;
|
||||
if (stream->bufPtr == stream->bufEnd) {
|
||||
// The buffer is full. Flush it out.
|
||||
if (uio_Stream_flushWriteBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
*(unsigned char *) stream->bufPtr = (unsigned char) c;
|
||||
stream->bufPtr++;
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
uio_fputs(const char *s, uio_Stream *stream) {
|
||||
int result;
|
||||
|
||||
result = uio_fwrite(s, strlen(s), 1, stream);
|
||||
if (result != 1)
|
||||
return EOF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uio_fseek(uio_Stream *stream, long offset, int whence) {
|
||||
int newPos;
|
||||
|
||||
if (stream->writeStart != NULL) {
|
||||
if (uio_Stream_flushWriteBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
|
||||
switch(whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
offset += stream->seekLow - (stream->readEnd - stream->bufPtr);
|
||||
break;
|
||||
case SEEK_END: {
|
||||
struct stat statBuf;
|
||||
|
||||
if (uio_fstat(stream->handle, &statBuf) == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
offset += statBuf.st_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: when implementing pushback: throw away pushback buffer.
|
||||
|
||||
// Maybe the new location is still inside the read buffer.
|
||||
// If not, we must throw the buffer away.
|
||||
// If the buffer was polluted from calls to ungetc(),
|
||||
// always throw away the buffer.
|
||||
if (offset >= stream->seekLow - (stream->readEnd - stream->buf) &&
|
||||
offset <= stream->seekLow) {
|
||||
// The buffer can be reused.
|
||||
stream->status = uio_Stream_STATUS_OK;
|
||||
stream->bufPtr = stream->buf +
|
||||
(stream->readEnd - stream->buf) +
|
||||
(offset - stream->seekLow);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The read buffer is not reusable.
|
||||
newPos = uio_lseek(stream->handle, offset, SEEK_SET);
|
||||
if (newPos == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
stream->seekLow = newPos;
|
||||
stream->status = uio_Stream_STATUS_OK;
|
||||
// Clear error or end-of-file flag.
|
||||
stream->bufPtr = stream->buf;
|
||||
stream->readEnd = stream->buf;
|
||||
|
||||
if ((stream->openFlags & O_ACCMODE) == O_RDONLY) {
|
||||
// We're done if there's no writing involved.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uio_Stream_alignReadBuffer(stream) == -1) {
|
||||
// Even when the buffer can't be filled, it might be
|
||||
// a suitable location for writing (for instance, at the end
|
||||
// of the file).
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
uio_ftell(uio_Stream *stream) {
|
||||
return (long) stream->seekLow - (stream->readEnd - stream->bufPtr);
|
||||
}
|
||||
|
||||
// If less that nmemb elements could be written, or an error occurs, the
|
||||
// file pointer is undefined. clearerr() followed by fseek() need to be
|
||||
// called before attempting to read or write again.
|
||||
// I don't have the C standard myself, but I suspect this is the official
|
||||
// behaviour for fread() and fwrite().
|
||||
size_t
|
||||
uio_fwrite(const void *buf, size_t size, size_t nmemb, uio_Stream *stream) {
|
||||
ssize_t bytesToWrite;
|
||||
ssize_t bytesWritten;
|
||||
|
||||
assert((stream->openFlags & O_ACCMODE) != O_RDONLY);
|
||||
|
||||
bytesToWrite = size * nmemb;
|
||||
if (stream->writeStart == NULL)
|
||||
stream->writeStart = stream->bufPtr;
|
||||
if (bytesToWrite < stream->bufEnd - stream->bufPtr) {
|
||||
// There's enough space in the write buffer to store everything.
|
||||
memcpy(stream->bufPtr, buf, bytesToWrite);
|
||||
stream->bufPtr += bytesToWrite;
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
// Not enough space in the write buffer to write everything.
|
||||
// Flush what's left in the write buffer, and then directly write 'buf'.
|
||||
if (uio_Stream_flushWriteBuffer(stream) == -1) {
|
||||
// errno is set
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesWritten = uio_write(stream->handle, buf, bytesToWrite);
|
||||
if (bytesWritten != bytesToWrite) {
|
||||
stream->status = uio_Stream_STATUS_ERROR;
|
||||
if (bytesWritten == -1)
|
||||
return 0;
|
||||
}
|
||||
stream->seekLow += stream->readEnd - stream->bufPtr + bytesWritten;
|
||||
stream->readStart = stream->buf;
|
||||
stream->bufPtr = stream->buf;
|
||||
stream->readEnd = stream->buf;
|
||||
stream->writeStart = NULL;
|
||||
if (bytesWritten == bytesToWrite)
|
||||
return nmemb;
|
||||
return (size_t) bytesWritten / size;
|
||||
}
|
||||
|
||||
// NB: stdio fflush() accepts NULL to flush all streams. uio_flush() does
|
||||
// not.
|
||||
int
|
||||
uio_fflush(uio_Stream *stream) {
|
||||
assert(stream != NULL);
|
||||
assert((stream->openFlags & O_ACCMODE) != O_RDONLY);
|
||||
return uio_Stream_flushWriteBuffer(stream);
|
||||
}
|
||||
|
||||
int
|
||||
uio_feof(uio_Stream *stream) {
|
||||
return stream->status == uio_Stream_STATUS_EOF;
|
||||
}
|
||||
|
||||
int
|
||||
uio_ferror(uio_Stream *stream) {
|
||||
return stream->status == uio_Stream_STATUS_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
uio_clearerr(uio_Stream *stream) {
|
||||
stream->status = uio_Stream_STATUS_OK;
|
||||
}
|
||||
|
||||
// Counterpart of fileno()
|
||||
uio_Handle *
|
||||
uio_streamHandle(uio_Stream *stream) {
|
||||
return stream->handle;
|
||||
}
|
||||
|
||||
static int
|
||||
uio_Stream_flushWriteBuffer(uio_Stream *stream) {
|
||||
ssize_t bytesWritten;
|
||||
off_t newPos;
|
||||
|
||||
newPos = uio_lseek(stream->handle,
|
||||
(off_t) (stream->seekLow - (stream->readEnd - stream->writeStart)),
|
||||
SEEK_SET);
|
||||
if (newPos == -1) {
|
||||
// errno is set
|
||||
return -1;
|
||||
}
|
||||
stream->seekLow = newPos;
|
||||
|
||||
bytesWritten = uio_write(stream->handle, stream->writeStart,
|
||||
stream->bufPtr - stream->writeStart);
|
||||
if (bytesWritten != stream->bufPtr - stream->writeStart) {
|
||||
stream->status = uio_Stream_STATUS_ERROR;
|
||||
if (bytesWritten != -1)
|
||||
stream->seekLow += bytesWritten;
|
||||
return -1;
|
||||
}
|
||||
stream->seekLow += bytesWritten;
|
||||
stream->writeStart = NULL;
|
||||
|
||||
if (stream->bufPtr > stream->readEnd) {
|
||||
stream->readEnd = stream->bufPtr;
|
||||
} else {
|
||||
newPos = uio_lseek(stream->handle,
|
||||
(off_t) (stream->seekLow + (stream->readEnd - stream->bufPtr)),
|
||||
SEEK_SET);
|
||||
if (newPos == -1) {
|
||||
// errno is set
|
||||
// At least keep the internal state consistent so that
|
||||
// a new uio_fseek() (after an uio_clearerr()) can succeed:
|
||||
stream->readEnd = stream->bufPtr;
|
||||
// SeekLow of the buffer is not aligned on a block.
|
||||
return -1;
|
||||
}
|
||||
stream->seekLow = newPos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uio_Stream_fillReadBuffer(uio_Stream *stream) {
|
||||
ssize_t numRead;
|
||||
|
||||
assert(stream->bufPtr == stream->readEnd);
|
||||
|
||||
numRead = uio_read(stream->handle, stream->buf,
|
||||
uio_Stream_BLOCK_SIZE);
|
||||
if (numRead == -1)
|
||||
return -1;
|
||||
stream->bufPtr = stream->buf;
|
||||
stream->readEnd = stream->buf + numRead;
|
||||
stream->seekLow += numRead;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uio_Stream_alignReadBuffer(uio_Stream *stream) {
|
||||
off_t endAlign;
|
||||
ssize_t numRead;
|
||||
|
||||
endAlign = uio_Stream_BLOCK_PAGE_START(stream->seekLow +
|
||||
uio_Stream_BLOCK_SIZE - 1);
|
||||
if (endAlign == stream->seekLow) {
|
||||
// Nothing to do.
|
||||
return 0;
|
||||
}
|
||||
|
||||
numRead = uio_read(stream->handle, stream->buf,
|
||||
endAlign - stream->seekLow);
|
||||
if (numRead == -1)
|
||||
return -1;
|
||||
stream->bufPtr = stream->buf;
|
||||
stream->readEnd = stream->buf + numRead;
|
||||
stream->seekLow += numRead;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uio_Stream *
|
||||
uio_Stream_new(uio_Handle *handle, int openFlags) {
|
||||
uio_Stream *result;
|
||||
|
||||
result = uio_Stream_alloc();
|
||||
result->handle = handle;
|
||||
result->openFlags = openFlags;
|
||||
result->status = uio_Stream_STATUS_OK;
|
||||
result->buf = uio_malloc(uio_Stream_BLOCK_SIZE);
|
||||
result->bufPtr = result->buf;
|
||||
result->readStart = result->buf;
|
||||
result->readEnd = result->buf;
|
||||
result->writeStart = NULL;
|
||||
result->bufEnd = result->buf + uio_Stream_BLOCK_SIZE;
|
||||
result->seekLow = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uio_Stream *
|
||||
uio_Stream_alloc(void) {
|
||||
uio_Stream *result = uio_malloc(sizeof (uio_Stream));
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugAlloc(uio_Stream, (void *) result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_Stream_delete(uio_Stream *stream) {
|
||||
uio_free(stream->buf);
|
||||
uio_Stream_free(stream);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uio_Stream_free(uio_Stream *stream) {
|
||||
#ifdef uio_MEM_DEBUG
|
||||
uio_MemDebug_debugFree(uio_Stream, (void *) stream);
|
||||
#endif
|
||||
uio_free(stream);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Serge van den Boom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _STREAM_H
|
||||
#define _STREAM_H
|
||||
|
||||
|
||||
typedef struct uio_Stream uio_Stream;
|
||||
|
||||
#include "io.h"
|
||||
|
||||
|
||||
uio_Stream *uio_fopen(uio_DirHandle *dir, const char *path, const char *mode);
|
||||
int uio_fclose(uio_Stream *stream);
|
||||
size_t uio_fread(void *buf, size_t size, size_t nmemb, uio_Stream *stream);
|
||||
char *uio_fgets(char *buf, int size, uio_Stream *stream);
|
||||
int uio_fgetc(uio_Stream *stream);
|
||||
#define uio_getc uio_fgetc
|
||||
int uio_ungetc(int c, uio_Stream *stream);
|
||||
int uio_fputc(int c, uio_Stream *stream);
|
||||
#define uio_putc uio_fputc
|
||||
int uio_fputs(const char *s, uio_Stream *stream);
|
||||
int uio_fseek(uio_Stream *stream, long offset, int whence);
|
||||
long uio_ftell(uio_Stream *stream);
|
||||
size_t uio_fwrite(const void *buf, size_t size, size_t nmemb,
|
||||
uio_Stream *stream);
|
||||
int uio_fflush(uio_Stream *stream);
|
||||
int uio_feof(uio_Stream *stream);
|
||||
int uio_ferror(uio_Stream *stream);
|
||||
void uio_clearerr(uio_Stream *stream);
|
||||
uio_Handle *uio_streamHandle(uio_Stream *stream);
|
||||
|
||||
|
||||
/* *** Internal definitions follow *** */
|
||||
#ifdef uio_INTERNAL
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include "iointrn.h"
|
||||
|
||||
/*
|
||||
* Layout of buf:
|
||||
*
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | | | | | | | |D|D|D|D|D|D|D|D| | | | | | | |X|X|X|X|X|X|X|X|X|X|X|X|X|X|
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* ^ ^ ^ ^ ^
|
||||
* +-readStart +-writeStart +-bufPtr +-readEnd bufEnd-+
|
||||
*
|
||||
* buf - start of the buffer
|
||||
* readStart - start of the segment that was read
|
||||
* writeStart - start of the part which is written, or NULL if nothing
|
||||
* written.
|
||||
* bufPtr - file pointer; here new reads or writes are done.
|
||||
* readEnd - end of the part of the file that is pre-read.
|
||||
* bufEnd - end of memory allocated for the buffer.
|
||||
* D - dirty, needs to be written to disk
|
||||
* X - invalid; reserved but not used memory
|
||||
*
|
||||
* Invariants:
|
||||
* buf <= bufPtr <= bufEnd
|
||||
* If writeStart != NULL: buf <= writeStart <= bufPtr <= bufEnd
|
||||
* buf <= readStart <= readEnd <= bufEnd
|
||||
* Note that writeStart and bufPtr may point past readEnd.
|
||||
*
|
||||
*/
|
||||
struct uio_Stream {
|
||||
char *buf;
|
||||
char *bufPtr;
|
||||
char *readStart;
|
||||
// Not really used atm.
|
||||
char *writeStart;
|
||||
char *readEnd;
|
||||
char *bufEnd;
|
||||
off_t seekLow;
|
||||
// Low(er) level file pointer. Always points to the position just
|
||||
// past the part that's in the buffer.
|
||||
uio_Handle *handle;
|
||||
int status;
|
||||
#define uio_Stream_STATUS_OK 0
|
||||
#define uio_Stream_STATUS_EOF 1
|
||||
#define uio_Stream_STATUS_ERROR 2
|
||||
int openFlags;
|
||||
// Flags used for opening the file.
|
||||
};
|
||||
|
||||
|
||||
#endif /* uio_INTERNAL */
|
||||
|
||||
#endif /* _STREAM_H */
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user