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:
meep-eep
2003-07-08 18:17:40 +00:00
parent d97bb2aa03
commit f7c97f2ba7
112 changed files with 13922 additions and 762 deletions
+2 -1
View File
@@ -28,6 +28,7 @@ uqm_INSTALL_LIBDIR="@INSTALL_LIBDIR@"
# Non-exported files only where build.vars is explicitely included. # Non-exported files only where build.vars is explicitely included.
uqm_SOUNDMODULE="@SOUNDMODULE@" uqm_SOUNDMODULE="@SOUNDMODULE@"
uqm_HAVE_OPENGL="@HAVE_OPENGL@" uqm_HAVE_OPENGL="@HAVE_OPENGL@"
uqm_USE_ZIP_IO="@USE_ZIP_IO@"
WINDRES="@WINDRES@" WINDRES="@WINDRES@"
export uqm_SOUNDMODULE uqm_HAVE_OPENGL WINDRES export uqm_SOUNDMODULE uqm_HAVE_OPENGL uqm_USE_ZIP_IO WINDRES
+16 -1
View File
@@ -38,11 +38,12 @@ define_have_header getopt.h
# Describe the menu: # 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_TITLE="Main menu"
MENU_main_ITEM_debug_TYPE=CHOICE MENU_main_ITEM_debug_TYPE=CHOICE
MENU_main_ITEM_graphics_TYPE=CHOICE MENU_main_ITEM_graphics_TYPE=CHOICE
MENU_main_ITEM_sound_TYPE=CHOICE MENU_main_ITEM_sound_TYPE=CHOICE
MENU_main_ITEM_ioformat_TYPE=CHOICE
MENU_main_ITEM_link_TYPE=CHOICE MENU_main_ITEM_link_TYPE=CHOICE
MENU_main_ITEM_install_path_TYPE=MENU MENU_main_ITEM_install_path_TYPE=MENU
@@ -134,6 +135,19 @@ sound_openal_action() {
} }
CHOICE_sound_DEFAULT=mixsdl 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. # Making static binaries is more complicated than this.
# For now, it will have to be done by hand. # For now, it will have to be done by hand.
#CHOICE_link_OPTIONS="static dynamic" #CHOICE_link_OPTIONS="static dynamic"
@@ -185,6 +199,7 @@ substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES
# Make build.vars from build.vars.in, substituting variables. # Make build.vars from build.vars.in, substituting variables.
SUBSTITUTE_VARS="CFLAGS LDFLAGS MAKE DEBUG SOUNDMODULE HAVE_OPENGL \ SUBSTITUTE_VARS="CFLAGS LDFLAGS MAKE DEBUG SOUNDMODULE HAVE_OPENGL \
USE_ZIP_IO \
INSTALL_LIBDIR INSTALL_BINDIR WINDRES" INSTALL_LIBDIR INSTALL_BINDIR WINDRES"
SUBSTITUTE_FILES="build.vars" SUBSTITUTE_FILES="build.vars"
substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES
+5
View File
@@ -125,3 +125,8 @@ case "$OSNAME" in
esac esac
LIB_vorbisfile_VERSION="" LIB_vorbisfile_VERSION=""
LIB_zlib_NAME="zlib"
LIB_zlib_CFLAGS=""
LIB_zlib_LDFLAGS=""
LIB_zlib_VERSION=""
+193 -5
View File
@@ -42,7 +42,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # 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 BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@@ -50,7 +50,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe 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 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" !ELSEIF "$(CFG)" == "UrQuanMasters - Win32 Debug"
@@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # 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 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 BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@@ -74,7 +74,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo /o"UrQuanMasters.bsc" # ADD BSC32 /nologo /o"UrQuanMasters.bsc"
LINK32=link.exe 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 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 # SUBTRACT LINK32 /nodefaultlib
!ENDIF !ENDIF
@@ -220,6 +220,14 @@ SOURCE=..\sc2code\libs\graphics\sdl\rndzoom.c
# End Source File # End Source File
# Begin 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 SOURCE=..\sc2code\libs\graphics\sdl\sdl_common.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@@ -814,8 +822,188 @@ SOURCE=..\sc2code\libs\timelib.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\sc2code\libs\vidlib.h SOURCE=..\sc2code\libs\uio.h
# End Source File # 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 # End Group
# Begin Group "comm" # Begin Group "comm"
+132 -14
View File
@@ -22,11 +22,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include "port.h"
#include "libs/graphics/gfx_common.h" #include "libs/graphics/gfx_common.h"
#include "compiler.h" #include "compiler.h"
#include "options.h" #include "options.h"
#include "file.h" #include "file.h"
#include "config.h" #include "config.h"
#include "libs/uio.h"
int optWhichMusic = OPT_3DO; int optWhichMusic = OPT_3DO;
int optWhichCoarseScan = OPT_3DO; int optWhichCoarseScan = OPT_3DO;
@@ -35,61 +38,176 @@ int optWhichFonts = OPT_PC;
int optSmoothScroll = OPT_PC; int optSmoothScroll = OPT_PC;
int optMeleeScale = TFB_SCALE_TRILINEAR; int optMeleeScale = TFB_SCALE_TRILINEAR;
char *configDir, *saveDir, *meleeDir;
BOOLEAN optSubtitles = TRUE; BOOLEAN optSubtitles = TRUE;
BOOLEAN optStereoSFX = FALSE; 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 void
prepareConfigDir (void) { prepareConfigDir (void) {
configDir = malloc (PATH_MAX - 13); char buf[PATH_MAX];
if (expandPath (configDir, PATH_MAX - 13, CONFIGDIR) == -1) 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 // Doesn't have to be fatal, but might mess up things when saving
// config files. // config files.
fprintf (stderr, "Fatal error: Invalid path to config files.\n"); fprintf (stderr, "Fatal error: Invalid path to config files.\n");
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
configDir = realloc (configDir, strlen (configDir) + 1);
// Create the path upto the config dir, if not already existing. // Create the path upto the config dir, if not already existing.
if (mkdirhier (configDir) == -1) if (mkdirhier (buf) == -1)
exit (EXIT_FAILURE); 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 void
prepareSaveDir (void) { prepareSaveDir (void) {
saveDir = malloc (PATH_MAX - 13); char buf[PATH_MAX];
if (expandPath (saveDir, PATH_MAX - 13, SAVEDIR) == -1) if (expandPath (buf, PATH_MAX - 13, SAVEDIR) == -1)
{ {
// Doesn't have to be fatal, but might mess up things when saving // Doesn't have to be fatal, but might mess up things when saving
// config files. // config files.
fprintf (stderr, "Fatal error: Invalid path to config files.\n"); fprintf (stderr, "Fatal error: Invalid path to config files.\n");
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
saveDir = realloc (saveDir, strlen (saveDir) + 1);
// Create the path upto the save dir, if not already existing. // Create the path upto the save dir, if not already existing.
if (mkdirhier (saveDir) == -1) if (mkdirhier (buf) == -1)
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
//#ifdef DEBUG //#ifdef DEBUG
fprintf(stderr, "Saved games are kept in %s.\n", saveDir); fprintf(stderr, "Saved games are kept in %s.\n", buf);
//#endif //#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 void
prepareMeleeDir (void) { prepareMeleeDir (void) {
meleeDir = malloc (PATH_MAX - 13); char buf[PATH_MAX];
if (expandPath (meleeDir, PATH_MAX - 13, MELEEDIR) == -1)
if (expandPath (buf, PATH_MAX - 13, MELEEDIR) == -1)
{ {
// Doesn't have to be fatal, but might mess up things when saving // Doesn't have to be fatal, but might mess up things when saving
// config files. // config files.
fprintf (stderr, "Fatal error: Invalid path to config files.\n"); fprintf (stderr, "Fatal error: Invalid path to config files.\n");
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
meleeDir = realloc (meleeDir, strlen (meleeDir) + 1);
// Create the path upto the save dir, if not already existing. // Create the path upto the save dir, if not already existing.
if (mkdirhier (meleeDir) == -1) if (mkdirhier (buf) == -1)
exit (EXIT_FAILURE); 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
View File
@@ -22,6 +22,9 @@
#ifndef OPTIONS_H #ifndef OPTIONS_H
#define OPTIONS_H #define OPTIONS_H
#include "port.h"
#include "libs/uio.h"
#define OPT_3DO 0x01 #define OPT_3DO 0x01
#define OPT_PC 0x02 #define OPT_PC 0x02
#define OPT_ALL 0xFF #define OPT_ALL 0xFF
@@ -36,10 +39,12 @@ extern int optMeleeScale;
extern BOOLEAN optSubtitles; extern BOOLEAN optSubtitles;
extern BOOLEAN optStereoSFX; extern BOOLEAN optStereoSFX;
extern char *configDir; extern uio_DirHandle *contentDir;
extern char *meleeDir; extern uio_DirHandle *configDir;
extern char *saveDir; extern uio_DirHandle *saveDir;
extern uio_DirHandle *meleeDir;
void prepareContentDir (char *contentDirName);
void prepareConfigDir(void); void prepareConfigDir(void);
void prepareMeleeDir(void); void prepareMeleeDir(void);
void prepareSaveDir(void); void prepareSaveDir(void);
+46
View File
@@ -16,5 +16,51 @@
char *strupr (char *str); char *strupr (char *str);
#endif #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 */ #endif /* _PORT_H */
+2 -2
View File
@@ -87,7 +87,7 @@ OpenJournal (void)
else else
#endif /* CREATE_JOURNAL */ #endif /* CREATE_JOURNAL */
{ {
FILE *fp; uio_Stream *fp;
if (fp = res_OpenResFile ("starcon.jnl", "rb")) if (fp = res_OpenResFile ("starcon.jnl", "rb"))
{ {
@@ -114,7 +114,7 @@ CloseJournal (void)
{ {
if (journal_fh) if (journal_fh)
{ {
FILE *fp; uio_Stream *fp;
cclose (journal_fh); cclose (journal_fh);
journal_fh = 0; journal_fh = 0;
+1 -1
View File
@@ -35,7 +35,7 @@ LoadCodeResFile (PSTR pStr)
} }
static MEM_HANDLE static MEM_HANDLE
GetCodeResData (FILE *fp, DWORD length) GetCodeResData (uio_Stream *fp, DWORD length)
{ {
enum enum
{ {
+7 -8
View File
@@ -36,7 +36,7 @@ InitGroupInfo (BOOLEAN FirstTime)
{ {
PVOID fp; PVOID fp;
fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb");
if (fp) if (fp)
{ {
GROUP_HEADER GH; GROUP_HEADER GH;
@@ -49,8 +49,7 @@ InitGroupInfo (BOOLEAN FirstTime)
res_CloseResFile (fp); res_CloseResFile (fp);
} }
if (FirstTime && (fp = res_OpenResFile (tempFilePath (DEFGRPINFO_FILE), if (FirstTime && (fp = res_OpenResFile (tempDir, DEFGRPINFO_FILE, "wb")))
"wb")))
{ {
PutResFileChar (0, fp); PutResFileChar (0, fp);
@@ -349,8 +348,8 @@ GetGroupInfo (DWORD offset, BYTE which_group)
{ {
PVOID fp; PVOID fp;
fp = res_OpenResFile (tempFilePath ( fp = res_OpenResFile (tempDir,
offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE), offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE,
"r+b"); "r+b");
if (fp) if (fp)
{ {
@@ -387,7 +386,7 @@ GetGroupInfo (DWORD offset, BYTE which_group)
fprintf (stderr, "GetGroupInfo: battle groups out of date %u/%u/%u!\n", fprintf (stderr, "GetGroupInfo: battle groups out of date %u/%u/%u!\n",
month_index, day_index, year_index); month_index, day_index, year_index);
#endif /* DEBUG */ #endif /* DEBUG */
fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb");
GH.NumGroups = 0; GH.NumGroups = 0;
GH.star_index = (COUNT)~0; GH.star_index = (COUNT)~0;
GH.GroupOffset[0] = 0; GH.GroupOffset[0] = 0;
@@ -616,8 +615,8 @@ PutGroupInfo (DWORD offset, BYTE which_group)
{ {
PVOID fp; PVOID fp;
fp = res_OpenResFile (tempFilePath ( fp = res_OpenResFile (tempDir,
offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE), offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE,
"r+b"); "r+b");
if (fp) if (fp)
{ {
+29
View File
@@ -16,13 +16,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "port.h"
#include "starcon.h" #include "starcon.h"
#include "libs/uio.h"
FRAME stars_in_space, FRAME stars_in_space,
asteroid[NUM_VIEWS], asteroid[NUM_VIEWS],
blast[NUM_VIEWS], blast[NUM_VIEWS],
explosion[NUM_VIEWS]; explosion[NUM_VIEWS];
uio_Repository *repository;
uio_DirHandle *rootDir;
BOOLEAN BOOLEAN
load_animation (PFRAME pixarray, DWORD big_res, DWORD med_res, DWORD load_animation (PFRAME pixarray, DWORD big_res, DWORD med_res, DWORD
sml_res) sml_res)
@@ -268,3 +274,26 @@ InitGlobData (void)
(GLOBAL (GameClock)).clock_sem = CreateSemaphore(0, "Clock"); (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 -1
View File
@@ -1,2 +1,2 @@
uqm_SUBDIRS="decomp file graphics input math memory resource sound strings uqm_SUBDIRS="decomp file graphics input math memory resource sound strings
task threads time video" task threads time uio video"
+1 -1
View File
@@ -335,7 +335,7 @@ _encode_cleanup (void)
_lpCurCodeDesc->StreamIndex += 4; _lpCurCodeDesc->StreamIndex += 4;
/* rewind */ /* rewind */
if (_lpCurCodeDesc->StreamType == FILE_STREAM) if (_lpCurCodeDesc->StreamType == FILE_STREAM)
SeekResFile ((FILE *)_Stream, SeekResFile ((uio_Stream *)_Stream,
-(int)_lpCurCodeDesc->StreamIndex, SEEK_CUR); -(int)_lpCurCodeDesc->StreamIndex, SEEK_CUR);
else /* _lpCurCodeDesc->StreamType == MEMORY_STREAM */ else /* _lpCurCodeDesc->StreamType == MEMORY_STREAM */
_Stream = (PBYTE)((BYTE *)_Stream _Stream = (PBYTE)((BYTE *)_Stream
+2 -2
View File
@@ -69,10 +69,10 @@ typedef struct
typedef LZHCODE_DESC *PLZHCODE_DESC; typedef LZHCODE_DESC *PLZHCODE_DESC;
#define InChar() (_StreamType == FILE_STREAM ? \ #define InChar() (_StreamType == FILE_STREAM ? \
GetResFileChar ((FILE *)_Stream) : \ GetResFileChar ((uio_Stream *)_Stream) : \
(int)*_Stream++) (int)*_Stream++)
#define OutChar(c) (_StreamType == FILE_STREAM ? \ #define OutChar(c) (_StreamType == FILE_STREAM ? \
PutResFileChar ((c), (FILE *)_Stream) : \ PutResFileChar ((c), (uio_Stream *)_Stream) : \
(*_Stream++ = (BYTE)(c))) (*_Stream++ = (BYTE)(c)))
+9 -40
View File
@@ -18,50 +18,17 @@
#ifndef _FILE_H #ifndef _FILE_H
/* Make sure we have PATH_MAX */ #include "port.h"
#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
// for BOOLEAN // for bool
#include "compiler.h" #include "types.h"
// from temp.h // from temp.h
#include "libs/uio.h"
void initTempDir (void); void initTempDir (void);
void unInitTempDir (void); void unInitTempDir (void);
char *tempFilePath (const char *filename); char *tempFilePath (const char *filename);
extern uio_DirHandle *tempDir;
// from dirs.h // from dirs.h
int mkdirhier (const char *path); 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); int expandPath (char *dest, size_t len, const char *src);
// from files.h // from files.h
int copyFile (const char *srcName, const char *newName); int copyFile (uio_DirHandle *srcDir, const char *srcName,
BOOLEAN fileExists (const char *name); uio_DirHandle *dstDir, const char *newName);
bool fileExists (const char *name);
bool fileExists2(uio_DirHandle *dir, const char *fileName);
#endif /* _FILE_H */ #endif /* _FILE_H */
+55 -30
View File
@@ -22,20 +22,34 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include "port.h" #include "port.h"
#include "uio.h"
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
#include "filintrn.h" #include "filintrn.h"
#include "misc.h" #include "misc.h"
static int copyError(int srcFd, int dstFd, const char *unlinkPath, static int copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
uint8 *buf); uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf);
BOOLEAN bool
fileExists (const char *name) fileExists (const char *name)
{ {
return access (name, F_OK) == 0; 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. * Copy a file with path srcName to a file with name newName.
* If the destination already exists, the operation fails. * If the destination already exists, the operation fails.
@@ -48,49 +62,59 @@ fileExists (const char *name)
* remove the copy. * remove the copy.
*/ */
int 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; struct stat sb;
#define BUFSIZE 65536 #define BUFSIZE 65536
uint8 *buf, *bufPtr; uint8 *buf, *bufPtr;
ssize_t numInBuf, numWritten; ssize_t numInBuf, numWritten;
src = open (srcName, O_RDONLY); src = uio_open (srcDir, srcName, O_RDONLY
if (src == -1) #ifdef WIN32
| O_BINARY
#endif
, 0);
if (src == NULL)
return -1; return -1;
if (fstat (src, &sb) == -1) if (uio_fstat (src, &sb) == -1)
return copyError (src, -1, NULL, NULL); return copyError (src, NULL, NULL, NULL, NULL);
dst = open (newName, O_WRONLY | O_CREAT | O_EXCL, dst = uio_open (dstDir, newName, O_WRONLY | O_CREAT | O_EXCL
sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); #ifdef WIN32
if (dst == -1) | O_BINARY
return copyError (src, -1, NULL, NULL); #endif
, sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
if (dst == NULL)
return copyError (src, NULL, NULL, NULL, NULL);
buf = HMalloc(BUFSIZE); buf = HMalloc(BUFSIZE);
// This was originally a statically allocated buffer, // This was originally a statically allocated buffer,
// but as this function might be run from a thread with // but as this function might be run from a thread with
// a small Stack, this is better. // a small Stack, this is better.
while (1) { while (1)
numInBuf = read (src, buf, BUFSIZE); {
numInBuf = uio_read (src, buf, BUFSIZE);
if (numInBuf == -1) if (numInBuf == -1)
{ {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
return copyError (src, dst, newName, buf); return copyError (src, dst, dstDir, newName, buf);
} }
if (numInBuf == 0) if (numInBuf == 0)
break; break;
bufPtr = buf; bufPtr = buf;
do { do
numWritten = write (dst, bufPtr, numInBuf); {
numWritten = uio_write (dst, bufPtr, numInBuf);
if (numWritten == -1) if (numWritten == -1)
{ {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
return copyError (src, dst, newName, buf); return copyError (src, dst, dstDir, newName, buf);
} }
numInBuf -= numWritten; numInBuf -= numWritten;
bufPtr += numWritten; bufPtr += numWritten;
@@ -98,22 +122,23 @@ copyFile (const char *srcName, const char *newName)
} }
HFree(buf); HFree(buf);
close(src); uio_close(src);
close(dst); uio_close(dst);
errno = 0; errno = 0;
return 0; return 0;
} }
/* /*
* Closes srcFd if it's not -1. * Closes srcHandle if it's not -1.
* Closes dstFd if it's not -1. * Closes dstHandle if it's not -1.
* Removes unlinkpath if it's not NULL. * Removes unlinkpath from the unlinkHandle dir if it's not NULL.
* Frees 'buf' if not NULL. * Frees 'buf' if not NULL.
* Always returns -1. * Always returns -1.
* errno is what was before the call. * errno is what was before the call.
*/ */
static int 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; 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)) fprintf (stderr, "Error while copying: %s\n", strerror (errno))
#endif #endif
if (srcFd >= 0) if (srcHandle != NULL)
close (srcFd); uio_close (srcHandle);
if (dstFd >= 0) if (dstHandle != NULL)
close (dstFd); uio_close (dstHandle);
if (unlinkPath != NULL) if (unlinkPath != NULL)
unlink (unlinkPath); uio_unlink (unlinkHandle, unlinkPath);
if (buf != NULL) if (buf != NULL)
HFree(buf); HFree(buf);
+65 -15
View File
@@ -30,12 +30,13 @@
#include "libs/compiler.h" #include "libs/compiler.h"
#include "misc.h" #include "misc.h"
static char *tempDir; static char *tempDirName;
uio_DirHandle *tempDir;
static void static void
removeTempDir (void) removeTempDir (void)
{ {
rmdir (tempDir); rmdir (tempDirName);
} }
// Try if the null-terminated path 'dir' to a directory is valid // 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) if (dir == NULL)
return EINVAL; return EINVAL;
if (dir[0] == '\0')
return EINVAL;
len = strlen (dir); len = strlen (dir);
haveSlash = (dir[len - 1] == '/' haveSlash = (dir[len - 1] == '/'
#ifdef WIN32 #ifdef WIN32
@@ -63,6 +67,17 @@ tryTempDir (char *buf, size_t buflen, const char *dir)
return ENAMETOOLONG; return ENAMETOOLONG;
strcpy (buf, dir); strcpy (buf, dir);
#if 0
//def WIN32
{
char *bufPtr;
for (bufPtr = buf; *bufPtr != '\0'; bufPtr++)
{
if (*bufPtr == '\\')
*bufPtr = '/';
}
}
#endif
if (!haveSlash) if (!haveSlash)
{ {
buf[len] = '/'; buf[len] = '/';
@@ -71,22 +86,54 @@ tryTempDir (char *buf, size_t buflen, const char *dir)
} }
if (access (buf, R_OK | W_OK) == -1) if (access (buf, R_OK | W_OK) == -1)
return errno; return errno;
return 0; return 0;
} }
static void static void
getTempDir (char *buf, size_t buflen) { getTempDir (char *buf, size_t buflen) {
char cwd[PATH_MAX];
if (tryTempDir (buf, buflen, getenv("TMP")) && if (tryTempDir (buf, buflen, getenv("TMP")) &&
tryTempDir (buf, buflen, getenv("TEMP")) && tryTempDir (buf, buflen, getenv("TEMP")) &&
tryTempDir (buf, buflen, "/tmp/") && tryTempDir (buf, buflen, "/tmp/") &&
tryTempDir (buf, buflen, "./")) tryTempDir (buf, buflen, getcwd (cwd, sizeof cwd)))
{ {
fprintf (stderr, "Fatal Error: Cannot find a suitable location " fprintf (stderr, "Fatal Error: Cannot find a suitable location "
"to store temporary files.\n"); "to store temporary files.\n");
exit(EXIT_FAILURE); exit (EXIT_FAILURE);
} }
} }
// 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 #define NUM_TEMP_RETRIES 16
// Number of files to try to open before giving up. // Number of files to try to open before giving up.
void void
@@ -95,27 +142,29 @@ initTempDir (void) {
DWORD num; DWORD num;
int i; int i;
char *tempPtr; 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. // path to the temp dir ends and the dir starts.
tempDir = HMalloc (PATH_MAX); tempDirName = HMalloc (PATH_MAX);
getTempDir (tempDir, PATH_MAX - 21); getTempDir (tempDirName, PATH_MAX - 21);
// reserve 8 chars for dirname, 1 for slash, and 12 for filename // reserve 8 chars for dirname, 1 for slash, and 12 for filename
len = strlen(tempDir); len = strlen(tempDirName);
num = ((DWORD) time (NULL)); num = ((DWORD) time (NULL));
// num = GetTimeCounter () % 0xffffffff; // num = GetTimeCounter () % 0xffffffff;
tempPtr = tempDir + len; tempPtr = tempDirName + len;
i = NUM_TEMP_RETRIES; i = NUM_TEMP_RETRIES;
while (i--) while (i--)
{ {
sprintf (tempPtr, "%08lx", num + i); sprintf (tempPtr, "%08lx", num + i);
if (createDirectory (tempDir, 0700) == -1) if (createDirectory (tempDirName, 0700) == -1)
continue; continue;
// Success, we've got a temp dir. // Success, we've got a temp dir.
tempDir = HRealloc (tempDir, len + 9); tempDirName = HRealloc (tempDirName, len + 9);
atexit (removeTempDir); atexit (removeTempDir);
if (mountTempDir (tempDirName) == -1)
exit (EXIT_FAILURE);
return; return;
} }
@@ -127,7 +176,7 @@ initTempDir (void) {
void void
unInitTempDir (void) { unInitTempDir (void) {
// nothing at the moment. uio_closeDir(tempDir);
// the removing of the dir is handled via atexit // the removing of the dir is handled via atexit
} }
@@ -137,10 +186,11 @@ char *
tempFilePath (const char *filename) { tempFilePath (const char *filename) {
static char file[PATH_MAX]; 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"); fprintf (stderr, "Path to temp file too long.\n");
exit(EXIT_FAILURE); exit (EXIT_FAILURE);
} }
return file; return file;
} }
+1 -1
View File
@@ -122,7 +122,7 @@ extern DRAWABLE _request_drawable (COUNT NumFrames, DRAWABLE_TYPE
extern INTERSECT_CODE _clip_line (PRECT pClipRect, PBRESENHAM_LINE extern INTERSECT_CODE _clip_line (PRECT pClipRect, PBRESENHAM_LINE
pLine); pLine);
extern MEM_HANDLE _GetCelData (FILE *fp, DWORD length); extern MEM_HANDLE _GetCelData (uio_Stream *fp, DWORD length);
extern BOOLEAN _ReleaseCelData (MEM_HANDLE handle); extern BOOLEAN _ReleaseCelData (MEM_HANDLE handle);
typedef PPRIMITIVE PRIMITIVEPTR; typedef PPRIMITIVE PRIMITIVEPTR;
+3 -2
View File
@@ -17,20 +17,21 @@
*/ */
#include "gfxintrn.h" #include "gfxintrn.h"
#include "options.h"
extern char *_cur_resfile_name; extern char *_cur_resfile_name;
DWORD DWORD
LoadCelFile (PVOID pStr) LoadCelFile (PVOID pStr)
{ {
FILE *fp; uio_Stream *fp;
// FIXME: this theoretically needs a mechanism to prevent races // FIXME: this theoretically needs a mechanism to prevent races
if (_cur_resfile_name) if (_cur_resfile_name)
// something else is loading resources atm // something else is loading resources atm
return 0; return 0;
if ((fp = res_OpenResFile (pStr, "rb")) != NULL) if ((fp = res_OpenResFile (contentDir, pStr, "rb")) != NULL)
{ {
MEM_HANDLE hData; MEM_HANDLE hData;
+1 -1
View File
@@ -48,7 +48,7 @@ typedef FONT_DESC *PFONT_DESC;
extern FONTPTR _CurFontPtr; 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); extern BOOLEAN _ReleaseFontData (MEM_HANDLE handle);
#endif /* _FONT_H */ #endif /* _FONT_H */
+29 -26
View File
@@ -23,8 +23,12 @@
#endif #endif
#include <fcntl.h> #include <fcntl.h>
#include "port.h"
#include "sdl_common.h" #include "sdl_common.h"
#include "primitives.h" #include "primitives.h"
#include "sdluio.h"
#include "libs/file.h"
#include "options.h"
typedef struct anidata typedef struct anidata
{ {
@@ -415,11 +419,8 @@ Uint32 frame_mapRGBA (FRAMEPTR FramePtr,Uint8 r, Uint8 g, Uint8 b, Uint8 a)
} }
MEM_HANDLE MEM_HANDLE
_GetCelData (FILE *fp, DWORD length) _GetCelData (uio_Stream *fp, DWORD length)
{ {
#ifdef WIN32
int omode;
#endif
int cel_ct, n; int cel_ct, n;
DWORD opos; DWORD opos;
char CurrentLine[1024], filename[1024]; char CurrentLine[1024], filename[1024];
@@ -428,7 +429,7 @@ _GetCelData (FILE *fp, DWORD length)
AniData ani[MAX_CELS]; AniData ani[MAX_CELS];
DRAWABLE Drawable; DRAWABLE Drawable;
opos = ftell (fp); opos = uio_ftell (fp);
{ {
char *s1, *s2; char *s1, *s2;
@@ -446,37 +447,38 @@ _GetCelData (FILE *fp, DWORD length)
} }
} }
#ifdef WIN32
omode = _setmode (fileno (fp), O_TEXT);
#endif
cel_ct = 0; 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], sscanf (CurrentLine, "%s %d %d %d %d", &filename[n],
&ani[cel_ct].transparent_color, &ani[cel_ct].colormap_index, &ani[cel_ct].transparent_color, &ani[cel_ct].colormap_index,
&ani[cel_ct].hotspot_x, &ani[cel_ct].hotspot_y); &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] = sdluio_loadImage (contentDir, filename);
img[cel_ct]->h > 0 && img[cel_ct]->format->BitsPerPixel >= 8) 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"); fprintf (stderr, "_GetCelData: Bad file!\n");
SDL_FreeSurface (img[cel_ct]); 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; break;
} }
#ifdef WIN32
_setmode (fileno (fp), omode);
#endif
Drawable = 0; Drawable = 0;
if (cel_ct && (Drawable = AllocDrawable (cel_ct))) if (cel_ct && (Drawable = AllocDrawable (cel_ct)))
@@ -555,7 +557,7 @@ _ReleaseCelData (MEM_HANDLE handle)
} }
MEM_HANDLE MEM_HANDLE
_GetFontData (FILE *fp, DWORD length) _GetFontData (uio_Stream *fp, DWORD length)
{ {
DWORD cel_ct; DWORD cel_ct;
COUNT num_entries; COUNT num_entries;
@@ -564,14 +566,15 @@ _GetFontData (FILE *fp, DWORD length)
BOOLEAN found_chars; BOOLEAN found_chars;
#define MAX_CELS 256 #define MAX_CELS 256
SDL_Surface *img[MAX_CELS] = { 0 }; SDL_Surface *img[MAX_CELS] = { 0 };
char pattern[1024]; char pattern[PATH_MAX];
if (_cur_resfile_name == 0) if (_cur_resfile_name == 0)
return (0); return (0);
sprintf (pattern, "%s/*.*", _cur_resfile_name);
found_chars = FALSE; found_chars = FALSE;
FontDir = CaptureDirEntryTable (LoadDirEntryTable (pattern, &num_entries)); FontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir,
_cur_resfile_name, ".", match_MATCH_SUBSTRING,
&num_entries));
while (num_entries--) while (num_entries--)
{ {
char *char_name; char *char_name;
@@ -581,7 +584,7 @@ _GetFontData (FILE *fp, DWORD length)
&& cel_ct >= FIRST_CHAR && cel_ct >= FIRST_CHAR
&& img[cel_ct -= FIRST_CHAR] == 0 && img[cel_ct -= FIRST_CHAR] == 0
&& sprintf (pattern, "%s/%s", _cur_resfile_name, char_name) && 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 if (img[cel_ct]->w > 0
&& img[cel_ct]->h > 0 && img[cel_ct]->h > 0
+1 -1
View File
@@ -1,3 +1,3 @@
uqm_CFILES="3do_blt.c 3do_funcs.c 3do_getbody.c dcqueue.c opengl.c uqm_CFILES="3do_blt.c 3do_funcs.c 3do_getbody.c dcqueue.c opengl.c
primitives.c pure.c rndzoom.c sdl_common.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]; static TFB_Palette palette[256];
#define FPS_PERIOD 1000 #define FPS_PERIOD 100
int RenderedFrames = 0; int RenderedFrames = 0;
void void
+110
View File
@@ -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 */
+19 -19
View File
@@ -76,47 +76,47 @@ static VControl_NameBinding control_names[] = {
static void static void
initKeyConfig(void) { initKeyConfig(void) {
char userFile[PATH_MAX]; /* System-wide key config */ uio_Stream *fp;
int cb;
FILE *fp;
int errors; int errors;
cb = snprintf (userFile, PATH_MAX, "%skeys.cfg", configDir); fp = res_OpenResFile (configDir, "keys.cfg", "rt");
assert (cb != -1); if (fp == NULL)
// Verified before: strlen (configDir) <= PATH_MAX - 13 {
if (copyFile (contentDir, "starcon.key",
if (fileExists (userFile)) { configDir, "keys.cfg") == -1)
fp = res_OpenResFile (userFile, "rt");
} else {
if (copyFile ("starcon.key", userFile) == -1)
{ {
fprintf(stderr, "Warning: Could not copy default key config " 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 else
{ {
fprintf(stderr, "Copying default key config file to %s.\n", fprintf(stderr, "Copying default key config file to user "
userFile); "config dir.\n");
} }
fp = res_OpenResFile ("starcon.key", "rt"); fp = res_OpenResFile (contentDir, "starcon.key", "rt");
} }
errors = VControl_ReadConfiguration (fp); errors = VControl_ReadConfiguration (fp);
res_CloseResFile (fp); res_CloseResFile (fp);
if (errors) 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 /* This code should go away in 0.3; it's just
* to force people to upgrade and forestall a * to force people to upgrade and forestall a
* bunch of "none of my keys work anymore" bugs. * bunch of "none of my keys work anymore" bugs.
*/ */
if (errors > 5) 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, "Hey! you haven't updated your keys.cfg to "
fprintf (stderr, "If you've done that and it STILL doesn't work, make sure your content/starcon.key is up to date.\n"); "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 else
{ {
fprintf (stderr, "Repair your %s file to continue.\n", userFile); fprintf (stderr, "Repair your keys.cfg file to continue.\n");
} }
exit (1); exit (1);
+7 -7
View File
@@ -906,18 +906,18 @@ _next_token (parse_state *state)
} }
static void static void
_next_line (parse_state *state, FILE *in) _next_line (parse_state *state, uio_Stream *in)
{ {
int i, ch = 0; int i, ch = 0;
state->linenum++; state->linenum++;
for (i = 0; i < LINE_SIZE-1; i++) for (i = 0; i < LINE_SIZE-1; i++)
{ {
if (feof (in)) if (uio_feof (in))
{ {
break; break;
} }
ch = fgetc (in); ch = uio_fgetc (in);
if (ch == '#' || ch == '\n' || ch == -1) if (ch == '#' || ch == '\n' || ch == EOF)
{ {
/* If this line is blank or all commented, include some /* If this line is blank or all commented, include some
* whitespace. This lets us detect EOF as a completely * whitespace. This lets us detect EOF as a completely
@@ -933,9 +933,9 @@ _next_line (parse_state *state, FILE *in)
} }
state->line[i] = '\0'; state->line[i] = '\0';
/* Skip to end of line */ /* 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->token[0] = 0;
state->index = 0; state->index = 0;
@@ -1180,7 +1180,7 @@ _parse_config_line (parse_state *state)
} }
int int
VControl_ReadConfiguration (FILE *in) VControl_ReadConfiguration (uio_Stream *in)
{ {
parse_state ps; parse_state ps;
int errors; int errors;
+3 -1
View File
@@ -3,6 +3,8 @@
#ifndef _VCONTROL_H_ #ifndef _VCONTROL_H_
#define _VCONTROL_H_ #define _VCONTROL_H_
#include "port.h"
#include "libs/uio.h"
/* Initialization routines */ /* Initialization routines */
void VControl_Init (void); 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. */ /* Dump a configuration file corresponding to the current bindings and names. */
void VControl_Dump (FILE *out); void VControl_Dump (FILE *out);
/* Read a configuration file. Returns number of errors encountered. */ /* Read a configuration file. Returns number of errors encountered. */
int VControl_ReadConfiguration (FILE *in); int VControl_ReadConfiguration (uio_Stream *in);
#endif #endif
+20 -15
View File
@@ -19,8 +19,10 @@
#ifndef _RESLIB_H #ifndef _RESLIB_H
#define _RESLIB_H #define _RESLIB_H
#include <stdio.h> //#include <stdio.h>
#include "port.h"
#include "memlib.h" #include "memlib.h"
#include "libs/uio.h"
typedef DWORD RESOURCE; typedef DWORD RESOURCE;
typedef RESOURCE *PRESOURCE; typedef RESOURCE *PRESOURCE;
@@ -49,24 +51,25 @@ typedef COUNT RES_PACKAGE;
((RESOURCE)(i) << TYPE_BITS) | \ ((RESOURCE)(i) << TYPE_BITS) | \
((RESOURCE)(t))) ((RESOURCE)(t)))
extern FILE *res_OpenResFile (PVOID filename, const char *mode); extern uio_Stream *res_OpenResFile (uio_DirHandle *dir, const char *filename,
extern int ReadResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp); const char *mode);
extern int WriteResFile (PVOID lpBuf, COUNT size, COUNT count, FILE extern int ReadResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp);
*fp); extern int WriteResFile (PVOID lpBuf, COUNT size, COUNT count,
extern int GetResFileChar (FILE *fp); uio_Stream *fp);
extern int PutResFileChar (char ch, FILE *fp); extern int GetResFileChar (uio_Stream *fp);
extern long SeekResFile (FILE *fp, long offset, int whence); extern int PutResFileChar (char ch, uio_Stream *fp);
extern long TellResFile (FILE *fp); extern long SeekResFile (uio_Stream *fp, long offset, int whence);
extern long LengthResFile (FILE *fp); extern long TellResFile (uio_Stream *fp);
extern BOOLEAN res_CloseResFile (FILE *fp); extern long LengthResFile (uio_Stream *fp);
extern BOOLEAN DeleteResFile (PVOID filename); 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, extern MEM_HANDLE InitResourceSystem (PVOID resfile, COUNT resindex_type,
BOOLEAN (*FileErrorFunc) (PVOID filename)); BOOLEAN (*FileErrorFunc) (PVOID filename));
extern BOOLEAN UninitResourceSystem (void); extern BOOLEAN UninitResourceSystem (void);
extern BOOLEAN InstallResTypeVectors ( extern BOOLEAN InstallResTypeVectors (
COUNT res_type, 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)); BOOLEAN (*free_func) (MEM_HANDLE handle));
extern MEM_HANDLE res_GetResource (RESOURCE res); extern MEM_HANDLE res_GetResource (RESOURCE res);
extern MEM_HANDLE res_DetachResource (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 MEM_HANDLE SetResourceIndex (MEM_HANDLE hRH);
extern BOOLEAN CloseResourceIndex (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); length, MEM_FLAGS mem_flags);
#define RESOURCE_PRIORITY DEFAULT_MEM_PRIORITY #define RESOURCE_PRIORITY DEFAULT_MEM_PRIORITY
@@ -102,7 +105,9 @@ typedef STRING_TABLE DIRENTRY_REF;
typedef STRING DIRENTRY; typedef STRING DIRENTRY;
typedef STRINGPTR DIRENTRYPTR; 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); PCOUNT pnum_entries);
#define CaptureDirEntryTable CaptureStringTable #define CaptureDirEntryTable CaptureStringTable
#define ReleaseDirEntryTable ReleaseStringTable #define ReleaseDirEntryTable ReleaseStringTable
+66 -252
View File
@@ -16,281 +16,95 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 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" #include "libs/strings/strintrn.h"
#include "port.h"
DIRENTRY_REF #include "libs/uio.h"
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 <sys/stat.h> #include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <fnmatch.h>
#include <ctype.h>
#include <limits.h>
DIRENTRY_REF 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 num_entries, length;
COUNT i;
COUNT slen;
uio_DirHandle *dir;
STRING_TABLE StringTable; STRING_TABLE StringTable;
STRING_TABLEPTR lpST; STRING_TABLEPTR lpST;
PSTR lpStr;
PDWORD lpLastOffs; 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; num_entries = 0;
StringTable = 0;
do
{
COUNT slen;
DIR *handle;
if (num_entries == 0)
length = 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; struct stat sb;
de = readdir(handle); if (dirList->names[i][0] == '.')
if (de == NULL)
break;
if (de->d_name[0] == '.')
continue;
strcpy (file, de->d_name);
// attach the filename to path
if (stat(path, &sb) == -1)
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; dirList->names[i] = NULL;
PDWORD lpLo, lpHi; continue;
}
lpLo = &lpST->StringOffsets[0]; if (uio_stat (dir, dirList->names[i], &sb) == -1)
lpHi = lpLastOffs - 1;
while (lpLo <= lpHi)
{ {
char c1, c2; dirList->names[i] = NULL;
PSTR pStr; continue;
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;
} }
if (!S_ISREG (sb.st_mode))
lpStr = (PSTR)lpST + lpLo[0]; {
memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]); dirList->names[i] = NULL;
strcpy (lpStr, de->d_name); continue;
for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi)
lpHi[1] = lpHi[0] + slen;
} }
length += strlen (dirList->names[i]) + 1;
++num_entries; num_entries++;
} }
closedir(handle); uio_closeDir (dir);
}
} while (num_entries && (MEM_HANDLE)StringTable == 0);
if ((MEM_HANDLE)StringTable == 0) if (num_entries == 0) {
uio_freeDirList(dirList);
*pnum_entries = 0; *pnum_entries = 0;
else return ((DIRENTRY_REF) 0);
{
*pnum_entries = num_entries;
UnlockStringTable (StringTable);
} }
return ((DIRENTRY_REF)StringTable); 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
+31 -38
View File
@@ -24,33 +24,31 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "port.h"
#include "resintrn.h" #include "resintrn.h"
#include "libs/uio.h"
FILE * uio_Stream *
res_OpenResFile (PVOID filename, const char *mode) res_OpenResFile (uio_DirHandle *dir, const char *filename, const char *mode)
{ {
FILE *fp; uio_Stream *fp;
struct stat sb; struct stat sb;
#ifdef WIN32 if (uio_stat (dir, filename, &sb) == 0 && S_ISDIR(sb.st_mode))
if (stat (filename, &sb) == 0 && (sb.st_mode & _S_IFDIR)) return ((uio_Stream *) ~0);
#else
if (stat (filename, &sb) == 0 && S_ISDIR(sb.st_mode))
#endif
return ((FILE *) ~0);
fp = fopen (filename, mode); fp = uio_fopen (dir, filename, mode);
return (fp); return (fp);
} }
BOOLEAN BOOLEAN
res_CloseResFile (FILE *fp) res_CloseResFile (uio_Stream *fp)
{ {
if (fp) if (fp)
{ {
if (fp != (FILE *)~0) if (fp != (uio_Stream *)~0)
fclose (fp); uio_fclose (fp);
return (TRUE); return (TRUE);
} }
@@ -58,85 +56,80 @@ res_CloseResFile (FILE *fp)
} }
BOOLEAN BOOLEAN
DeleteResFile (PVOID filename) DeleteResFile (uio_DirHandle *dir, const char *filename)
{ {
return (remove (filename) == 0); return (uio_unlink (dir, filename) == 0);
} }
int int
ReadResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp) ReadResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp)
{ {
int retval; int retval;
retval = fread (lpBuf, size, count, fp); retval = uio_fread (lpBuf, size, count, fp);
return (retval); return (retval);
} }
int int
WriteResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp) WriteResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp)
{ {
int retval; int retval;
retval = fwrite (lpBuf, size, count, fp); retval = uio_fwrite (lpBuf, size, count, fp);
return (retval); return (retval);
} }
int int
GetResFileChar (FILE *fp) GetResFileChar (uio_Stream *fp)
{ {
int retval; int retval;
retval = getc (fp); retval = uio_getc (fp);
return (retval); return (retval);
} }
int int
PutResFileChar (char ch, FILE *fp) PutResFileChar (char ch, uio_Stream *fp)
{ {
int retval; int retval;
retval = putc (ch, fp); retval = uio_putc (ch, fp);
return (retval); return (retval);
} }
long long
SeekResFile (FILE *fp, long offset, int whence) SeekResFile (uio_Stream *fp, long offset, int whence)
{ {
long retval; long retval;
retval = fseek (fp, offset, whence); retval = uio_fseek (fp, offset, whence);
return (retval); return (retval);
} }
long long
TellResFile (FILE *fp) TellResFile (uio_Stream *fp)
{ {
long retval; long retval;
retval = ftell (fp); retval = uio_ftell (fp);
return (retval); return (retval);
} }
long long
LengthResFile (FILE *fp) LengthResFile (uio_Stream *fp)
{ {
if (fp == (FILE *)~0)
return (1);
#ifdef WIN32
return filelength (fileno (fp));
#else
{
struct stat sb; 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 1;
return sb.st_size; return sb.st_size;
}
#endif
} }
+4 -3
View File
@@ -18,6 +18,7 @@
#include "resintrn.h" #include "resintrn.h"
#include "port.h" #include "port.h"
#include "options.h"
char *_cur_resfile_name; char *_cur_resfile_name;
@@ -156,7 +157,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package)
{ {
BOOLEAN DanglingOpen; BOOLEAN DanglingOpen;
MEM_HANDLE hList; MEM_HANDLE hList;
FILE *fp; uio_Stream *fp;
COUNT t, num_types, num_instances; COUNT t, num_types, num_instances;
DWORD file_offs, data_len; DWORD file_offs, data_len;
RES_HANDLE_LISTPTR ResourceHandleListPtr; RES_HANDLE_LISTPTR ResourceHandleListPtr;
@@ -221,7 +222,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package)
fp = ResHeaderPtr->res_fp; fp = ResHeaderPtr->res_fp;
else else
{ {
fp = res_OpenResFile (file_buf, "rb"); fp = res_OpenResFile (contentDir, file_buf, "rb");
if (fp) if (fp)
DanglingOpen = TRUE; DanglingOpen = TRUE;
} }
@@ -298,7 +299,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package)
{ {
get_resource_filename (ResHeaderPtr, file_buf, (COUNT)data_len); 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 (fp == NULL)
{ {
#if 1 // def DEBUG #if 1 // def DEBUG
+2 -2
View File
@@ -23,7 +23,7 @@
typedef struct 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); BOOLEAN (*free_func) (MEM_HANDLE handle);
} RES_VECTORS; } RES_VECTORS;
@@ -50,7 +50,7 @@ typedef BYTE RES_FLAGS;
typedef struct typedef struct
{ {
FILE *res_fp; uio_Stream *res_fp;
DWORD packmem_list_offs; DWORD packmem_list_offs;
DWORD path_list_offs; DWORD path_list_offs;
+1 -1
View File
@@ -20,7 +20,7 @@
#include "declib.h" #include "declib.h"
MEM_HANDLE MEM_HANDLE
GetResourceData (FILE *fp, DWORD length, MEM_FLAGS mem_flags) GetResourceData (uio_Stream *fp, DWORD length, MEM_FLAGS mem_flags)
{ {
MEM_HANDLE RData; MEM_HANDLE RData;
DECODE_REF fh; DECODE_REF fh;
+8 -7
View File
@@ -17,6 +17,7 @@
*/ */
#include "resintrn.h" #include "resintrn.h"
#include "options.h"
static MEM_HANDLE hIndexList; static MEM_HANDLE hIndexList;
@@ -83,7 +84,7 @@ _sub_index_list (MEM_HANDLE hRH)
} }
MEM_HANDLE MEM_HANDLE
_GetResFileData (FILE *res_fp, DWORD flen) _GetResFileData (uio_Stream *res_fp, DWORD flen)
{ {
UWORD lo_word, hi_word; UWORD lo_word, hi_word;
DWORD res_offs, remainder; DWORD res_offs, remainder;
@@ -250,17 +251,17 @@ UninitResourceSystem (void)
MEM_HANDLE MEM_HANDLE
OpenResourceIndexFile (PVOID resfile) OpenResourceIndexFile (PVOID resfile)
{ {
FILE *res_fp; uio_Stream *res_fp;
char fullname[256]; char fullname[256];
strcpy (fullname, resfile); 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); 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); 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)) if (UnlockResourceHeader (hRH))
{ {
FILE *res_fp; uio_Stream *res_fp;
INDEX_HEADERPTR ResHeaderPtr; INDEX_HEADERPTR ResHeaderPtr;
ResHeaderPtr = LockResourceHeader (hRH); ResHeaderPtr = LockResourceHeader (hRH);
@@ -379,7 +380,7 @@ CloseResourceIndex (MEM_HANDLE hRH)
BOOLEAN BOOLEAN
InstallResTypeVectors (COUNT res_type, 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)) BOOLEAN (*free_func) (MEM_HANDLE handle))
{ {
INDEX_HEADERPTR ResHeaderPtr; INDEX_HEADERPTR ResHeaderPtr;
+1 -1
View File
@@ -54,7 +54,7 @@ do \
#define DoLoad(pRH, t,fp,len) (*(pRH)->TypeList[t-1].func_vectors.load_func)(fp,len) #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) #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 \ #define IsIndexType(pRH, t) ((pRH)->TypeList[t-1].func_vectors.load_func \
==_GetResFileData) ==_GetResFileData)
+25 -27
View File
@@ -27,12 +27,17 @@
#include <string.h> #include <string.h>
#include <vorbis/codec.h> #include <vorbis/codec.h>
#include <vorbis/vorbisfile.h> #include <vorbis/vorbisfile.h>
#include "port.h"
#include "libs/misc.h" #include "libs/misc.h"
#include "libs/uio.h"
#include "decoder.h" #include "decoder.h"
#include "wav.h" #include "wav.h"
#include "libs/sound/sound_common.h" #include "libs/sound/sound_common.h"
#include "mikmod/mikmod.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; MIKMODAPI extern struct MDRIVER drv_openal;
static char *decoder_info_wav = "Wav"; static char *decoder_info_wav = "Wav";
@@ -42,35 +47,25 @@ static char *decoder_info_nul = "None";
TFB_DecoderFormats decoder_formats; 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) 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) static int ogg_seek (void *datasource, ogg_int64_t offset, int whence)
{ {
long off = (long) offset; long off = (long) offset;
return fseek (datasource, off, whence); return uio_fseek ((uio_Stream *) datasource, off, whence);
} }
static int ogg_close (void *datasource) static int ogg_close (void *datasource)
{ {
return fclose (datasource); return uio_fclose ((uio_Stream *) datasource);
} }
static long ogg_tell(void *datasource) static long ogg_tell(void *datasource)
{ {
return ftell (datasource); return uio_ftell ((uio_Stream *) datasource);
} }
static const ov_callbacks ogg_callbacks = static const ov_callbacks ogg_callbacks =
@@ -152,13 +147,13 @@ void SoundDecoder_Uninit (void)
MikMod_Exit (); MikMod_Exit ();
} }
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir, char *filename,
uint32 startTime, sint32 runTime) uint32 buffer_size, uint32 startTime, sint32 runTime)
{ {
int i; int i;
i = strlen (filename) - 3; i = strlen (filename) - 3;
if (!file_exists (filename)) if (!fileExists2 (dir, filename))
{ {
if (runTime) if (runTime)
{ {
@@ -180,6 +175,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
decoder->decoder_info = decoder_info_nul; decoder->decoder_info = decoder_info_nul;
decoder->type = SOUNDDECODER_NULL; decoder->type = SOUNDDECODER_NULL;
decoder->dir = dir;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
strcpy (decoder->filename, filename); strcpy (decoder->filename, filename);
decoder->data = NULL; decoder->data = NULL;
@@ -208,6 +204,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
decoder->length = 0; // FIXME should be calculated decoder->length = 0; // FIXME should be calculated
decoder->decoder_info = decoder_info_wav; decoder->decoder_info = decoder_info_wav;
decoder->type = SOUNDDECODER_WAV; decoder->type = SOUNDDECODER_WAV;
decoder->dir = dir;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0; decoder->start_sample = 0;
decoder->end_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); //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) if (!mod)
{ {
fprintf (stderr, "SoundDecoder_Load(): couldn't load %s\n", filename); 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->length = 0; // FIXME way to obtain this from mikmod?
decoder->decoder_info = decoder_info_mod; decoder->decoder_info = decoder_info_mod;
decoder->type = SOUNDDECODER_MOD; decoder->type = SOUNDDECODER_MOD;
decoder->dir = dir;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0; decoder->start_sample = 0;
decoder->end_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")) else if (!strcmp (&filename[i], "ogg"))
{ {
int rc; int rc;
FILE *vfp; uio_Stream *vfp;
OggVorbis_File *vf; OggVorbis_File *vf;
vorbis_info *vinfo; vorbis_info *vinfo;
TFB_SoundDecoder *decoder; 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"); fprintf (stderr, "SoundDecoder_Load(): couldn't allocate mem for OggVorbis_File\n");
return NULL; 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); fprintf (stderr, "SoundDecoder_Load(): couldn't open %s\n", filename);
HFree (vf); HFree (vf);
return NULL; return NULL;
} }
#ifdef WIN32
_setmode( _fileno(vfp), _O_BINARY);
#endif
rc = ov_open_callbacks (vfp, vf, NULL, 0, ogg_callbacks); rc = ov_open_callbacks (vfp, vf, NULL, 0, ogg_callbacks);
if (rc != 0) if (rc != 0)
{ {
fprintf (stderr, "SoundDecoder_Load(): ov_open_callbacks failed for %s, error code %d\n", filename, rc); fprintf (stderr, "SoundDecoder_Load(): ov_open_callbacks failed for %s, error code %d\n", filename, rc);
fclose (vfp); uio_fclose (vfp);
HFree (vf); HFree (vf);
return NULL; return NULL;
} }
@@ -330,6 +326,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
decoder->decoder_info = decoder_info_ogg; decoder->decoder_info = decoder_info_ogg;
decoder->type = SOUNDDECODER_OGG; decoder->type = SOUNDDECODER_OGG;
decoder->dir = dir;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
strcpy (decoder->filename, filename); strcpy (decoder->filename, filename);
decoder->data = vf; decoder->data = vf;
@@ -506,8 +503,9 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
{ {
case SOUNDDECODER_WAV: case SOUNDDECODER_WAV:
{ {
LoadWAVFile (decoder->filename ,&decoder->format, &decoder->buffer, LoadWAVFile (decoder->dir, decoder->filename, &decoder->format,
&decoder->buffer_size, &decoder->frequency, decoder_formats.want_big_endian); &decoder->buffer, &decoder->buffer_size,
&decoder->frequency, decoder_formats.want_big_endian);
if (decoder->buffer_size != 0) if (decoder->buffer_size != 0)
{ {
@@ -21,7 +21,9 @@
#ifndef DECODER_H #ifndef DECODER_H
#define DECODER_H #define DECODER_H
#include "port.h"
#include "types.h" #include "types.h"
#include "uio.h"
#ifdef WIN32 #ifdef WIN32
#pragma comment (lib, "vorbisfile.lib") #pragma comment (lib, "vorbisfile.lib")
@@ -51,6 +53,7 @@ typedef struct tfb_sounddecoder
// semi-private // semi-private
sint32 type; sint32 type;
uio_DirHandle *dir;
char *filename; char *filename;
void *data; void *data;
uint32 pos; uint32 pos;
@@ -82,8 +85,8 @@ extern TFB_DecoderFormats decoder_formats;
void SoundDecoder_SwapWords (uint16* data, uint32 size); void SoundDecoder_SwapWords (uint16* data, uint32 size);
sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats); sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats);
void SoundDecoder_Uninit (void); void SoundDecoder_Uninit (void);
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir,
uint32 startTime, sint32 runTime); char *filename, uint32 buffer_size, uint32 startTime, sint32 runTime);
uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder); uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder);
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder); uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
float SoundDecoder_GetTime (TFB_SoundDecoder *decoder); float SoundDecoder_GetTime (TFB_SoundDecoder *decoder);
@@ -31,6 +31,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "port.h"
#include "libs/uio.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -324,8 +326,8 @@ typedef struct SAMPLE {
/* Sample functions */ /* Sample functions */
MIKMODAPI extern SAMPLE *Sample_Load(CHAR*); MIKMODAPI extern SAMPLE *Sample_Load(uio_DirHandle*,CHAR*);
MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*); MIKMODAPI extern SAMPLE *Sample_LoadFP(uio_Stream*);
MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*); MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
MIKMODAPI extern void Sample_Free(SAMPLE*); MIKMODAPI extern void Sample_Free(SAMPLE*);
MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE); 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); MIKMODAPI extern MODULE* Player_LoadRW(SDL_RWops*,int,BOOL);
#endif /* USE_RWOPS */ #endif /* USE_RWOPS */
/* End SDL_RWops compatability */ /* End SDL_RWops compatability */
MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL); MIKMODAPI extern MODULE* Player_Load(uio_DirHandle *, CHAR*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL); MIKMODAPI extern MODULE* Player_LoadFP(uio_Stream*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,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_Free(MODULE*);
MIKMODAPI extern void Player_Start(MODULE*); MIKMODAPI extern void Player_Start(MODULE*);
MIKMODAPI extern BOOL Player_Active(void); MIKMODAPI extern BOOL Player_Active(void);
@@ -38,6 +38,8 @@
#endif #endif
#include "mikmod_build.h" #include "mikmod_build.h"
#include "port.h"
#include "libs/uio.h"
#ifdef macintosh #ifdef macintosh
#ifndef __MWERKS__ #ifndef __MWERKS__
@@ -142,13 +144,13 @@ extern void _mm_delete_rwops_reader (MREADER*);
#endif /* USE_RWOPS */ #endif /* USE_RWOPS */
/* End SDL_RWops compatability */ /* 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 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 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_SBYTE(x,y) y->Put(y,(int)x)
#define _mm_write_UBYTE(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_setcur(MREADER*);
extern void _mm_iobase_revert(void); 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 void _mm_write_string(CHAR*,MWRITER*);
extern int _mm_read_string (CHAR*,int,MREADER*); extern int _mm_read_string (CHAR*,int,MREADER*);
@@ -32,6 +32,8 @@
#include <string.h> #include <string.h>
#include "mikmod_internals.h" #include "mikmod_internals.h"
#include "port.h"
#include "libs/uio.h"
MREADER *modreader; MREADER *modreader;
@@ -372,20 +374,20 @@ static CHAR* Player_LoadTitle_internal(MREADER *reader)
return l->LoadTitle(); return l->LoadTitle();
} }
CHAR* Player_LoadTitle(CHAR* filename) CHAR* Player_LoadTitle(uio_DirHandle *dir, CHAR* filename)
{ {
CHAR* result=NULL; CHAR* result=NULL;
FILE* fp; uio_Stream* fp;
MREADER* reader; MREADER* reader;
if((fp=_mm_fopen(filename,"rb"))) { if((fp=_mm_fopen(dir, filename,"rb"))) {
if((reader=_mm_new_file_reader(fp))) { if((reader=_mm_new_file_reader(fp))) {
MUTEX_LOCK(lists); MUTEX_LOCK(lists);
result=Player_LoadTitle_internal(reader); result=Player_LoadTitle_internal(reader);
MUTEX_UNLOCK(lists); MUTEX_UNLOCK(lists);
_mm_delete_file_reader(reader); _mm_delete_file_reader(reader);
} }
fclose(fp); uio_fclose(fp);
} }
return result; return result;
} }
@@ -507,7 +509,7 @@ MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
/* Loads a module given a file pointer. /* Loads a module given a file pointer.
File is loaded from the current file seek position. */ 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; MODULE* result=NULL;
struct MREADER* reader=_mm_new_file_reader (fp); 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 /* Open a module via its filename. The loader will initialize the specified
song-player 'player'. */ 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; MODULE *mf=NULL;
if((fp=_mm_fopen(filename,"rb"))) { if((fp=_mm_fopen(dir, filename,"rb"))) {
mf=Player_LoadFP(fp,maxchan,curious); mf=Player_LoadFP(fp,maxchan,curious);
fclose(fp); uio_fclose(fp);
} }
return mf; 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; _mm_errno = MMERR_OPENING_FILE;
if(_mm_errorhandler) _mm_errorhandler(); if(_mm_errorhandler) _mm_errorhandler();
} }
return fp; 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; if(!(fp=uio_fopen(dir, fname,"rb"))) return 0;
fclose(fp); uio_fclose(fp);
return 1; return 1;
} }
@@ -180,36 +180,36 @@ void _mm_iobase_revert(void)
typedef struct MFILEREADER { typedef struct MFILEREADER {
MREADER core; MREADER core;
FILE* file; uio_Stream* file;
} MFILEREADER; } MFILEREADER;
static BOOL _mm_FileReader_Eof(MREADER* reader) 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) 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) 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) 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); (whence==SEEK_SET)?offset+_mm_iobase:offset,whence);
} }
static long _mm_FileReader_Tell(MREADER* reader) 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)); MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER));
if (reader) { if (reader) {
@@ -232,30 +232,30 @@ void _mm_delete_file_reader (MREADER* reader)
typedef struct MFILEWRITER { typedef struct MFILEWRITER {
MWRITER core; MWRITER core;
FILE* file; uio_Stream* file;
} MFILEWRITER; } MFILEWRITER;
static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence) 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) 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) 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) 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)); MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER));
if (writer) { if (writer) {
@@ -143,7 +143,7 @@ SAMPLE* Sample_LoadGeneric(MREADER* reader)
return result; return result;
} }
SAMPLE* Sample_LoadFP(FILE *fp) SAMPLE* Sample_LoadFP(uio_Stream *fp)
{ {
SAMPLE* result=NULL; SAMPLE* result=NULL;
MREADER* reader; MREADER* reader;
@@ -155,15 +155,15 @@ SAMPLE* Sample_LoadFP(FILE *fp)
return result; return result;
} }
SAMPLE* Sample_Load(CHAR* filename) SAMPLE* Sample_Load(uio_DirHandle* dir,CHAR* filename)
{ {
FILE *fp; uio_Stream *fp;
SAMPLE *si=NULL; SAMPLE *si=NULL;
if(!(md_mode & DMODE_SOFT_SNDFX)) return 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); si = Sample_LoadFP(fp);
fclose(fp); uio_fclose(fp);
} }
return si; return si;
} }
+22 -21
View File
@@ -53,52 +53,52 @@ typedef struct
void void
LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format,
uint32 *freq, bool want_big_endian) void **data, uint32 *size, uint32 *freq, bool want_big_endian)
{ {
WAVChunkHdr_Struct ChunkHdr; WAVChunkHdr_Struct ChunkHdr;
WAVFileHdr_Struct FileHdr; WAVFileHdr_Struct FileHdr;
WAVFmtHdr_Struct FmtHdr; WAVFmtHdr_Struct FmtHdr;
FILE *fp; uio_Stream *fp;
*format = decoder_formats.mono16; *format = decoder_formats.mono16;
*data = NULL; *data = NULL;
*size = 0; *size = 0;
*freq = 22050; *freq = 22050;
fp = fopen (file, "rb"); fp = uio_fopen (dir, file, "rb");
if (fp) if (fp)
{ {
fread(&FileHdr.Id, 4, 1, fp); uio_fread(&FileHdr.Id, 4, 1, fp);
FileHdr.Id = UQM_SwapLE32 (FileHdr.Id); 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); 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.Type = UQM_SwapLE32 (FileHdr.Type);
FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4; FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4;
while (FileHdr.Size != 0) while (FileHdr.Size != 0)
{ {
if (!fread (&ChunkHdr.Id, 4, 1, fp)) if (!uio_fread (&ChunkHdr.Id, 4, 1, fp))
break; break;
ChunkHdr.Id = UQM_SwapLE32 (ChunkHdr.Id); ChunkHdr.Id = UQM_SwapLE32 (ChunkHdr.Id);
if (!fread (&ChunkHdr.Size, 4, 1, fp)) if (!uio_fread (&ChunkHdr.Size, 4, 1, fp))
break; break;
ChunkHdr.Size = UQM_SwapLE32 (ChunkHdr.Size); ChunkHdr.Size = UQM_SwapLE32 (ChunkHdr.Size);
if (ChunkHdr.Id == FMT) if (ChunkHdr.Id == FMT)
{ {
fread (&FmtHdr.Format, 2, 1, fp); uio_fread (&FmtHdr.Format, 2, 1, fp);
FmtHdr.Format = UQM_SwapLE16 (FmtHdr.Format); 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); 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); 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); 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); 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); FmtHdr.BitsPerSample = UQM_SwapLE16 (FmtHdr.BitsPerSample);
if (FmtHdr.Format == 0x0001) if (FmtHdr.Format == 0x0001)
@@ -112,12 +112,12 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
: decoder_formats.stereo16) : decoder_formats.stereo16)
); );
*freq = FmtHdr.SamplesPerSec; *freq = FmtHdr.SamplesPerSec;
fseek (fp, ChunkHdr.Size - 16, SEEK_CUR); uio_fseek (fp, ChunkHdr.Size - 16, SEEK_CUR);
} }
else else
{ {
fprintf (stderr, "LoadWAVFile(): unsupported format %x\n", FmtHdr.Format); fprintf (stderr, "LoadWAVFile(): unsupported format %x\n", FmtHdr.Format);
fclose (fp); uio_fclose (fp);
return; return;
} }
} }
@@ -125,18 +125,18 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
{ {
*size = ChunkHdr.Size; *size = ChunkHdr.Size;
if ((*data = HMalloc (ChunkHdr.Size + 31))) 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); memset(((char *)*data) + ChunkHdr.Size, 0, 31);
} }
else 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); FileHdr.Size -= (((ChunkHdr.Size + 1) & ~1) + 8);
} }
fclose(fp); uio_fclose(fp);
} }
if (want_big_endian && if (want_big_endian &&
@@ -148,3 +148,4 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size,
if (*size == 0) if (*size == 0)
fprintf (stderr, "LoadWAVFile(): loading %s failed!\n", file); fprintf (stderr, "LoadWAVFile(): loading %s failed!\n", file);
} }
+4 -2
View File
@@ -19,9 +19,11 @@
#ifndef WAV_H #ifndef WAV_H
#define WAV_H #define WAV_H
#include "port.h"
#include "types.h" #include "types.h"
#include "uio.h"
void LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, void LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format,
uint32 *freq, bool want_big_endian); void **data, uint32 *size, uint32 *freq, bool want_big_endian);
#endif #endif
+5 -4
View File
@@ -17,20 +17,21 @@
*/ */
#include "sndintrn.h" #include "sndintrn.h"
#include "options.h"
extern char *_cur_resfile_name; extern char *_cur_resfile_name;
SOUND_REF SOUND_REF
LoadSoundFile (PVOID pStr) LoadSoundFile (PVOID pStr)
{ {
FILE *fp; uio_Stream *fp;
// FIXME: this theoretically needs a mechanism to prevent races // FIXME: this theoretically needs a mechanism to prevent races
if (_cur_resfile_name) if (_cur_resfile_name)
// something else is loading resources atm // something else is loading resources atm
return 0; return 0;
fp = res_OpenResFile (pStr, "rb"); fp = res_OpenResFile (contentDir, pStr, "rb");
if (fp) if (fp)
{ {
MEM_HANDLE hData; MEM_HANDLE hData;
@@ -50,14 +51,14 @@ LoadSoundFile (PVOID pStr)
MUSIC_REF MUSIC_REF
LoadMusicFile (PVOID pStr) LoadMusicFile (PVOID pStr)
{ {
FILE *fp; uio_Stream *fp;
// FIXME: this theoretically needs a mechanism to prevent races // FIXME: this theoretically needs a mechanism to prevent races
if (_cur_resfile_name) if (_cur_resfile_name)
// something else is loading resources atm // something else is loading resources atm
return 0; return 0;
fp = res_OpenResFile (pStr, "rb"); fp = res_OpenResFile (contentDir, pStr, "rb");
if (fp) if (fp)
{ {
MEM_HANDLE hData; MEM_HANDLE hData;
+4 -3
View File
@@ -107,7 +107,7 @@ SetMusicVolume (COUNT Volume)
} }
MEM_HANDLE MEM_HANDLE
_GetMusicData (FILE *fp, DWORD length) _GetMusicData (uio_Stream *fp, DWORD length)
{ {
MEM_HANDLE h; MEM_HANDLE h;
extern char *_cur_resfile_name; extern char *_cur_resfile_name;
@@ -142,7 +142,7 @@ _GetMusicData (FILE *fp, DWORD length)
strcpy (threedoname, filename); strcpy (threedoname, filename);
strcpy (&threedoname[strlen (threedoname)-3], "ogg"); strcpy (&threedoname[strlen (threedoname)-3], "ogg");
if (fileExists (threedoname)) if (fileExists2 (contentDir, threedoname))
{ {
strcpy (filename, threedoname); strcpy (filename, threedoname);
} }
@@ -155,7 +155,8 @@ _GetMusicData (FILE *fp, DWORD length)
} }
fprintf (stderr, "_GetMusicData(): loading %s\n", filename); 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); fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename);
+7 -14
View File
@@ -165,11 +165,8 @@ GetSampleRate (SOUND sound)
} }
MEM_HANDLE MEM_HANDLE
_GetSoundBankData (FILE *fp, DWORD length) _GetSoundBankData (uio_Stream *fp, DWORD length)
{ {
#ifdef WIN32
int omode;
#endif
int snd_ct, n; int snd_ct, n;
DWORD opos; DWORD opos;
char CurrentLine[1024], filename[1024]; char CurrentLine[1024], filename[1024];
@@ -178,7 +175,7 @@ _GetSoundBankData (FILE *fp, DWORD length)
STRING_TABLE Snd; STRING_TABLE Snd;
(void) length; // ignored (void) length; // ignored
opos = ftell (fp); opos = uio_ftell (fp);
{ {
char *s1, *s2; char *s1, *s2;
@@ -197,11 +194,9 @@ _GetSoundBankData (FILE *fp, DWORD length)
} }
} }
#ifdef WIN32
omode = _setmode (fileno (fp), O_TEXT);
#endif
snd_ct = 0; 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) 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]->buffer_tag = 0;
sndfx[snd_ct]->read_chain_ptr = NULL; 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) if (!sndfx[snd_ct]->decoder)
{ {
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); 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) // 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;*/ break;*/
} }
#ifdef WIN32
_setmode (fileno (fp), omode);
#endif
Snd = 0; Snd = 0;
if (snd_ct && (Snd = AllocStringTable ( if (snd_ct && (Snd = AllocStringTable (
+2 -2
View File
@@ -23,10 +23,10 @@
#include "sndlib.h" #include "sndlib.h"
#include "reslib.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 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); extern BOOLEAN _ReleaseSoundBankData (MEM_HANDLE handle);
#define AllocMusicData(s) AllocResourceData((s),MEM_ZEROINIT) #define AllocMusicData(s) AllocResourceData((s),MEM_ZEROINIT)
+7 -3
View File
@@ -19,6 +19,7 @@
#include "sound.h" #include "sound.h"
#include "libs/sound/trackplayer.h" #include "libs/sound/trackplayer.h"
#include "comm.h" #include "comm.h"
#include "options.h"
static int tct; //total number of subtitle tracks static int tct; //total number of subtitle tracks
static int tcur; //currently playing subtitle track static int tcur; //currently playing subtitle track
@@ -316,7 +317,8 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
fprintf (stderr, "SpliceMultiTrack(): loading...\n"); fprintf (stderr, "SpliceMultiTrack(): loading...\n");
for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++) 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]) if (track_decs[tracks])
{ {
fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n", 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_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers);
sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers); sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers);
TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); 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->read_chain_ptr = create_soundchain (decoder, 0.0);
sound_sample->decoder = decoder; sound_sample->decoder = decoder;
first_chain = last_chain = sound_sample->read_chain_ptr; first_chain = last_chain = sound_sample->read_chain_ptr;
@@ -481,7 +484,8 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
else else
{ {
TFB_SoundDecoder *decoder; 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->next = create_soundchain (decoder, sound_sample->length);
last_chain = last_chain->next; last_chain = last_chain->next;
} }
+11 -18
View File
@@ -18,6 +18,7 @@
#include "strintrn.h" #include "strintrn.h"
#include "libs/graphics/gfx_common.h" #include "libs/graphics/gfx_common.h"
#include "options.h"
#ifdef WIN32 #ifdef WIN32
#include <io.h> #include <io.h>
#endif #endif
@@ -39,7 +40,7 @@ dword_convert (PDWORD dword_array, COUNT num_dwords)
} }
MEM_HANDLE MEM_HANDLE
_GetStringData (FILE *fp, DWORD length) _GetStringData (uio_Stream *fp, DWORD length)
{ {
MEM_HANDLE hData; MEM_HANDLE hData;
@@ -51,16 +52,13 @@ _GetStringData (FILE *fp, DWORD length)
{ {
#define MAX_STRINGS 2048 #define MAX_STRINGS 2048
#define POOL_SIZE 4096 #define POOL_SIZE 4096
#ifdef WIN32
int omode;
#endif
int n, path_len, num_data_sets; int n, path_len, num_data_sets;
DWORD opos, DWORD opos,
slen[MAX_STRINGS], StringOffs, tot_string_size, slen[MAX_STRINGS], StringOffs, tot_string_size,
clen[MAX_STRINGS], ClipOffs, tot_clip_size, clen[MAX_STRINGS], ClipOffs, tot_clip_size,
tslen[MAX_STRINGS], TSOffs, tot_ts_size; tslen[MAX_STRINGS], TSOffs, tot_ts_size;
char CurrentLine[1024], clip_path[1024], *strdata, *clipdata, *ts_data; 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) if ((strdata = HMalloc (tot_string_size = POOL_SIZE)) == 0)
return (0); return (0);
@@ -97,7 +95,8 @@ _GetStringData (FILE *fp, DWORD length)
s += 2; s += 2;
*s++ = 's'; *s++ = 's';
*s = '\0'; *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); fprintf (stderr, "Found timestamp file: %s\n", ts_file_name);
if ((ts_data = HMalloc (tot_ts_size = POOL_SIZE)) == 0) if ((ts_data = HMalloc (tot_ts_size = POOL_SIZE)) == 0)
@@ -105,13 +104,10 @@ _GetStringData (FILE *fp, DWORD length)
} }
} }
opos = ftell (fp); opos = uio_ftell (fp);
#ifdef WIN32
omode = _setmode (fileno (fp), O_TEXT);
#endif
n = -1; n = -1;
StringOffs = ClipOffs = TSOffs = 0; 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; int l;
@@ -139,7 +135,7 @@ _GetStringData (FILE *fp, DWORD length)
{ {
char TimeStampLine[1024], *tsptr; char TimeStampLine[1024], *tsptr;
BOOLEAN ts_ok = FALSE; BOOLEAN ts_ok = FALSE;
fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp); uio_fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp);
if (TimeStampLine[0] == '#') if (TimeStampLine[0] == '#')
{ {
tslen[n] = 0; tslen[n] = 0;
@@ -171,7 +167,7 @@ _GetStringData (FILE *fp, DWORD length)
// timestamp data is invalid, remove all of it // timestamp data is invalid, remove all of it
fprintf (stderr, "Invalid timestamp data for '%s'. Disabling timestamps\n", s); fprintf (stderr, "Invalid timestamp data for '%s'. Disabling timestamps\n", s);
HFree (ts_data); HFree (ts_data);
fclose (timestamp_fp); uio_fclose (timestamp_fp);
timestamp_fp = NULL; timestamp_fp = NULL;
TSOffs = 0; TSOffs = 0;
} }
@@ -219,12 +215,9 @@ _GetStringData (FILE *fp, DWORD length)
strcpy (s, CurrentLine); strcpy (s, CurrentLine);
} }
if ((int)ftell (fp) - (int)opos >= (int)length) if ((int)uio_ftell (fp) - (int)opos >= (int)length)
break; break;
} }
#ifdef WIN32
_setmode (fileno (fp), omode);
#endif
if (n >= 0) if (n >= 0)
{ {
while (slen[n] > 1 && strdata[StringOffs - 2] == '\n') while (slen[n] > 1 && strdata[StringOffs - 2] == '\n')
@@ -236,7 +229,7 @@ _GetStringData (FILE *fp, DWORD length)
} }
if (timestamp_fp) if (timestamp_fp)
fclose (timestamp_fp); uio_fclose (timestamp_fp);
hData = 0; hData = 0;
num_data_sets = (ClipOffs ? 1 : 0) + (TSOffs ? 1 : 0) + 1; num_data_sets = (ClipOffs ? 1 : 0) + (TSOffs ? 1 : 0) + 1;
+6 -4
View File
@@ -16,26 +16,28 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "port.h"
#include "strintrn.h" #include "strintrn.h"
#include "uio.h"
extern char *_cur_resfile_name; extern char *_cur_resfile_name;
STRING_TABLE 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 // FIXME: this theoretically needs a mechanism to prevent races
if (_cur_resfile_name) if (_cur_resfile_name)
// something else is loading resources atm // something else is loading resources atm
return 0; return 0;
fp = res_OpenResFile (pStr, "rb"); fp = res_OpenResFile (dir, fileName, "rb");
if (fp) if (fp)
{ {
MEM_HANDLE hData; MEM_HANDLE hData;
_cur_resfile_name = pStr; _cur_resfile_name = fileName;
hData = _GetStringData (fp, LengthResFile (fp)); hData = _GetStringData (fp, LengthResFile (fp));
_cur_resfile_name = 0; _cur_resfile_name = 0;
res_CloseResFile (fp); res_CloseResFile (fp);
+1 -1
View File
@@ -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(h,i) ((STRING_TABLE)MAKE_DWORD(h,i))
#define BUILD_STRING_TABLE(h) (STRING_TABLE)(h) #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 */ #endif /* _STRINTRN_H */
+4 -1
View File
@@ -20,6 +20,8 @@
#define _STRLIB_H #define _STRLIB_H
#include "compiler.h" #include "compiler.h"
#include "port.h"
#include "libs/uio.h"
typedef DWORD STRING_TABLE; typedef DWORD STRING_TABLE;
typedef DWORD STRING; typedef DWORD STRING;
@@ -27,7 +29,8 @@ typedef PBYTE STRINGPTR;
extern BOOLEAN InstallStringTableResType (COUNT string_type); extern BOOLEAN InstallStringTableResType (COUNT string_type);
extern STRING_TABLE LoadStringTableInstance (DWORD res); 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 BOOLEAN DestroyStringTable (STRING_TABLE StringTable);
extern STRING CaptureStringTable (STRING_TABLE StringTable); extern STRING CaptureStringTable (STRING_TABLE StringTable);
extern STRING_TABLE ReleaseStringTable (STRING String); extern STRING_TABLE ReleaseStringTable (STRING String);
+27
View File
@@ -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 */
+350
View File
@@ -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.
+17
View File
@@ -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
+77
View File
@@ -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);
}
+37
View File
@@ -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 */
+764
View File
@@ -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;
}
+29
View File
@@ -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 */
+41
View File
@@ -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];
}
+41
View File
@@ -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 */
+140
View File
@@ -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
+29
View File
@@ -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.
+177
View File
@@ -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.
+107
View File
@@ -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
+184
View File
@@ -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);
}
+52
View File
@@ -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 */
+271
View File
@@ -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);
}
+110
View File
@@ -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 */
+618
View File
@@ -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
+313
View File
@@ -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 */
+338
View File
@@ -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);
}
+141
View File
@@ -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
+139
View File
@@ -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 */
+780
View File
@@ -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;
}
+49
View File
@@ -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 */
+181
View File
@@ -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 */
+546
View File
@@ -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 */
+180
View File
@@ -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 */
+59
View File
@@ -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
+292
View File
@@ -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);
}
+96
View File
@@ -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 */
+168
View File
@@ -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);
}
+64
View File
@@ -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 */
+928
View File
@@ -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);
}
+217
View File
@@ -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 */
+186
View File
@@ -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;
}
+46
View File
@@ -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 */
+129
View File
@@ -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);
}
+74
View File
@@ -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 */
+3
View File
@@ -0,0 +1,3 @@
uqm_CFILES="stdio.c"
+729
View File
@@ -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);
}
+109
View File
@@ -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);
+42
View File
@@ -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 */
+119
View File
@@ -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 */
+575
View File
@@ -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);
}
+109
View File
@@ -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