From f7c97f2ba72519b465d4b66a6ec38ef463751485 Mon Sep 17 00:00:00 2001 From: meep-eep Date: Tue, 8 Jul 2003 18:17:40 +0000 Subject: [PATCH] New io/packaging system. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1035 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/build.vars.in | 3 +- sc2/build/unix/build.config | 17 +- sc2/build/unix/config_proginfo | 5 + sc2/src/msvc++/UrQuanMasters.dsp | 198 ++- sc2/src/options.c | 146 +- sc2/src/options.h | 11 +- sc2/src/port.h | 46 + sc2/src/sc2code/demo.c | 4 +- sc2/src/sc2code/dummy.c | 2 +- sc2/src/sc2code/grpinfo.c | 15 +- sc2/src/sc2code/init.c | 29 + sc2/src/sc2code/libs/Makeinfo | 2 +- sc2/src/sc2code/libs/decomp/lzencode.c | 2 +- sc2/src/sc2code/libs/decomp/lzh.h | 4 +- sc2/src/sc2code/libs/file.h | 49 +- sc2/src/sc2code/libs/file/files.c | 85 +- sc2/src/sc2code/libs/file/temp.c | 82 +- sc2/src/sc2code/libs/graphics/drawable.h | 2 +- sc2/src/sc2code/libs/graphics/filegfx.c | 5 +- sc2/src/sc2code/libs/graphics/font.h | 2 +- .../sc2code/libs/graphics/sdl/3do_getbody.c | 55 +- sc2/src/sc2code/libs/graphics/sdl/Makeinfo | 2 +- .../sc2code/libs/graphics/sdl/sdl_common.c | 2 +- sc2/src/sc2code/libs/graphics/sdl/sdluio.c | 110 ++ sc2/src/sc2code/libs/graphics/sdl/sdluio.h | 17 + sc2/src/sc2code/libs/input/sdl/input.c | 42 +- sc2/src/sc2code/libs/input/sdl/vcontrol.c | 14 +- sc2/src/sc2code/libs/input/sdl/vcontrol.h | 4 +- sc2/src/sc2code/libs/reslib.h | 37 +- sc2/src/sc2code/libs/resource/direct.c | 326 +--- sc2/src/sc2code/libs/resource/filecntl.c | 75 +- sc2/src/sc2code/libs/resource/getres.c | 7 +- sc2/src/sc2code/libs/resource/index.h | 4 +- sc2/src/sc2code/libs/resource/loadres.c | 2 +- sc2/src/sc2code/libs/resource/resinit.c | 15 +- sc2/src/sc2code/libs/resource/resintrn.h | 2 +- sc2/src/sc2code/libs/sound/decoders/decoder.c | 52 +- sc2/src/sc2code/libs/sound/decoders/decoder.h | 7 +- .../libs/sound/decoders/mikmod/mikmod.h | 12 +- .../sound/decoders/mikmod/mikmod_internals.h | 10 +- .../libs/sound/decoders/mikmod/mloader.c | 20 +- .../sc2code/libs/sound/decoders/mikmod/mmio.c | 44 +- .../sc2code/libs/sound/decoders/mikmod/mwav.c | 10 +- sc2/src/sc2code/libs/sound/decoders/wav.c | 43 +- sc2/src/sc2code/libs/sound/decoders/wav.h | 6 +- sc2/src/sc2code/libs/sound/fileinst.c | 9 +- sc2/src/sc2code/libs/sound/music.c | 15 +- sc2/src/sc2code/libs/sound/sfx.c | 21 +- sc2/src/sc2code/libs/sound/sndintrn.h | 4 +- sc2/src/sc2code/libs/sound/trackplayer.c | 10 +- sc2/src/sc2code/libs/strings/getstr.c | 29 +- sc2/src/sc2code/libs/strings/sfileins.c | 10 +- sc2/src/sc2code/libs/strings/strintrn.h | 2 +- sc2/src/sc2code/libs/strlib.h | 5 +- sc2/src/sc2code/libs/uio.h | 27 + sc2/src/sc2code/libs/uio/COPYING | 350 +++++ sc2/src/sc2code/libs/uio/Makeinfo | 17 + sc2/src/sc2code/libs/uio/charhashtable.c | 77 + sc2/src/sc2code/libs/uio/charhashtable.h | 37 + sc2/src/sc2code/libs/uio/debug.c | 764 +++++++++ sc2/src/sc2code/libs/uio/debug.h | 29 + sc2/src/sc2code/libs/uio/defaultfs.c | 41 + sc2/src/sc2code/libs/uio/defaultfs.h | 41 + sc2/src/sc2code/libs/uio/doc/basics | 140 ++ sc2/src/sc2code/libs/uio/doc/conventions | 29 + sc2/src/sc2code/libs/uio/doc/notes | 177 +++ sc2/src/sc2code/libs/uio/doc/todo | 107 ++ sc2/src/sc2code/libs/uio/fileblock.c | 184 +++ sc2/src/sc2code/libs/uio/fileblock.h | 52 + sc2/src/sc2code/libs/uio/fstypes.c | 271 ++++ sc2/src/sc2code/libs/uio/fstypes.h | 110 ++ sc2/src/sc2code/libs/uio/gphys.c | 618 ++++++++ sc2/src/sc2code/libs/uio/gphys.h | 313 ++++ sc2/src/sc2code/libs/uio/hashtable.c | 338 ++++ sc2/src/sc2code/libs/uio/hashtable.h | 141 ++ sc2/src/sc2code/libs/uio/io.c | 1371 +++++++++++++++++ sc2/src/sc2code/libs/uio/io.h | 139 ++ sc2/src/sc2code/libs/uio/ioaux.c | 780 ++++++++++ sc2/src/sc2code/libs/uio/ioaux.h | 49 + sc2/src/sc2code/libs/uio/iointrn.h | 181 +++ sc2/src/sc2code/libs/uio/match.c | 546 +++++++ sc2/src/sc2code/libs/uio/match.h | 180 +++ sc2/src/sc2code/libs/uio/mem.h | 59 + sc2/src/sc2code/libs/uio/memdebug.c | 292 ++++ sc2/src/sc2code/libs/uio/memdebug.h | 96 ++ sc2/src/sc2code/libs/uio/mount.c | 168 ++ sc2/src/sc2code/libs/uio/mount.h | 64 + sc2/src/sc2code/libs/uio/mounttree.c | 928 +++++++++++ sc2/src/sc2code/libs/uio/mounttree.h | 217 +++ sc2/src/sc2code/libs/uio/paths.c | 186 +++ sc2/src/sc2code/libs/uio/paths.h | 46 + sc2/src/sc2code/libs/uio/physical.c | 129 ++ sc2/src/sc2code/libs/uio/physical.h | 74 + sc2/src/sc2code/libs/uio/stdio/Makeinfo | 3 + sc2/src/sc2code/libs/uio/stdio/stdio.c | 729 +++++++++ sc2/src/sc2code/libs/uio/stdio/stdio.h | 109 ++ sc2/src/sc2code/libs/uio/types.h | 42 + sc2/src/sc2code/libs/uio/uioport.h | 119 ++ sc2/src/sc2code/libs/uio/uiostream.c | 575 +++++++ sc2/src/sc2code/libs/uio/uiostream.h | 109 ++ sc2/src/sc2code/libs/uio/uioutils.c | 200 +++ sc2/src/sc2code/libs/uio/uioutils.h | 92 ++ sc2/src/sc2code/libs/uio/zip/Makeinfo | 3 + sc2/src/sc2code/libs/uio/zip/zip.c | 1360 ++++++++++++++++ sc2/src/sc2code/libs/uio/zip/zip.h | 92 ++ sc2/src/sc2code/load.c | 16 +- sc2/src/sc2code/melee.c | 72 +- sc2/src/sc2code/save.c | 16 +- sc2/src/sc2code/shipyard.c | 3 +- sc2/src/sc2code/starcon.h | 13 +- sc2/src/sc2code/state.c | 6 +- sc2/src/starcon2.c | 25 +- 112 files changed, 13922 insertions(+), 762 deletions(-) create mode 100644 sc2/src/sc2code/libs/graphics/sdl/sdluio.c create mode 100644 sc2/src/sc2code/libs/graphics/sdl/sdluio.h create mode 100644 sc2/src/sc2code/libs/uio.h create mode 100644 sc2/src/sc2code/libs/uio/COPYING create mode 100644 sc2/src/sc2code/libs/uio/Makeinfo create mode 100644 sc2/src/sc2code/libs/uio/charhashtable.c create mode 100644 sc2/src/sc2code/libs/uio/charhashtable.h create mode 100644 sc2/src/sc2code/libs/uio/debug.c create mode 100644 sc2/src/sc2code/libs/uio/debug.h create mode 100644 sc2/src/sc2code/libs/uio/defaultfs.c create mode 100644 sc2/src/sc2code/libs/uio/defaultfs.h create mode 100644 sc2/src/sc2code/libs/uio/doc/basics create mode 100644 sc2/src/sc2code/libs/uio/doc/conventions create mode 100644 sc2/src/sc2code/libs/uio/doc/notes create mode 100644 sc2/src/sc2code/libs/uio/doc/todo create mode 100644 sc2/src/sc2code/libs/uio/fileblock.c create mode 100644 sc2/src/sc2code/libs/uio/fileblock.h create mode 100644 sc2/src/sc2code/libs/uio/fstypes.c create mode 100644 sc2/src/sc2code/libs/uio/fstypes.h create mode 100644 sc2/src/sc2code/libs/uio/gphys.c create mode 100644 sc2/src/sc2code/libs/uio/gphys.h create mode 100644 sc2/src/sc2code/libs/uio/hashtable.c create mode 100644 sc2/src/sc2code/libs/uio/hashtable.h create mode 100644 sc2/src/sc2code/libs/uio/io.c create mode 100644 sc2/src/sc2code/libs/uio/io.h create mode 100644 sc2/src/sc2code/libs/uio/ioaux.c create mode 100644 sc2/src/sc2code/libs/uio/ioaux.h create mode 100644 sc2/src/sc2code/libs/uio/iointrn.h create mode 100644 sc2/src/sc2code/libs/uio/match.c create mode 100644 sc2/src/sc2code/libs/uio/match.h create mode 100644 sc2/src/sc2code/libs/uio/mem.h create mode 100644 sc2/src/sc2code/libs/uio/memdebug.c create mode 100644 sc2/src/sc2code/libs/uio/memdebug.h create mode 100644 sc2/src/sc2code/libs/uio/mount.c create mode 100644 sc2/src/sc2code/libs/uio/mount.h create mode 100644 sc2/src/sc2code/libs/uio/mounttree.c create mode 100644 sc2/src/sc2code/libs/uio/mounttree.h create mode 100644 sc2/src/sc2code/libs/uio/paths.c create mode 100644 sc2/src/sc2code/libs/uio/paths.h create mode 100644 sc2/src/sc2code/libs/uio/physical.c create mode 100644 sc2/src/sc2code/libs/uio/physical.h create mode 100644 sc2/src/sc2code/libs/uio/stdio/Makeinfo create mode 100644 sc2/src/sc2code/libs/uio/stdio/stdio.c create mode 100644 sc2/src/sc2code/libs/uio/stdio/stdio.h create mode 100644 sc2/src/sc2code/libs/uio/types.h create mode 100644 sc2/src/sc2code/libs/uio/uioport.h create mode 100644 sc2/src/sc2code/libs/uio/uiostream.c create mode 100644 sc2/src/sc2code/libs/uio/uiostream.h create mode 100644 sc2/src/sc2code/libs/uio/uioutils.c create mode 100644 sc2/src/sc2code/libs/uio/uioutils.h create mode 100644 sc2/src/sc2code/libs/uio/zip/Makeinfo create mode 100644 sc2/src/sc2code/libs/uio/zip/zip.c create mode 100644 sc2/src/sc2code/libs/uio/zip/zip.h diff --git a/sc2/build.vars.in b/sc2/build.vars.in index 750bda014..498f6ae70 100644 --- a/sc2/build.vars.in +++ b/sc2/build.vars.in @@ -28,6 +28,7 @@ uqm_INSTALL_LIBDIR="@INSTALL_LIBDIR@" # Non-exported files only where build.vars is explicitely included. uqm_SOUNDMODULE="@SOUNDMODULE@" uqm_HAVE_OPENGL="@HAVE_OPENGL@" +uqm_USE_ZIP_IO="@USE_ZIP_IO@" WINDRES="@WINDRES@" -export uqm_SOUNDMODULE uqm_HAVE_OPENGL WINDRES +export uqm_SOUNDMODULE uqm_HAVE_OPENGL uqm_USE_ZIP_IO WINDRES diff --git a/sc2/build/unix/build.config b/sc2/build/unix/build.config index cf368e4e3..132deec83 100644 --- a/sc2/build/unix/build.config +++ b/sc2/build/unix/build.config @@ -38,11 +38,12 @@ define_have_header getopt.h # Describe the menu: -MENU_main_ITEMS="debug graphics sound install_path" +MENU_main_ITEMS="debug graphics sound ioformat install_path" MENU_main_TITLE="Main menu" MENU_main_ITEM_debug_TYPE=CHOICE MENU_main_ITEM_graphics_TYPE=CHOICE MENU_main_ITEM_sound_TYPE=CHOICE +MENU_main_ITEM_ioformat_TYPE=CHOICE MENU_main_ITEM_link_TYPE=CHOICE MENU_main_ITEM_install_path_TYPE=MENU @@ -134,6 +135,19 @@ sound_openal_action() { } CHOICE_sound_DEFAULT=mixsdl +CHOICE_ioformat_OPTIONS="stdio stdio_zip" +CHOICE_ioformat_TITLE="Supported file i/o methods" +CHOICE_ioformat_OPTION_stdio_TITLE="Only direct file i/o" +CHOICE_ioformat_OPTION_stdio_zip_TITLE="Direct & .zip file i/o" +CHOICE_ioformat_OPTION_stdio_zip_PRECOND="have_library zlib" +CHOICE_ioformat_OPTION_stdio_zip_ACTION="ioformat_stdio_zip_action" +ioformat_stdio_zip_action() { + CFLAGS="$CFLAGS -DHAVE_ZIP=1" + USE_ZIP_IO=1 + use_library zlib +} +CHOICE_ioformat_DEFAULT=stdio_zip + # Making static binaries is more complicated than this. # For now, it will have to be done by hand. #CHOICE_link_OPTIONS="static dynamic" @@ -185,6 +199,7 @@ substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES # Make build.vars from build.vars.in, substituting variables. SUBSTITUTE_VARS="CFLAGS LDFLAGS MAKE DEBUG SOUNDMODULE HAVE_OPENGL \ + USE_ZIP_IO \ INSTALL_LIBDIR INSTALL_BINDIR WINDRES" SUBSTITUTE_FILES="build.vars" substitute_vars SUBSTITUTE_VARS SUBSTITUTE_FILES diff --git a/sc2/build/unix/config_proginfo b/sc2/build/unix/config_proginfo index 2a6df9bf6..7e52859ea 100644 --- a/sc2/build/unix/config_proginfo +++ b/sc2/build/unix/config_proginfo @@ -125,3 +125,8 @@ case "$OSNAME" in esac LIB_vorbisfile_VERSION="" +LIB_zlib_NAME="zlib" +LIB_zlib_CFLAGS="" +LIB_zlib_LDFLAGS="" +LIB_zlib_VERSION="" + diff --git a/sc2/src/msvc++/UrQuanMasters.dsp b/sc2/src/msvc++/UrQuanMasters.dsp index 46e3b2313..d7050b9d9 100644 --- a/sc2/src/msvc++/UrQuanMasters.dsp +++ b/sc2/src/msvc++/UrQuanMasters.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /D "HAVE_ZIP" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../uqm.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib zlib.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../uqm.exe" !ELSEIF "$(CFG)" == "UrQuanMasters - Win32 Debug" @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "DEBUG_TRACK_SEM" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "DEBUG_TRACK_SEM" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /D "HAVE_ZIP" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -74,7 +74,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo /o"UrQuanMasters.bsc" LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../uqmdebug.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib zlib.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../uqmdebug.exe" /pdbtype:sept # SUBTRACT LINK32 /nodefaultlib !ENDIF @@ -220,6 +220,14 @@ SOURCE=..\sc2code\libs\graphics\sdl\rndzoom.c # End Source File # Begin Source File +SOURCE=..\sc2code\libs\graphics\sdl\sdluio.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\graphics\sdl\sdluio.h +# End Source File +# Begin Source File + SOURCE=..\sc2code\libs\graphics\sdl\sdl_common.c # End Source File # Begin Source File @@ -814,8 +822,188 @@ SOURCE=..\sc2code\libs\timelib.h # End Source File # Begin Source File -SOURCE=..\sc2code\libs\vidlib.h +SOURCE=..\sc2code\libs\uio.h # End Source File +# Begin Group "uio" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc2code\libs\uio\charhashtable.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\charhashtable.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\debug.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\debug.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\defaultfs.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\defaultfs.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\fileblock.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\fileblock.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\fstypes.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\fstypes.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\gphys.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\gphys.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\io.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\io.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\ioaux.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\ioaux.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\iointrn.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\match.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\match.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\mem.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\memdebug.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\memdebug.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\mount.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\mount.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\mounttree.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\mounttree.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\paths.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\paths.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\physical.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\physical.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\uiostream.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\uiostream.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\types.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\uioport.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\uioutils.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\uioutils.h +# End Source File +# Begin Group "stdio" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc2code\libs\uio\stdio\stdio.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\stdio\stdio.h +# End Source File +# End Group +# Begin Group "zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc2code\libs\uio\zip\zip.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\uio\zip\zip.h +# End Source File +# End Group +# End Group # End Group # Begin Group "comm" diff --git a/sc2/src/options.c b/sc2/src/options.c index 28e7c16db..b42f8b290 100644 --- a/sc2/src/options.c +++ b/sc2/src/options.c @@ -22,11 +22,14 @@ #include #include #include +#include +#include "port.h" #include "libs/graphics/gfx_common.h" #include "compiler.h" #include "options.h" #include "file.h" #include "config.h" +#include "libs/uio.h" int optWhichMusic = OPT_3DO; int optWhichCoarseScan = OPT_3DO; @@ -35,61 +38,176 @@ int optWhichFonts = OPT_PC; int optSmoothScroll = OPT_PC; int optMeleeScale = TFB_SCALE_TRILINEAR; -char *configDir, *saveDir, *meleeDir; BOOLEAN optSubtitles = TRUE; BOOLEAN optStereoSFX = FALSE; +uio_DirHandle *contentDir; +uio_DirHandle *configDir; +uio_DirHandle *saveDir; +uio_DirHandle *meleeDir; + +extern uio_Repository *repository; +extern uio_DirHandle *rootDir; + + +static void mountContentDir (uio_Repository *repository, + const char *contentPath); + +void +prepareContentDir (char *contentDirName) +{ + const char *testfile = "version"; + char cwd[PATH_MAX]; + + if (!fileExists (testfile)) + { + if ((chdir (contentDirName) || !fileExists (testfile)) && + (chdir ("content") || !fileExists (testfile)) && + (chdir ("../../content") || !fileExists (testfile))) { + fprintf (stderr, "Fatal error: content not available, running from wrong dir?\n"); + exit (EXIT_FAILURE); + } + } + if (getcwd(cwd, sizeof cwd) == NULL) { + fprintf (stderr, "Fatal error: Could not get the current " + "directory.\n"); + exit (EXIT_FAILURE); + } + mountContentDir (repository, cwd); +} void prepareConfigDir (void) { - configDir = malloc (PATH_MAX - 13); - if (expandPath (configDir, PATH_MAX - 13, CONFIGDIR) == -1) + char buf[PATH_MAX]; + static uio_AutoMount *autoMount[] = { NULL }; + uio_MountHandle *contentHandle; + + if (expandPath (buf, PATH_MAX - 13, CONFIGDIR) == -1) { // Doesn't have to be fatal, but might mess up things when saving // config files. fprintf (stderr, "Fatal error: Invalid path to config files.\n"); exit (EXIT_FAILURE); } - configDir = realloc (configDir, strlen (configDir) + 1); // Create the path upto the config dir, if not already existing. - if (mkdirhier (configDir) == -1) + if (mkdirhier (buf) == -1) exit (EXIT_FAILURE); + + contentHandle = uio_mountDir (repository, "/", + uio_FSTYPE_STDIO, NULL, NULL, buf, autoMount, + uio_MOUNT_TOP, NULL); + if (contentHandle == NULL) { + fprintf (stderr, "Fatal error: Couldn't mount content dir: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + } + + configDir = uio_openDir (repository, "/", 0); + if (configDir == NULL) { + fprintf (stderr, "Fatal error: Could not open config dir: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + } } void prepareSaveDir (void) { - saveDir = malloc (PATH_MAX - 13); - if (expandPath (saveDir, PATH_MAX - 13, SAVEDIR) == -1) + char buf[PATH_MAX]; + if (expandPath (buf, PATH_MAX - 13, SAVEDIR) == -1) { // Doesn't have to be fatal, but might mess up things when saving // config files. fprintf (stderr, "Fatal error: Invalid path to config files.\n"); exit (EXIT_FAILURE); } - saveDir = realloc (saveDir, strlen (saveDir) + 1); // Create the path upto the save dir, if not already existing. - if (mkdirhier (saveDir) == -1) + if (mkdirhier (buf) == -1) exit (EXIT_FAILURE); //#ifdef DEBUG - fprintf(stderr, "Saved games are kept in %s.\n", saveDir); + fprintf(stderr, "Saved games are kept in %s.\n", buf); //#endif + + saveDir = uio_openDirRelative (configDir, "save", 0); + if (saveDir == NULL) { + fprintf (stderr, "Fatal error: Could not open save dir: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + } } void prepareMeleeDir (void) { - meleeDir = malloc (PATH_MAX - 13); - if (expandPath (meleeDir, PATH_MAX - 13, MELEEDIR) == -1) + char buf[PATH_MAX]; + + if (expandPath (buf, PATH_MAX - 13, MELEEDIR) == -1) { // Doesn't have to be fatal, but might mess up things when saving // config files. fprintf (stderr, "Fatal error: Invalid path to config files.\n"); exit (EXIT_FAILURE); } - meleeDir = realloc (meleeDir, strlen (meleeDir) + 1); // Create the path upto the save dir, if not already existing. - if (mkdirhier (meleeDir) == -1) + if (mkdirhier (buf) == -1) exit (EXIT_FAILURE); + + meleeDir = uio_openDirRelative (configDir, "teams", 0); + if (meleeDir == NULL) { + fprintf (stderr, "Fatal error: Could not open melee teams dir: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + } } +static void +mountContentDir (uio_Repository *repository, const char *contentPath) { + uio_MountHandle *contentHandle; + uio_DirHandle *packagesDir; + static uio_AutoMount *autoMount[] = { NULL }; + + contentHandle = uio_mountDir (repository, "/", + uio_FSTYPE_STDIO, NULL, NULL, contentPath, autoMount, + uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL); + if (contentHandle == NULL) { + fprintf (stderr, "Fatal error: Couldn't mount content dir: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + } + + contentDir = uio_openDir (repository, "/", 0); + if (contentDir == NULL) { + fprintf (stderr, "Fatal error: Could not open content dir: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + } + + packagesDir = uio_openDir (repository, "/packages", 0); + if (packagesDir == NULL) { + // No packages dir means no packages to load. + return; + } + + { + uio_DirList *dirList; + + dirList = uio_getDirList(packagesDir, "", ".zip", match_MATCH_SUFFIX); + if (dirList != NULL) { + int i; + + for (i = 0; i < dirList->numNames; i++) { + if (uio_mountDir (repository, "/", uio_FSTYPE_ZIP, + packagesDir, dirList->names[i], "/", autoMount, + uio_MOUNT_BELOW | uio_MOUNT_RDONLY, + contentHandle) == NULL) { + fprintf(stderr, "Warning: Could not mount '%s': %s.\n", + dirList->names[i], strerror(errno)); + } + } + } + uio_freeDirList (dirList); + } + uio_closeDir(packagesDir); +} + + diff --git a/sc2/src/options.h b/sc2/src/options.h index 672576033..e7bd3ec06 100644 --- a/sc2/src/options.h +++ b/sc2/src/options.h @@ -22,6 +22,9 @@ #ifndef OPTIONS_H #define OPTIONS_H +#include "port.h" +#include "libs/uio.h" + #define OPT_3DO 0x01 #define OPT_PC 0x02 #define OPT_ALL 0xFF @@ -36,10 +39,12 @@ extern int optMeleeScale; extern BOOLEAN optSubtitles; extern BOOLEAN optStereoSFX; -extern char *configDir; -extern char *meleeDir; -extern char *saveDir; +extern uio_DirHandle *contentDir; +extern uio_DirHandle *configDir; +extern uio_DirHandle *saveDir; +extern uio_DirHandle *meleeDir; +void prepareContentDir (char *contentDirName); void prepareConfigDir(void); void prepareMeleeDir(void); void prepareSaveDir(void); diff --git a/sc2/src/port.h b/sc2/src/port.h index 3cdf4cea7..7ca488191 100644 --- a/sc2/src/port.h +++ b/sc2/src/port.h @@ -16,5 +16,51 @@ char *strupr (char *str); #endif +#ifdef WIN32 +# include +# 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 */ +# include +#endif +#ifdef _MSC_VER +# include +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 +# 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 +#endif + #endif /* _PORT_H */ diff --git a/sc2/src/sc2code/demo.c b/sc2/src/sc2code/demo.c index 5fd66f009..ae3e50b0c 100644 --- a/sc2/src/sc2code/demo.c +++ b/sc2/src/sc2code/demo.c @@ -87,7 +87,7 @@ OpenJournal (void) else #endif /* CREATE_JOURNAL */ { - FILE *fp; + uio_Stream *fp; if (fp = res_OpenResFile ("starcon.jnl", "rb")) { @@ -114,7 +114,7 @@ CloseJournal (void) { if (journal_fh) { - FILE *fp; + uio_Stream *fp; cclose (journal_fh); journal_fh = 0; diff --git a/sc2/src/sc2code/dummy.c b/sc2/src/sc2code/dummy.c index 22e870286..348dd0a4a 100644 --- a/sc2/src/sc2code/dummy.c +++ b/sc2/src/sc2code/dummy.c @@ -35,7 +35,7 @@ LoadCodeResFile (PSTR pStr) } static MEM_HANDLE -GetCodeResData (FILE *fp, DWORD length) +GetCodeResData (uio_Stream *fp, DWORD length) { enum { diff --git a/sc2/src/sc2code/grpinfo.c b/sc2/src/sc2code/grpinfo.c index 87a3621a8..14c475fb8 100644 --- a/sc2/src/sc2code/grpinfo.c +++ b/sc2/src/sc2code/grpinfo.c @@ -36,7 +36,7 @@ InitGroupInfo (BOOLEAN FirstTime) { PVOID fp; - fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); + fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb"); if (fp) { GROUP_HEADER GH; @@ -49,8 +49,7 @@ InitGroupInfo (BOOLEAN FirstTime) res_CloseResFile (fp); } - if (FirstTime && (fp = res_OpenResFile (tempFilePath (DEFGRPINFO_FILE), - "wb"))) + if (FirstTime && (fp = res_OpenResFile (tempDir, DEFGRPINFO_FILE, "wb"))) { PutResFileChar (0, fp); @@ -349,8 +348,8 @@ GetGroupInfo (DWORD offset, BYTE which_group) { PVOID fp; - fp = res_OpenResFile (tempFilePath ( - offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE), + fp = res_OpenResFile (tempDir, + offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE, "r+b"); if (fp) { @@ -387,7 +386,7 @@ GetGroupInfo (DWORD offset, BYTE which_group) fprintf (stderr, "GetGroupInfo: battle groups out of date %u/%u/%u!\n", month_index, day_index, year_index); #endif /* DEBUG */ - fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); + fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb"); GH.NumGroups = 0; GH.star_index = (COUNT)~0; GH.GroupOffset[0] = 0; @@ -616,8 +615,8 @@ PutGroupInfo (DWORD offset, BYTE which_group) { PVOID fp; - fp = res_OpenResFile (tempFilePath ( - offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE), + fp = res_OpenResFile (tempDir, + offset && which_group ? DEFGRPINFO_FILE : RANDGRPINFO_FILE, "r+b"); if (fp) { diff --git a/sc2/src/sc2code/init.c b/sc2/src/sc2code/init.c index a3fe5ca68..763742dac 100644 --- a/sc2/src/sc2code/init.c +++ b/sc2/src/sc2code/init.c @@ -16,13 +16,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "port.h" #include "starcon.h" +#include "libs/uio.h" FRAME stars_in_space, asteroid[NUM_VIEWS], blast[NUM_VIEWS], explosion[NUM_VIEWS]; +uio_Repository *repository; +uio_DirHandle *rootDir; + + BOOLEAN load_animation (PFRAME pixarray, DWORD big_res, DWORD med_res, DWORD sml_res) @@ -268,3 +274,26 @@ InitGlobData (void) (GLOBAL (GameClock)).clock_sem = CreateSemaphore(0, "Clock"); } +int +initIO (void) +{ + uio_init (); + repository = uio_openRepository (0); + + rootDir = uio_openDir(repository, "/", 0); + if (rootDir == NULL) { + fprintf(stderr, "Could not open '/' dir.\n"); + return -1; + } + return 0; +} + +void +uninitIO (void) +{ + uio_closeDir (rootDir); + uio_closeRepository (repository); + uio_unInit (); +} + + diff --git a/sc2/src/sc2code/libs/Makeinfo b/sc2/src/sc2code/libs/Makeinfo index f00110e05..9824e5605 100644 --- a/sc2/src/sc2code/libs/Makeinfo +++ b/sc2/src/sc2code/libs/Makeinfo @@ -1,2 +1,2 @@ uqm_SUBDIRS="decomp file graphics input math memory resource sound strings - task threads time video" + task threads time uio video" diff --git a/sc2/src/sc2code/libs/decomp/lzencode.c b/sc2/src/sc2code/libs/decomp/lzencode.c index b0a556b3e..2ba8ff5ad 100644 --- a/sc2/src/sc2code/libs/decomp/lzencode.c +++ b/sc2/src/sc2code/libs/decomp/lzencode.c @@ -335,7 +335,7 @@ _encode_cleanup (void) _lpCurCodeDesc->StreamIndex += 4; /* rewind */ if (_lpCurCodeDesc->StreamType == FILE_STREAM) - SeekResFile ((FILE *)_Stream, + SeekResFile ((uio_Stream *)_Stream, -(int)_lpCurCodeDesc->StreamIndex, SEEK_CUR); else /* _lpCurCodeDesc->StreamType == MEMORY_STREAM */ _Stream = (PBYTE)((BYTE *)_Stream diff --git a/sc2/src/sc2code/libs/decomp/lzh.h b/sc2/src/sc2code/libs/decomp/lzh.h index 740675fd7..c01eb78b2 100644 --- a/sc2/src/sc2code/libs/decomp/lzh.h +++ b/sc2/src/sc2code/libs/decomp/lzh.h @@ -69,10 +69,10 @@ typedef struct typedef LZHCODE_DESC *PLZHCODE_DESC; #define InChar() (_StreamType == FILE_STREAM ? \ - GetResFileChar ((FILE *)_Stream) : \ + GetResFileChar ((uio_Stream *)_Stream) : \ (int)*_Stream++) #define OutChar(c) (_StreamType == FILE_STREAM ? \ - PutResFileChar ((c), (FILE *)_Stream) : \ + PutResFileChar ((c), (uio_Stream *)_Stream) : \ (*_Stream++ = (BYTE)(c))) diff --git a/sc2/src/sc2code/libs/file.h b/sc2/src/sc2code/libs/file.h index 7f64aa505..910cbed31 100644 --- a/sc2/src/sc2code/libs/file.h +++ b/sc2/src/sc2code/libs/file.h @@ -18,50 +18,17 @@ #ifndef _FILE_H -/* Make sure we have PATH_MAX */ -#ifdef WIN32 -# include -# define PATH_MAX _MAX_PATH -#else - /* PATH_MAX is per POSIX defined in */ -# include -#endif -#ifdef _MSC_VER -# include -# define access _access -# define F_OK 0 -# define W_OK 2 -# define R_OK 4 -# include -# 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 -#endif +#include "port.h" -// for BOOLEAN -#include "compiler.h" +// for bool +#include "types.h" // from temp.h +#include "libs/uio.h" void initTempDir (void); void unInitTempDir (void); char *tempFilePath (const char *filename); - +extern uio_DirHandle *tempDir; // from dirs.h int mkdirhier (const char *path); @@ -70,8 +37,10 @@ int createDirectory (const char *dir, int mode); int expandPath (char *dest, size_t len, const char *src); // from files.h -int copyFile (const char *srcName, const char *newName); -BOOLEAN fileExists (const char *name); +int copyFile (uio_DirHandle *srcDir, const char *srcName, + uio_DirHandle *dstDir, const char *newName); +bool fileExists (const char *name); +bool fileExists2(uio_DirHandle *dir, const char *fileName); #endif /* _FILE_H */ diff --git a/sc2/src/sc2code/libs/file/files.c b/sc2/src/sc2code/libs/file/files.c index dc660842f..6de873178 100644 --- a/sc2/src/sc2code/libs/file/files.c +++ b/sc2/src/sc2code/libs/file/files.c @@ -22,20 +22,34 @@ #include #include #include "port.h" +#include "uio.h" #include "config.h" #include "types.h" #include "filintrn.h" #include "misc.h" -static int copyError(int srcFd, int dstFd, const char *unlinkPath, - uint8 *buf); +static int copyError(uio_Handle *srcHandle, uio_Handle *dstHandle, + uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf); -BOOLEAN +bool fileExists (const char *name) { return access (name, F_OK) == 0; } +bool +fileExists2(uio_DirHandle *dir, const char *fileName) +{ + uio_Stream *stream; + + stream = uio_fopen (dir, fileName, "rb"); + if (stream == NULL) + return 0; + + uio_fclose (stream); + return 1; +} + /* * Copy a file with path srcName to a file with name newName. * If the destination already exists, the operation fails. @@ -48,49 +62,59 @@ fileExists (const char *name) * remove the copy. */ int -copyFile (const char *srcName, const char *newName) +copyFile (uio_DirHandle *srcDir, const char *srcName, + uio_DirHandle *dstDir, const char *newName) { - int src, dst; + uio_Handle *src, *dst; struct stat sb; #define BUFSIZE 65536 uint8 *buf, *bufPtr; ssize_t numInBuf, numWritten; - src = open (srcName, O_RDONLY); - if (src == -1) + src = uio_open (srcDir, srcName, O_RDONLY +#ifdef WIN32 + | O_BINARY +#endif + , 0); + if (src == NULL) return -1; - if (fstat (src, &sb) == -1) - return copyError (src, -1, NULL, NULL); + if (uio_fstat (src, &sb) == -1) + return copyError (src, NULL, NULL, NULL, NULL); - dst = open (newName, O_WRONLY | O_CREAT | O_EXCL, - sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); - if (dst == -1) - return copyError (src, -1, NULL, NULL); + dst = uio_open (dstDir, newName, O_WRONLY | O_CREAT | O_EXCL +#ifdef WIN32 + | O_BINARY +#endif + , sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + if (dst == NULL) + return copyError (src, NULL, NULL, NULL, NULL); buf = HMalloc(BUFSIZE); // This was originally a statically allocated buffer, // but as this function might be run from a thread with // a small Stack, this is better. - while (1) { - numInBuf = read (src, buf, BUFSIZE); + while (1) + { + numInBuf = uio_read (src, buf, BUFSIZE); if (numInBuf == -1) { if (errno == EINTR) continue; - return copyError (src, dst, newName, buf); + return copyError (src, dst, dstDir, newName, buf); } if (numInBuf == 0) break; bufPtr = buf; - do { - numWritten = write (dst, bufPtr, numInBuf); + do + { + numWritten = uio_write (dst, bufPtr, numInBuf); if (numWritten == -1) { if (errno == EINTR) continue; - return copyError (src, dst, newName, buf); + return copyError (src, dst, dstDir, newName, buf); } numInBuf -= numWritten; bufPtr += numWritten; @@ -98,22 +122,23 @@ copyFile (const char *srcName, const char *newName) } HFree(buf); - close(src); - close(dst); + uio_close(src); + uio_close(dst); errno = 0; return 0; } /* - * Closes srcFd if it's not -1. - * Closes dstFd if it's not -1. - * Removes unlinkpath if it's not NULL. + * Closes srcHandle if it's not -1. + * Closes dstHandle if it's not -1. + * Removes unlinkpath from the unlinkHandle dir if it's not NULL. * Frees 'buf' if not NULL. * Always returns -1. * errno is what was before the call. */ static int -copyError(int srcFd, int dstFd, const char *unlinkPath, uint8 *buf) +copyError(uio_Handle *srcHandle, uio_Handle *dstHandle, + uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf) { int savedErrno; @@ -123,14 +148,14 @@ copyError(int srcFd, int dstFd, const char *unlinkPath, uint8 *buf) fprintf (stderr, "Error while copying: %s\n", strerror (errno)) #endif - if (srcFd >= 0) - close (srcFd); + if (srcHandle != NULL) + uio_close (srcHandle); - if (dstFd >= 0) - close (dstFd); + if (dstHandle != NULL) + uio_close (dstHandle); if (unlinkPath != NULL) - unlink (unlinkPath); + uio_unlink (unlinkHandle, unlinkPath); if (buf != NULL) HFree(buf); diff --git a/sc2/src/sc2code/libs/file/temp.c b/sc2/src/sc2code/libs/file/temp.c index bf71b1672..c33b1b1b0 100644 --- a/sc2/src/sc2code/libs/file/temp.c +++ b/sc2/src/sc2code/libs/file/temp.c @@ -30,12 +30,13 @@ #include "libs/compiler.h" #include "misc.h" -static char *tempDir; +static char *tempDirName; +uio_DirHandle *tempDir; static void removeTempDir (void) { - rmdir (tempDir); + rmdir (tempDirName); } // Try if the null-terminated path 'dir' to a directory is valid @@ -52,7 +53,10 @@ tryTempDir (char *buf, size_t buflen, const char *dir) if (dir == NULL) return EINVAL; - + + if (dir[0] == '\0') + return EINVAL; + len = strlen (dir); haveSlash = (dir[len - 1] == '/' #ifdef WIN32 @@ -63,6 +67,17 @@ tryTempDir (char *buf, size_t buflen, const char *dir) return ENAMETOOLONG; strcpy (buf, dir); +#if 0 + //def WIN32 + { + char *bufPtr; + for (bufPtr = buf; *bufPtr != '\0'; bufPtr++) + { + if (*bufPtr == '\\') + *bufPtr = '/'; + } + } +#endif if (!haveSlash) { buf[len] = '/'; @@ -71,22 +86,54 @@ tryTempDir (char *buf, size_t buflen, const char *dir) } if (access (buf, R_OK | W_OK) == -1) return errno; + return 0; } static void getTempDir (char *buf, size_t buflen) { + char cwd[PATH_MAX]; + if (tryTempDir (buf, buflen, getenv("TMP")) && tryTempDir (buf, buflen, getenv("TEMP")) && tryTempDir (buf, buflen, "/tmp/") && - tryTempDir (buf, buflen, "./")) + tryTempDir (buf, buflen, getcwd (cwd, sizeof cwd))) { fprintf (stderr, "Fatal Error: Cannot find a suitable location " "to store temporary files.\n"); - 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 // Number of files to try to open before giving up. void @@ -95,27 +142,29 @@ initTempDir (void) { DWORD num; int i; char *tempPtr; - // Pointer to the location in the tempDir string where the + // Pointer to the location in the tempDirName string where the // path to the temp dir ends and the dir starts. - tempDir = HMalloc (PATH_MAX); - getTempDir (tempDir, PATH_MAX - 21); + tempDirName = HMalloc (PATH_MAX); + getTempDir (tempDirName, PATH_MAX - 21); // reserve 8 chars for dirname, 1 for slash, and 12 for filename - len = strlen(tempDir); + len = strlen(tempDirName); num = ((DWORD) time (NULL)); // num = GetTimeCounter () % 0xffffffff; - tempPtr = tempDir + len; + tempPtr = tempDirName + len; i = NUM_TEMP_RETRIES; while (i--) { sprintf (tempPtr, "%08lx", num + i); - if (createDirectory (tempDir, 0700) == -1) + if (createDirectory (tempDirName, 0700) == -1) continue; // Success, we've got a temp dir. - tempDir = HRealloc (tempDir, len + 9); + tempDirName = HRealloc (tempDirName, len + 9); atexit (removeTempDir); + if (mountTempDir (tempDirName) == -1) + exit (EXIT_FAILURE); return; } @@ -127,7 +176,7 @@ initTempDir (void) { void unInitTempDir (void) { - // nothing at the moment. + uio_closeDir(tempDir); // the removing of the dir is handled via atexit } @@ -137,10 +186,11 @@ char * tempFilePath (const char *filename) { static char file[PATH_MAX]; - if (snprintf(file, PATH_MAX, "%s/%s", tempDir, filename) == -1) { - fprintf(stderr, "Path to temp file too long.\n"); - exit(EXIT_FAILURE); + if (snprintf (file, PATH_MAX, "%s/%s", tempDirName, filename) == -1) { + fprintf (stderr, "Path to temp file too long.\n"); + exit (EXIT_FAILURE); } return file; } + diff --git a/sc2/src/sc2code/libs/graphics/drawable.h b/sc2/src/sc2code/libs/graphics/drawable.h index acf576543..3a167119a 100644 --- a/sc2/src/sc2code/libs/graphics/drawable.h +++ b/sc2/src/sc2code/libs/graphics/drawable.h @@ -122,7 +122,7 @@ extern DRAWABLE _request_drawable (COUNT NumFrames, DRAWABLE_TYPE extern INTERSECT_CODE _clip_line (PRECT pClipRect, PBRESENHAM_LINE pLine); -extern MEM_HANDLE _GetCelData (FILE *fp, DWORD length); +extern MEM_HANDLE _GetCelData (uio_Stream *fp, DWORD length); extern BOOLEAN _ReleaseCelData (MEM_HANDLE handle); typedef PPRIMITIVE PRIMITIVEPTR; diff --git a/sc2/src/sc2code/libs/graphics/filegfx.c b/sc2/src/sc2code/libs/graphics/filegfx.c index e98f1d2b4..e4866b4e4 100644 --- a/sc2/src/sc2code/libs/graphics/filegfx.c +++ b/sc2/src/sc2code/libs/graphics/filegfx.c @@ -17,20 +17,21 @@ */ #include "gfxintrn.h" +#include "options.h" extern char *_cur_resfile_name; DWORD LoadCelFile (PVOID pStr) { - FILE *fp; + uio_Stream *fp; // FIXME: this theoretically needs a mechanism to prevent races if (_cur_resfile_name) // something else is loading resources atm return 0; - if ((fp = res_OpenResFile (pStr, "rb")) != NULL) + if ((fp = res_OpenResFile (contentDir, pStr, "rb")) != NULL) { MEM_HANDLE hData; diff --git a/sc2/src/sc2code/libs/graphics/font.h b/sc2/src/sc2code/libs/graphics/font.h index 14ac22943..b14e4c420 100644 --- a/sc2/src/sc2code/libs/graphics/font.h +++ b/sc2/src/sc2code/libs/graphics/font.h @@ -48,7 +48,7 @@ typedef FONT_DESC *PFONT_DESC; extern FONTPTR _CurFontPtr; -extern MEM_HANDLE _GetFontData (FILE *fp, DWORD length); +extern MEM_HANDLE _GetFontData (uio_Stream *fp, DWORD length); extern BOOLEAN _ReleaseFontData (MEM_HANDLE handle); #endif /* _FONT_H */ diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c b/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c index aad13f119..b14577c1c 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c @@ -23,8 +23,12 @@ #endif #include +#include "port.h" #include "sdl_common.h" #include "primitives.h" +#include "sdluio.h" +#include "libs/file.h" +#include "options.h" typedef struct anidata { @@ -415,11 +419,8 @@ Uint32 frame_mapRGBA (FRAMEPTR FramePtr,Uint8 r, Uint8 g, Uint8 b, Uint8 a) } MEM_HANDLE -_GetCelData (FILE *fp, DWORD length) +_GetCelData (uio_Stream *fp, DWORD length) { -#ifdef WIN32 - int omode; -#endif int cel_ct, n; DWORD opos; char CurrentLine[1024], filename[1024]; @@ -428,7 +429,7 @@ _GetCelData (FILE *fp, DWORD length) AniData ani[MAX_CELS]; DRAWABLE Drawable; - opos = ftell (fp); + opos = uio_ftell (fp); { char *s1, *s2; @@ -446,37 +447,38 @@ _GetCelData (FILE *fp, DWORD length) } } -#ifdef WIN32 - omode = _setmode (fileno (fp), O_TEXT); -#endif cel_ct = 0; - while (fgets (CurrentLine, sizeof (CurrentLine), fp) && cel_ct < MAX_CELS) + while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) && cel_ct < MAX_CELS) { - /*char fnamestr[1000]; - sscanf(CurrentLine, "%s", fnamestr); - fprintf (stderr, "imgload %s\n",fnamestr);*/ - sscanf (CurrentLine, "%s %d %d %d %d", &filename[n], &ani[cel_ct].transparent_color, &ani[cel_ct].colormap_index, &ani[cel_ct].hotspot_x, &ani[cel_ct].hotspot_y); - if ((img[cel_ct] = IMG_Load (filename)) && img[cel_ct]->w > 0 && - img[cel_ct]->h > 0 && img[cel_ct]->format->BitsPerPixel >= 8) + img[cel_ct] = sdluio_loadImage (contentDir, filename); + if (img[cel_ct] == NULL) { - ++cel_ct; + const char *err; + + err = SDL_GetError(); + fprintf (stderr, "_GetCelData: Unable to load image!\n"); + if (err != NULL) + fprintf (stderr, "SDL reports: %s\n", err); + SDL_FreeSurface (img[cel_ct]); } - else if (img[cel_ct]) + else if (img[cel_ct]->w < 0 || img[cel_ct]->h < 0 || + img[cel_ct]->format->BitsPerPixel < 8) { fprintf (stderr, "_GetCelData: Bad file!\n"); SDL_FreeSurface (img[cel_ct]); } + else + { + ++cel_ct; + } - if ((int)ftell (fp) - (int)opos >= (int)length) + if ((int)uio_ftell (fp) - (int)opos >= (int)length) break; } -#ifdef WIN32 - _setmode (fileno (fp), omode); -#endif Drawable = 0; if (cel_ct && (Drawable = AllocDrawable (cel_ct))) @@ -555,7 +557,7 @@ _ReleaseCelData (MEM_HANDLE handle) } MEM_HANDLE -_GetFontData (FILE *fp, DWORD length) +_GetFontData (uio_Stream *fp, DWORD length) { DWORD cel_ct; COUNT num_entries; @@ -564,14 +566,15 @@ _GetFontData (FILE *fp, DWORD length) BOOLEAN found_chars; #define MAX_CELS 256 SDL_Surface *img[MAX_CELS] = { 0 }; - char pattern[1024]; + char pattern[PATH_MAX]; if (_cur_resfile_name == 0) return (0); - sprintf (pattern, "%s/*.*", _cur_resfile_name); found_chars = FALSE; - FontDir = CaptureDirEntryTable (LoadDirEntryTable (pattern, &num_entries)); + FontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir, + _cur_resfile_name, ".", match_MATCH_SUBSTRING, + &num_entries)); while (num_entries--) { char *char_name; @@ -581,7 +584,7 @@ _GetFontData (FILE *fp, DWORD length) && cel_ct >= FIRST_CHAR && img[cel_ct -= FIRST_CHAR] == 0 && sprintf (pattern, "%s/%s", _cur_resfile_name, char_name) - && (img[cel_ct] = IMG_Load (pattern))) + && (img[cel_ct] = sdluio_loadImage (contentDir, pattern))) { if (img[cel_ct]->w > 0 && img[cel_ct]->h > 0 diff --git a/sc2/src/sc2code/libs/graphics/sdl/Makeinfo b/sc2/src/sc2code/libs/graphics/sdl/Makeinfo index c81a6903c..869174de9 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/Makeinfo +++ b/sc2/src/sc2code/libs/graphics/sdl/Makeinfo @@ -1,3 +1,3 @@ uqm_CFILES="3do_blt.c 3do_funcs.c 3do_getbody.c dcqueue.c opengl.c primitives.c pure.c rndzoom.c sdl_common.c - canvas.c bbox.c 2xscalers.c" + canvas.c bbox.c 2xscalers.c sdluio.c" diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 8a7103184..08e1299e9 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -44,7 +44,7 @@ int GfxFlags = 0; static TFB_Palette palette[256]; -#define FPS_PERIOD 1000 +#define FPS_PERIOD 100 int RenderedFrames = 0; void diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdluio.c b/sc2/src/sc2code/libs/graphics/sdl/sdluio.c new file mode 100644 index 000000000..69d051fe7 --- /dev/null +++ b/sc2/src/sc2code/libs/graphics/sdl/sdluio.c @@ -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; +} + + + diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdluio.h b/sc2/src/sc2code/libs/graphics/sdl/sdluio.h new file mode 100644 index 000000000..ab97b2e33 --- /dev/null +++ b/sc2/src/sc2code/libs/graphics/sdl/sdluio.h @@ -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 */ + diff --git a/sc2/src/sc2code/libs/input/sdl/input.c b/sc2/src/sc2code/libs/input/sdl/input.c index 033b4941d..29b35ce0f 100644 --- a/sc2/src/sc2code/libs/input/sdl/input.c +++ b/sc2/src/sc2code/libs/input/sdl/input.c @@ -76,47 +76,47 @@ static VControl_NameBinding control_names[] = { static void initKeyConfig(void) { - char userFile[PATH_MAX]; /* System-wide key config */ - int cb; - FILE *fp; + uio_Stream *fp; int errors; - cb = snprintf (userFile, PATH_MAX, "%skeys.cfg", configDir); - assert (cb != -1); - // Verified before: strlen (configDir) <= PATH_MAX - 13 - - if (fileExists (userFile)) { - fp = res_OpenResFile (userFile, "rt"); - } else { - if (copyFile ("starcon.key", userFile) == -1) + fp = res_OpenResFile (configDir, "keys.cfg", "rt"); + if (fp == NULL) + { + if (copyFile (contentDir, "starcon.key", + configDir, "keys.cfg") == -1) { - fprintf(stderr, "Warning: Could not copy default key config " - "to %s: %s.\n", userFile, strerror (errno)); - } + fprintf(stderr, "Warning: Could not copy default key config " + "to user config dir: %s.\n", strerror (errno)); + } else { - fprintf(stderr, "Copying default key config file to %s.\n", - userFile); + fprintf(stderr, "Copying default key config file to user " + "config dir.\n"); } - fp = res_OpenResFile ("starcon.key", "rt"); + fp = res_OpenResFile (contentDir, "starcon.key", "rt"); } errors = VControl_ReadConfiguration (fp); res_CloseResFile (fp); if (errors) { - fprintf (stderr, "%d errors encountered in key configuration file.\n", errors); + fprintf (stderr, "%d errors encountered in key configuration " + "file.\n", errors); /* This code should go away in 0.3; it's just * to force people to upgrade and forestall a * bunch of "none of my keys work anymore" bugs. */ if (errors > 5) { - fprintf (stderr, "Hey! you haven't updated your keys.cfg to use the new system, have you?\nDelete %s and try again.\n", userFile); - fprintf (stderr, "If you've done that and it STILL doesn't work, make sure your content/starcon.key is up to date.\n"); + fprintf (stderr, "Hey! you haven't updated your keys.cfg to " + "use the new system, have you?\nDelete keys.cfg and " + "try again.\n"); + fprintf (stderr, "If you've done that and it STILL doesn't " + "work, make sure your content/starcon.key is up to" + "date.\n"); } else { - fprintf (stderr, "Repair your %s file to continue.\n", userFile); + fprintf (stderr, "Repair your keys.cfg file to continue.\n"); } exit (1); diff --git a/sc2/src/sc2code/libs/input/sdl/vcontrol.c b/sc2/src/sc2code/libs/input/sdl/vcontrol.c index 01e27da6a..2524870b8 100644 --- a/sc2/src/sc2code/libs/input/sdl/vcontrol.c +++ b/sc2/src/sc2code/libs/input/sdl/vcontrol.c @@ -906,18 +906,18 @@ _next_token (parse_state *state) } static void -_next_line (parse_state *state, FILE *in) +_next_line (parse_state *state, uio_Stream *in) { int i, ch = 0; state->linenum++; for (i = 0; i < LINE_SIZE-1; i++) { - if (feof (in)) + if (uio_feof (in)) { break; } - ch = fgetc (in); - if (ch == '#' || ch == '\n' || ch == -1) + ch = uio_fgetc (in); + if (ch == '#' || ch == '\n' || ch == EOF) { /* If this line is blank or all commented, include some * whitespace. This lets us detect EOF as a completely @@ -933,9 +933,9 @@ _next_line (parse_state *state, FILE *in) } state->line[i] = '\0'; /* Skip to end of line */ - while (ch != '\n' && !feof (in)) + while (ch != '\n' && !uio_feof (in)) { - ch = fgetc (in); + ch = uio_fgetc (in); } state->token[0] = 0; state->index = 0; @@ -1180,7 +1180,7 @@ _parse_config_line (parse_state *state) } int -VControl_ReadConfiguration (FILE *in) +VControl_ReadConfiguration (uio_Stream *in) { parse_state ps; int errors; diff --git a/sc2/src/sc2code/libs/input/sdl/vcontrol.h b/sc2/src/sc2code/libs/input/sdl/vcontrol.h index 1b9362318..237370610 100644 --- a/sc2/src/sc2code/libs/input/sdl/vcontrol.h +++ b/sc2/src/sc2code/libs/input/sdl/vcontrol.h @@ -3,6 +3,8 @@ #ifndef _VCONTROL_H_ #define _VCONTROL_H_ +#include "port.h" +#include "libs/uio.h" /* Initialization routines */ void VControl_Init (void); @@ -51,6 +53,6 @@ void VControl_RegisterNameTable (VControl_NameBinding *table); /* Dump a configuration file corresponding to the current bindings and names. */ void VControl_Dump (FILE *out); /* Read a configuration file. Returns number of errors encountered. */ -int VControl_ReadConfiguration (FILE *in); +int VControl_ReadConfiguration (uio_Stream *in); #endif diff --git a/sc2/src/sc2code/libs/reslib.h b/sc2/src/sc2code/libs/reslib.h index 99e1cdc0c..39099022a 100644 --- a/sc2/src/sc2code/libs/reslib.h +++ b/sc2/src/sc2code/libs/reslib.h @@ -19,8 +19,10 @@ #ifndef _RESLIB_H #define _RESLIB_H -#include +//#include +#include "port.h" #include "memlib.h" +#include "libs/uio.h" typedef DWORD RESOURCE; typedef RESOURCE *PRESOURCE; @@ -49,24 +51,25 @@ typedef COUNT RES_PACKAGE; ((RESOURCE)(i) << TYPE_BITS) | \ ((RESOURCE)(t))) -extern FILE *res_OpenResFile (PVOID filename, const char *mode); -extern int ReadResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp); -extern int WriteResFile (PVOID lpBuf, COUNT size, COUNT count, FILE - *fp); -extern int GetResFileChar (FILE *fp); -extern int PutResFileChar (char ch, FILE *fp); -extern long SeekResFile (FILE *fp, long offset, int whence); -extern long TellResFile (FILE *fp); -extern long LengthResFile (FILE *fp); -extern BOOLEAN res_CloseResFile (FILE *fp); -extern BOOLEAN DeleteResFile (PVOID filename); +extern uio_Stream *res_OpenResFile (uio_DirHandle *dir, const char *filename, + const char *mode); +extern int ReadResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp); +extern int WriteResFile (PVOID lpBuf, COUNT size, COUNT count, + uio_Stream *fp); +extern int GetResFileChar (uio_Stream *fp); +extern int PutResFileChar (char ch, uio_Stream *fp); +extern long SeekResFile (uio_Stream *fp, long offset, int whence); +extern long TellResFile (uio_Stream *fp); +extern long LengthResFile (uio_Stream *fp); +extern BOOLEAN res_CloseResFile (uio_Stream *fp); +extern BOOLEAN DeleteResFile (uio_DirHandle *dir, const char *filename); extern MEM_HANDLE InitResourceSystem (PVOID resfile, COUNT resindex_type, BOOLEAN (*FileErrorFunc) (PVOID filename)); extern BOOLEAN UninitResourceSystem (void); extern BOOLEAN InstallResTypeVectors ( - COUNT res_type, - MEM_HANDLE (*load_func) (FILE *fp, DWORD len), + COUNT res_type, + MEM_HANDLE (*load_func) (uio_Stream *fp, DWORD len), BOOLEAN (*free_func) (MEM_HANDLE handle)); extern MEM_HANDLE res_GetResource (RESOURCE res); extern MEM_HANDLE res_DetachResource (RESOURCE res); @@ -80,7 +83,7 @@ extern MEM_HANDLE OpenResourceIndexInstance (DWORD extern MEM_HANDLE SetResourceIndex (MEM_HANDLE hRH); extern BOOLEAN CloseResourceIndex (MEM_HANDLE hRH); -extern MEM_HANDLE GetResourceData (FILE *fp, DWORD +extern MEM_HANDLE GetResourceData (uio_Stream *fp, DWORD length, MEM_FLAGS mem_flags); #define RESOURCE_PRIORITY DEFAULT_MEM_PRIORITY @@ -102,7 +105,9 @@ typedef STRING_TABLE DIRENTRY_REF; typedef STRING DIRENTRY; typedef STRINGPTR DIRENTRYPTR; -extern DIRENTRY_REF LoadDirEntryTable (PSTR pattern, + +extern DIRENTRY_REF LoadDirEntryTable (uio_DirHandle *dirHandle, + const char *path, const char *pattern, match_MatchType matchType, PCOUNT pnum_entries); #define CaptureDirEntryTable CaptureStringTable #define ReleaseDirEntryTable ReleaseStringTable diff --git a/sc2/src/sc2code/libs/resource/direct.c b/sc2/src/sc2code/libs/resource/direct.c index b72830769..0e28f2c29 100644 --- a/sc2/src/sc2code/libs/resource/direct.c +++ b/sc2/src/sc2code/libs/resource/direct.c @@ -16,281 +16,95 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* This file contains two versions of LoadDirEntryTable; one for Windows, and - * one for other systems (POSIX). - * It might be better to split this up in seperate files eventually. - * - SvdB - */ -#ifdef WIN32 -#include -#include #include "libs/strings/strintrn.h" - -DIRENTRY_REF -LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries) -{ - COUNT num_entries, length; - STRING_TABLE StringTable; - STRING_TABLEPTR lpST; - PDWORD lpLastOffs; - - num_entries = 0; - StringTable = 0; - do - { - COUNT slen; - long handle; - struct _finddata_t f; - - if (num_entries == 0) - length = 0; - else - { - slen = sizeof (STRING_TABLE_DESC) - + (num_entries * sizeof (DWORD)); - StringTable = AllocResourceData (slen + length, 0); - LockStringTable (StringTable, &lpST); - if (lpST == 0) - { - FreeStringTable (StringTable); - StringTable = 0; - - break; - } - - lpST->StringCount = num_entries; - lpLastOffs = &lpST->StringOffsets[0]; - *lpLastOffs = slen; - - num_entries = 0; - length = slen; - } - - handle = _findfirst (pattern, &f); - if (handle != -1) - { - do - { - if (f.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM)) - continue; - - slen = strlen (f.name) + 1; - length += slen; - - if ((MEM_HANDLE)StringTable) - { - PSTR lpStr; - PDWORD lpLo, lpHi; - - lpLo = &lpST->StringOffsets[0]; - lpHi = lpLastOffs - 1; - while (lpLo <= lpHi) - { - char c1, c2; - PSTR pStr; - COUNT LocLen; - PDWORD lpMid; - - lpMid = lpLo + ((lpHi - lpLo) >> 1); - - LocLen = lpMid[1] - lpMid[0]; - if (LocLen > slen) - LocLen = slen; - - lpStr = (PSTR)lpST + lpMid[0]; - pStr = f.name; - while (LocLen-- - && (c1 = toupper (*lpStr++)) - == (c2 = toupper (*pStr++))) - ; - - if (c1 <= c2) - lpLo = lpMid + 1; - else - lpHi = lpMid - 1; - } - - lpStr = (PSTR)lpST + lpLo[0]; - memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]); - strcpy (lpStr, f.name); - - for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi) - lpHi[1] = lpHi[0] + slen; - } - - ++num_entries; - } while (_findnext (handle, &f) == 0); - _findclose (handle); - } - } while (num_entries && (MEM_HANDLE)StringTable == 0); - - if ((MEM_HANDLE)StringTable == 0) - *pnum_entries = 0; - else - { - *pnum_entries = num_entries; - - UnlockStringTable (StringTable); - } - - return ((DIRENTRY_REF)StringTable); -} - -#else /* ! defined(WIN32) */ - -#include "libs/strings/strintrn.h" -#include +#include "port.h" +#include "libs/uio.h" #include -#include -#include -#include -#include -#include DIRENTRY_REF -LoadDirEntryTable (PSTR pattern, PCOUNT pnum_entries) +LoadDirEntryTable (uio_DirHandle *dirHandle, const char *path, + const char *pattern, match_MatchType matchType, PCOUNT pnum_entries) { + uio_DirList *dirList; COUNT num_entries, length; + COUNT i; + COUNT slen; + uio_DirHandle *dir; STRING_TABLE StringTable; STRING_TABLEPTR lpST; + PSTR lpStr; PDWORD lpLastOffs; - PSTR slash; // Pointer inside pattern to the last / - SBYTE path[PATH_MAX]; // buffer for a filename with path - PSTR file; // Pointer inside path to the filename - size_t pathlen; // length of path, excluding last / and filename - slash = (PSTR) strrchr ((const char *) pattern, '/'); - if (slash == NULL) - { - pathlen = 1; - path[0] = '.'; - } - else - { - pathlen = slash - pattern; - memcpy (path, pattern, pathlen); - pattern = slash + 1; - } - file = path + pathlen + 1; - + dir = uio_openDirRelative (dirHandle, path, 0); + assert(dir != NULL); + dirList = uio_getDirList (dir, "", pattern, matchType); + assert(dirList != NULL); num_entries = 0; - StringTable = 0; - do + length = 0; + + // First, count the amount of space needed + for (i = 0; i < dirList->numNames; i++) { - COUNT slen; - DIR *handle; + struct stat sb; - if (num_entries == 0) - length = 0; - else + if (dirList->names[i][0] == '.') { - 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; + dirList->names[i] = NULL; + continue; } - - - path[pathlen] = '\0'; // strip any file part - handle = opendir((const char *) path); - if (handle != NULL) + if (uio_stat (dir, dirList->names[i], &sb) == -1) { - path[pathlen] = '/'; - // change the 0 char to a slash; a filename will be - // attached here. - while (1) - { - struct dirent *de; - struct stat sb; - - de = readdir(handle); - if (de == NULL) - break; - if (de->d_name[0] == '.') - 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; - PDWORD lpLo, lpHi; - - lpLo = &lpST->StringOffsets[0]; - lpHi = lpLastOffs - 1; - while (lpLo <= lpHi) - { - char c1, c2; - PSTR pStr; - COUNT LocLen; - PDWORD lpMid; - - lpMid = lpLo + ((lpHi - lpLo) >> 1); - - LocLen = lpMid[1] - lpMid[0]; - if (LocLen > slen) - LocLen = slen; - - lpStr = (PSTR)lpST + lpMid[0]; - pStr = de->d_name; - while (LocLen-- - && (c1 = toupper (*lpStr++)) - == (c2 = toupper (*pStr++))) - ; - - if (c1 <= c2) - lpLo = lpMid + 1; - else - lpHi = lpMid - 1; - } - - lpStr = (PSTR)lpST + lpLo[0]; - memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]); - strcpy (lpStr, de->d_name); - - for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi) - lpHi[1] = lpHi[0] + slen; - } - - ++num_entries; - } - closedir(handle); + dirList->names[i] = NULL; + continue; } - } while (num_entries && (MEM_HANDLE)StringTable == 0); + if (!S_ISREG (sb.st_mode)) + { + dirList->names[i] = NULL; + continue; + } + length += strlen (dirList->names[i]) + 1; + num_entries++; + } + uio_closeDir (dir); - if ((MEM_HANDLE)StringTable == 0) + if (num_entries == 0) { + uio_freeDirList(dirList); *pnum_entries = 0; - else - { - *pnum_entries = num_entries; - - UnlockStringTable (StringTable); + return ((DIRENTRY_REF) 0); } - 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 diff --git a/sc2/src/sc2code/libs/resource/filecntl.c b/sc2/src/sc2code/libs/resource/filecntl.c index da2d6c4fe..763de64da 100644 --- a/sc2/src/sc2code/libs/resource/filecntl.c +++ b/sc2/src/sc2code/libs/resource/filecntl.c @@ -24,33 +24,31 @@ #include #include #include +#include "port.h" #include "resintrn.h" +#include "libs/uio.h" -FILE * -res_OpenResFile (PVOID filename, const char *mode) +uio_Stream * +res_OpenResFile (uio_DirHandle *dir, const char *filename, const char *mode) { - FILE *fp; + uio_Stream *fp; struct stat sb; -#ifdef WIN32 - if (stat (filename, &sb) == 0 && (sb.st_mode & _S_IFDIR)) -#else - if (stat (filename, &sb) == 0 && S_ISDIR(sb.st_mode)) -#endif - return ((FILE *) ~0); + if (uio_stat (dir, filename, &sb) == 0 && S_ISDIR(sb.st_mode)) + return ((uio_Stream *) ~0); - fp = fopen (filename, mode); + fp = uio_fopen (dir, filename, mode); return (fp); } BOOLEAN -res_CloseResFile (FILE *fp) +res_CloseResFile (uio_Stream *fp) { if (fp) { - if (fp != (FILE *)~0) - fclose (fp); + if (fp != (uio_Stream *)~0) + uio_fclose (fp); return (TRUE); } @@ -58,85 +56,80 @@ res_CloseResFile (FILE *fp) } BOOLEAN -DeleteResFile (PVOID filename) +DeleteResFile (uio_DirHandle *dir, const char *filename) { - return (remove (filename) == 0); + return (uio_unlink (dir, filename) == 0); } int -ReadResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp) +ReadResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp) { int retval; - retval = fread (lpBuf, size, count, fp); + retval = uio_fread (lpBuf, size, count, fp); return (retval); } int -WriteResFile (PVOID lpBuf, COUNT size, COUNT count, FILE *fp) +WriteResFile (PVOID lpBuf, COUNT size, COUNT count, uio_Stream *fp) { int retval; - retval = fwrite (lpBuf, size, count, fp); + retval = uio_fwrite (lpBuf, size, count, fp); return (retval); } int -GetResFileChar (FILE *fp) +GetResFileChar (uio_Stream *fp) { int retval; - retval = getc (fp); + retval = uio_getc (fp); return (retval); } int -PutResFileChar (char ch, FILE *fp) +PutResFileChar (char ch, uio_Stream *fp) { int retval; - retval = putc (ch, fp); - + retval = uio_putc (ch, fp); return (retval); } long -SeekResFile (FILE *fp, long offset, int whence) +SeekResFile (uio_Stream *fp, long offset, int whence) { long retval; - retval = fseek (fp, offset, whence); + retval = uio_fseek (fp, offset, whence); return (retval); } long -TellResFile (FILE *fp) +TellResFile (uio_Stream *fp) { long retval; - retval = ftell (fp); + retval = uio_ftell (fp); return (retval); } long -LengthResFile (FILE *fp) +LengthResFile (uio_Stream *fp) { -if (fp == (FILE *)~0) - return (1); -#ifdef WIN32 - return filelength (fileno (fp)); -#else - { - struct stat sb; - if (fstat(fileno(fp), &sb) == -1) - return 1; - return sb.st_size; - } -#endif + struct stat sb; + + if (fp == (uio_Stream *)~0) + return (1); + if (uio_fstat(uio_streamHandle(fp), &sb) == -1) + return 1; + return sb.st_size; } + diff --git a/sc2/src/sc2code/libs/resource/getres.c b/sc2/src/sc2code/libs/resource/getres.c index 65bb73040..e97ee9bcc 100644 --- a/sc2/src/sc2code/libs/resource/getres.c +++ b/sc2/src/sc2code/libs/resource/getres.c @@ -18,6 +18,7 @@ #include "resintrn.h" #include "port.h" +#include "options.h" char *_cur_resfile_name; @@ -156,7 +157,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package) { BOOLEAN DanglingOpen; MEM_HANDLE hList; - FILE *fp; + uio_Stream *fp; COUNT t, num_types, num_instances; DWORD file_offs, data_len; RES_HANDLE_LISTPTR ResourceHandleListPtr; @@ -221,7 +222,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package) fp = ResHeaderPtr->res_fp; else { - fp = res_OpenResFile (file_buf, "rb"); + fp = res_OpenResFile (contentDir, file_buf, "rb"); if (fp) DanglingOpen = TRUE; } @@ -298,7 +299,7 @@ load_package (INDEX_HEADERPTR ResHeaderPtr, RES_PACKAGE res_package) { get_resource_filename (ResHeaderPtr, file_buf, (COUNT)data_len); - fp = res_OpenResFile (file_buf, "rb"); + fp = res_OpenResFile (contentDir, file_buf, "rb"); if (fp == NULL) { #if 1 // def DEBUG diff --git a/sc2/src/sc2code/libs/resource/index.h b/sc2/src/sc2code/libs/resource/index.h index 2327d28bf..fe0e8669d 100644 --- a/sc2/src/sc2code/libs/resource/index.h +++ b/sc2/src/sc2code/libs/resource/index.h @@ -23,7 +23,7 @@ typedef struct { - MEM_HANDLE (*load_func) (FILE *fp, DWORD len); + MEM_HANDLE (*load_func) (uio_Stream *fp, DWORD len); BOOLEAN (*free_func) (MEM_HANDLE handle); } RES_VECTORS; @@ -50,7 +50,7 @@ typedef BYTE RES_FLAGS; typedef struct { - FILE *res_fp; + uio_Stream *res_fp; DWORD packmem_list_offs; DWORD path_list_offs; diff --git a/sc2/src/sc2code/libs/resource/loadres.c b/sc2/src/sc2code/libs/resource/loadres.c index 48a38454b..8e0ca38a4 100644 --- a/sc2/src/sc2code/libs/resource/loadres.c +++ b/sc2/src/sc2code/libs/resource/loadres.c @@ -20,7 +20,7 @@ #include "declib.h" MEM_HANDLE -GetResourceData (FILE *fp, DWORD length, MEM_FLAGS mem_flags) +GetResourceData (uio_Stream *fp, DWORD length, MEM_FLAGS mem_flags) { MEM_HANDLE RData; DECODE_REF fh; diff --git a/sc2/src/sc2code/libs/resource/resinit.c b/sc2/src/sc2code/libs/resource/resinit.c index b7b990b10..286442821 100644 --- a/sc2/src/sc2code/libs/resource/resinit.c +++ b/sc2/src/sc2code/libs/resource/resinit.c @@ -17,6 +17,7 @@ */ #include "resintrn.h" +#include "options.h" static MEM_HANDLE hIndexList; @@ -83,7 +84,7 @@ _sub_index_list (MEM_HANDLE hRH) } MEM_HANDLE -_GetResFileData (FILE *res_fp, DWORD flen) +_GetResFileData (uio_Stream *res_fp, DWORD flen) { UWORD lo_word, hi_word; DWORD res_offs, remainder; @@ -250,17 +251,17 @@ UninitResourceSystem (void) MEM_HANDLE OpenResourceIndexFile (PVOID resfile) { - FILE *res_fp; + uio_Stream *res_fp; char fullname[256]; strcpy (fullname, resfile); - if ((res_fp = res_OpenResFile (fullname, "rb")) == 0) + if ((res_fp = res_OpenResFile (contentDir, fullname, "rb")) == 0) { sprintf (fullname, "%s.pkg", (char *) resfile); - if ((res_fp = res_OpenResFile (fullname, "rb")) == 0) + if ((res_fp = res_OpenResFile (contentDir, fullname, "rb")) == 0) { sprintf (fullname, "%s.ndx", (char *) resfile); - res_fp = res_OpenResFile (fullname, "rb"); + res_fp = res_OpenResFile (contentDir, fullname, "rb"); } } @@ -315,7 +316,7 @@ CloseResourceIndex (MEM_HANDLE hRH) { if (UnlockResourceHeader (hRH)) { - FILE *res_fp; + uio_Stream *res_fp; INDEX_HEADERPTR ResHeaderPtr; ResHeaderPtr = LockResourceHeader (hRH); @@ -379,7 +380,7 @@ CloseResourceIndex (MEM_HANDLE hRH) BOOLEAN InstallResTypeVectors (COUNT res_type, - MEM_HANDLE (*load_func) (FILE *fp, DWORD len), + MEM_HANDLE (*load_func) (uio_Stream *fp, DWORD len), BOOLEAN (*free_func) (MEM_HANDLE handle)) { INDEX_HEADERPTR ResHeaderPtr; diff --git a/sc2/src/sc2code/libs/resource/resintrn.h b/sc2/src/sc2code/libs/resource/resintrn.h index 68d5a7c6d..4403d8fa4 100644 --- a/sc2/src/sc2code/libs/resource/resintrn.h +++ b/sc2/src/sc2code/libs/resource/resintrn.h @@ -54,7 +54,7 @@ do \ #define DoLoad(pRH, t,fp,len) (*(pRH)->TypeList[t-1].func_vectors.load_func)(fp,len) #define DoFree(pRH, t,h) (*(pRH)->TypeList[t-1].func_vectors.free_func)(h) -extern MEM_HANDLE _GetResFileData (FILE *res_fp, DWORD flen); +extern MEM_HANDLE _GetResFileData (uio_Stream *res_fp, DWORD flen); #define IsIndexType(pRH, t) ((pRH)->TypeList[t-1].func_vectors.load_func \ ==_GetResFileData) diff --git a/sc2/src/sc2code/libs/sound/decoders/decoder.c b/sc2/src/sc2code/libs/sound/decoders/decoder.c index c06c8ee9d..4f7ca17d8 100644 --- a/sc2/src/sc2code/libs/sound/decoders/decoder.c +++ b/sc2/src/sc2code/libs/sound/decoders/decoder.c @@ -27,12 +27,17 @@ #include #include #include +#include "port.h" #include "libs/misc.h" +#include "libs/uio.h" #include "decoder.h" #include "wav.h" #include "libs/sound/sound_common.h" #include "mikmod/mikmod.h" +extern bool fileExists2(uio_DirHandle *dir, const char *fileName); + // Can't '#include "libs/file.h"' due to some type conflicts. + MIKMODAPI extern struct MDRIVER drv_openal; static char *decoder_info_wav = "Wav"; @@ -42,35 +47,25 @@ static char *decoder_info_nul = "None"; TFB_DecoderFormats decoder_formats; -static int file_exists (char *filename) -{ - FILE *fp; - if ((fp = fopen(filename, "rb")) == NULL) - return 0; - - fclose (fp); - return 1; -} - static size_t ogg_read (void *ptr, size_t size, size_t nmemb, void *datasource) { - return fread (ptr, size, nmemb, datasource); + return uio_fread ((uio_Stream *) ptr, size, nmemb, datasource); } static int ogg_seek (void *datasource, ogg_int64_t offset, int whence) { long off = (long) offset; - return fseek (datasource, off, whence); + return uio_fseek ((uio_Stream *) datasource, off, whence); } static int ogg_close (void *datasource) { - return fclose (datasource); + return uio_fclose ((uio_Stream *) datasource); } static long ogg_tell(void *datasource) { - return ftell (datasource); + return uio_ftell ((uio_Stream *) datasource); } static const ov_callbacks ogg_callbacks = @@ -152,13 +147,13 @@ void SoundDecoder_Uninit (void) MikMod_Exit (); } -TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, - uint32 startTime, sint32 runTime) +TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir, char *filename, + uint32 buffer_size, uint32 startTime, sint32 runTime) { int i; i = strlen (filename) - 3; - if (!file_exists (filename)) + if (!fileExists2 (dir, filename)) { if (runTime) { @@ -180,6 +175,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, decoder->decoder_info = decoder_info_nul; decoder->type = SOUNDDECODER_NULL; + decoder->dir = dir; decoder->filename = (char *) HMalloc (strlen (filename) + 1); strcpy (decoder->filename, filename); decoder->data = NULL; @@ -208,6 +204,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, decoder->length = 0; // FIXME should be calculated decoder->decoder_info = decoder_info_wav; decoder->type = SOUNDDECODER_WAV; + decoder->dir = dir; decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->start_sample = 0; decoder->end_sample = 0; @@ -223,7 +220,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, //fprintf (stderr, "SoundDecoder_Load(): %s interpreted as mod\n", filename); - mod = Player_Load (filename, 4, 0); + mod = Player_Load (dir, filename, 4, 0); if (!mod) { fprintf (stderr, "SoundDecoder_Load(): couldn't load %s\n", filename); @@ -245,6 +242,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, decoder->length = 0; // FIXME way to obtain this from mikmod? decoder->decoder_info = decoder_info_mod; decoder->type = SOUNDDECODER_MOD; + decoder->dir = dir; decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->start_sample = 0; decoder->end_sample = 0; @@ -257,7 +255,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, else if (!strcmp (&filename[i], "ogg")) { int rc; - FILE *vfp; + uio_Stream *vfp; OggVorbis_File *vf; vorbis_info *vinfo; TFB_SoundDecoder *decoder; @@ -270,22 +268,20 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, fprintf (stderr, "SoundDecoder_Load(): couldn't allocate mem for OggVorbis_File\n"); return NULL; } - if ((vfp = fopen (filename, "r")) == NULL) + + vfp = uio_fopen (dir, filename, "rb"); + if (vfp == NULL) { fprintf (stderr, "SoundDecoder_Load(): couldn't open %s\n", filename); HFree (vf); return NULL; } -#ifdef WIN32 - _setmode( _fileno(vfp), _O_BINARY); -#endif - rc = ov_open_callbacks (vfp, vf, NULL, 0, ogg_callbacks); if (rc != 0) { fprintf (stderr, "SoundDecoder_Load(): ov_open_callbacks failed for %s, error code %d\n", filename, rc); - fclose (vfp); + uio_fclose (vfp); HFree (vf); return NULL; } @@ -330,6 +326,7 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, decoder->decoder_info = decoder_info_ogg; decoder->type = SOUNDDECODER_OGG; + decoder->dir = dir; decoder->filename = (char *) HMalloc (strlen (filename) + 1); strcpy (decoder->filename, filename); decoder->data = vf; @@ -506,8 +503,9 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder) { case SOUNDDECODER_WAV: { - LoadWAVFile (decoder->filename ,&decoder->format, &decoder->buffer, - &decoder->buffer_size, &decoder->frequency, decoder_formats.want_big_endian); + LoadWAVFile (decoder->dir, decoder->filename, &decoder->format, + &decoder->buffer, &decoder->buffer_size, + &decoder->frequency, decoder_formats.want_big_endian); if (decoder->buffer_size != 0) { diff --git a/sc2/src/sc2code/libs/sound/decoders/decoder.h b/sc2/src/sc2code/libs/sound/decoders/decoder.h index 5a2ff65bc..6cb3ed633 100644 --- a/sc2/src/sc2code/libs/sound/decoders/decoder.h +++ b/sc2/src/sc2code/libs/sound/decoders/decoder.h @@ -21,7 +21,9 @@ #ifndef DECODER_H #define DECODER_H +#include "port.h" #include "types.h" +#include "uio.h" #ifdef WIN32 #pragma comment (lib, "vorbisfile.lib") @@ -51,6 +53,7 @@ typedef struct tfb_sounddecoder // semi-private sint32 type; + uio_DirHandle *dir; char *filename; void *data; uint32 pos; @@ -82,8 +85,8 @@ extern TFB_DecoderFormats decoder_formats; void SoundDecoder_SwapWords (uint16* data, uint32 size); sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats); void SoundDecoder_Uninit (void); -TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, - uint32 startTime, sint32 runTime); +TFB_SoundDecoder* SoundDecoder_Load (uio_DirHandle *dir, + char *filename, uint32 buffer_size, uint32 startTime, sint32 runTime); uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder); uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder); float SoundDecoder_GetTime (TFB_SoundDecoder *decoder); diff --git a/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod.h b/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod.h index a9d4e6b0e..c295b4d71 100644 --- a/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod.h +++ b/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod.h @@ -31,6 +31,8 @@ #include #include +#include "port.h" +#include "libs/uio.h" #ifdef __cplusplus extern "C" { @@ -324,8 +326,8 @@ typedef struct SAMPLE { /* Sample functions */ -MIKMODAPI extern SAMPLE *Sample_Load(CHAR*); -MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*); +MIKMODAPI extern SAMPLE *Sample_Load(uio_DirHandle*,CHAR*); +MIKMODAPI extern SAMPLE *Sample_LoadFP(uio_Stream*); MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*); MIKMODAPI extern void Sample_Free(SAMPLE*); MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE); @@ -527,10 +529,10 @@ MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */ MIKMODAPI extern MODULE* Player_LoadRW(SDL_RWops*,int,BOOL); #endif /* USE_RWOPS */ /* End SDL_RWops compatability */ -MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL); -MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL); +MIKMODAPI extern MODULE* Player_Load(uio_DirHandle *, CHAR*,int,BOOL); +MIKMODAPI extern MODULE* Player_LoadFP(uio_Stream*,int,BOOL); MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL); -MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*); +MIKMODAPI extern CHAR* Player_LoadTitle(uio_DirHandle*,CHAR*); MIKMODAPI extern void Player_Free(MODULE*); MIKMODAPI extern void Player_Start(MODULE*); MIKMODAPI extern BOOL Player_Active(void); diff --git a/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod_internals.h b/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod_internals.h index d33d4f01c..7b8062b84 100644 --- a/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod_internals.h +++ b/sc2/src/sc2code/libs/sound/decoders/mikmod/mikmod_internals.h @@ -38,6 +38,8 @@ #endif #include "mikmod_build.h" +#include "port.h" +#include "libs/uio.h" #ifdef macintosh #ifndef __MWERKS__ @@ -142,13 +144,13 @@ extern void _mm_delete_rwops_reader (MREADER*); #endif /* USE_RWOPS */ /* End SDL_RWops compatability */ -extern MREADER* _mm_new_file_reader(FILE* fp); +extern MREADER* _mm_new_file_reader(uio_Stream* fp); extern void _mm_delete_file_reader(MREADER*); -extern MWRITER* _mm_new_file_writer(FILE *fp); +extern MWRITER* _mm_new_file_writer(uio_Stream *fp); extern void _mm_delete_file_writer(MWRITER*); -extern BOOL _mm_FileExists(CHAR *fname); +extern BOOL _mm_FileExists(uio_DirHandle *dir,CHAR *fname); #define _mm_write_SBYTE(x,y) y->Put(y,(int)x) #define _mm_write_UBYTE(x,y) y->Put(y,(int)x) @@ -169,7 +171,7 @@ extern BOOL _mm_FileExists(CHAR *fname); extern void _mm_iobase_setcur(MREADER*); extern void _mm_iobase_revert(void); -extern FILE *_mm_fopen(CHAR*,CHAR*); +extern uio_Stream *_mm_fopen(uio_DirHandle *,CHAR*,CHAR*); extern void _mm_write_string(CHAR*,MWRITER*); extern int _mm_read_string (CHAR*,int,MREADER*); diff --git a/sc2/src/sc2code/libs/sound/decoders/mikmod/mloader.c b/sc2/src/sc2code/libs/sound/decoders/mikmod/mloader.c index 445ac0d80..1bc98291b 100644 --- a/sc2/src/sc2code/libs/sound/decoders/mikmod/mloader.c +++ b/sc2/src/sc2code/libs/sound/decoders/mikmod/mloader.c @@ -32,6 +32,8 @@ #include #include "mikmod_internals.h" +#include "port.h" +#include "libs/uio.h" MREADER *modreader; @@ -372,20 +374,20 @@ static CHAR* Player_LoadTitle_internal(MREADER *reader) return l->LoadTitle(); } -CHAR* Player_LoadTitle(CHAR* filename) +CHAR* Player_LoadTitle(uio_DirHandle *dir, CHAR* filename) { CHAR* result=NULL; - FILE* fp; + uio_Stream* fp; MREADER* reader; - if((fp=_mm_fopen(filename,"rb"))) { + if((fp=_mm_fopen(dir, filename,"rb"))) { if((reader=_mm_new_file_reader(fp))) { MUTEX_LOCK(lists); result=Player_LoadTitle_internal(reader); MUTEX_UNLOCK(lists); _mm_delete_file_reader(reader); } - fclose(fp); + uio_fclose(fp); } return result; } @@ -507,7 +509,7 @@ MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious) /* Loads a module given a file pointer. File is loaded from the current file seek position. */ -MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious) +MODULE* Player_LoadFP(uio_Stream* fp,int maxchan,BOOL curious) { MODULE* result=NULL; struct MREADER* reader=_mm_new_file_reader (fp); @@ -521,14 +523,14 @@ MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious) /* Open a module via its filename. The loader will initialize the specified song-player 'player'. */ -MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious) +MODULE* Player_Load(uio_DirHandle *dir,CHAR* filename,int maxchan,BOOL curious) { - FILE *fp; + uio_Stream *fp; MODULE *mf=NULL; - if((fp=_mm_fopen(filename,"rb"))) { + if((fp=_mm_fopen(dir, filename,"rb"))) { mf=Player_LoadFP(fp,maxchan,curious); - fclose(fp); + uio_fclose(fp); } return mf; } diff --git a/sc2/src/sc2code/libs/sound/decoders/mikmod/mmio.c b/sc2/src/sc2code/libs/sound/decoders/mikmod/mmio.c index c0d406d9f..8dc99da7e 100644 --- a/sc2/src/sc2code/libs/sound/decoders/mikmod/mmio.c +++ b/sc2/src/sc2code/libs/sound/decoders/mikmod/mmio.c @@ -142,23 +142,23 @@ void _mm_delete_rwops_reader (MREADER* reader) */ -FILE* _mm_fopen(CHAR* fname,CHAR* attrib) +uio_Stream* _mm_fopen(uio_DirHandle* dir,CHAR* fname,CHAR* attrib) { - FILE *fp; + uio_Stream *fp; - if(!(fp=fopen(fname,attrib))) { + if(!(fp=uio_fopen(dir,fname,attrib))) { _mm_errno = MMERR_OPENING_FILE; if(_mm_errorhandler) _mm_errorhandler(); } return fp; } -BOOL _mm_FileExists(CHAR* fname) +BOOL _mm_FileExists(uio_DirHandle* dir,CHAR* fname) { - FILE *fp; + uio_Stream *fp; - if(!(fp=fopen(fname,"r"))) return 0; - fclose(fp); + if(!(fp=uio_fopen(dir, fname,"rb"))) return 0; + uio_fclose(fp); return 1; } @@ -179,37 +179,37 @@ void _mm_iobase_revert(void) /*========== File Reader */ typedef struct MFILEREADER { - MREADER core; - FILE* file; + MREADER core; + uio_Stream* file; } MFILEREADER; static BOOL _mm_FileReader_Eof(MREADER* reader) { - return feof(((MFILEREADER*)reader)->file); + return uio_feof(((MFILEREADER*)reader)->file); } static BOOL _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size) { - return fread(ptr,size,1,((MFILEREADER*)reader)->file); + return uio_fread(ptr,size,1,((MFILEREADER*)reader)->file); } static int _mm_FileReader_Get(MREADER* reader) { - return fgetc(((MFILEREADER*)reader)->file); + return uio_fgetc(((MFILEREADER*)reader)->file); } static BOOL _mm_FileReader_Seek(MREADER* reader,long offset,int whence) { - return fseek(((MFILEREADER*)reader)->file, + return uio_fseek(((MFILEREADER*)reader)->file, (whence==SEEK_SET)?offset+_mm_iobase:offset,whence); } static long _mm_FileReader_Tell(MREADER* reader) { - return ftell(((MFILEREADER*)reader)->file)-_mm_iobase; + return uio_ftell(((MFILEREADER*)reader)->file)-_mm_iobase; } -MREADER *_mm_new_file_reader(FILE* fp) +MREADER *_mm_new_file_reader(uio_Stream* fp) { MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER)); if (reader) { @@ -231,31 +231,31 @@ void _mm_delete_file_reader (MREADER* reader) /*========== File Writer */ typedef struct MFILEWRITER { - MWRITER core; - FILE* file; + MWRITER core; + uio_Stream* file; } MFILEWRITER; static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence) { - return fseek(((MFILEWRITER*)writer)->file,offset,whence); + return uio_fseek(((MFILEWRITER*)writer)->file,offset,whence); } static long _mm_FileWriter_Tell(MWRITER* writer) { - return ftell(((MFILEWRITER*)writer)->file); + return uio_ftell(((MFILEWRITER*)writer)->file); } static BOOL _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size) { - return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size); + return (uio_fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size); } static BOOL _mm_FileWriter_Put(MWRITER* writer,int value) { - return fputc(value,((MFILEWRITER*)writer)->file); + return uio_fputc(value,((MFILEWRITER*)writer)->file); } -MWRITER *_mm_new_file_writer(FILE* fp) +MWRITER *_mm_new_file_writer(uio_Stream* fp) { MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER)); if (writer) { diff --git a/sc2/src/sc2code/libs/sound/decoders/mikmod/mwav.c b/sc2/src/sc2code/libs/sound/decoders/mikmod/mwav.c index 447329887..6f1c477b8 100644 --- a/sc2/src/sc2code/libs/sound/decoders/mikmod/mwav.c +++ b/sc2/src/sc2code/libs/sound/decoders/mikmod/mwav.c @@ -143,7 +143,7 @@ SAMPLE* Sample_LoadGeneric(MREADER* reader) return result; } -SAMPLE* Sample_LoadFP(FILE *fp) +SAMPLE* Sample_LoadFP(uio_Stream *fp) { SAMPLE* result=NULL; MREADER* reader; @@ -155,15 +155,15 @@ SAMPLE* Sample_LoadFP(FILE *fp) return result; } -SAMPLE* Sample_Load(CHAR* filename) +SAMPLE* Sample_Load(uio_DirHandle* dir,CHAR* filename) { - FILE *fp; + uio_Stream *fp; SAMPLE *si=NULL; if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL; - if((fp=_mm_fopen(filename,"rb"))) { + if((fp=_mm_fopen(dir,filename,"rb"))) { si = Sample_LoadFP(fp); - fclose(fp); + uio_fclose(fp); } return si; } diff --git a/sc2/src/sc2code/libs/sound/decoders/wav.c b/sc2/src/sc2code/libs/sound/decoders/wav.c index 640ada3a7..fffeae2c7 100644 --- a/sc2/src/sc2code/libs/sound/decoders/wav.c +++ b/sc2/src/sc2code/libs/sound/decoders/wav.c @@ -53,52 +53,52 @@ typedef struct void -LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, - uint32 *freq, bool want_big_endian) +LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format, + void **data, uint32 *size, uint32 *freq, bool want_big_endian) { WAVChunkHdr_Struct ChunkHdr; WAVFileHdr_Struct FileHdr; WAVFmtHdr_Struct FmtHdr; - FILE *fp; + uio_Stream *fp; *format = decoder_formats.mono16; *data = NULL; *size = 0; *freq = 22050; - fp = fopen (file, "rb"); + fp = uio_fopen (dir, file, "rb"); if (fp) { - fread(&FileHdr.Id, 4, 1, fp); + uio_fread(&FileHdr.Id, 4, 1, fp); FileHdr.Id = UQM_SwapLE32 (FileHdr.Id); - fread(&FileHdr.Size, 4, 1, fp); + uio_fread(&FileHdr.Size, 4, 1, fp); FileHdr.Size = UQM_SwapLE32 (FileHdr.Size); - fread(&FileHdr.Type, 4, 1, fp); + uio_fread(&FileHdr.Type, 4, 1, fp); FileHdr.Type = UQM_SwapLE32 (FileHdr.Type); FileHdr.Size = ((FileHdr.Size + 1) & ~1) - 4; while (FileHdr.Size != 0) { - if (!fread (&ChunkHdr.Id, 4, 1, fp)) + if (!uio_fread (&ChunkHdr.Id, 4, 1, fp)) break; ChunkHdr.Id = UQM_SwapLE32 (ChunkHdr.Id); - if (!fread (&ChunkHdr.Size, 4, 1, fp)) + if (!uio_fread (&ChunkHdr.Size, 4, 1, fp)) break; ChunkHdr.Size = UQM_SwapLE32 (ChunkHdr.Size); if (ChunkHdr.Id == FMT) { - fread (&FmtHdr.Format, 2, 1, fp); + uio_fread (&FmtHdr.Format, 2, 1, fp); FmtHdr.Format = UQM_SwapLE16 (FmtHdr.Format); - fread (&FmtHdr.Channels, 2, 1, fp); + uio_fread (&FmtHdr.Channels, 2, 1, fp); FmtHdr.Channels = UQM_SwapLE16 (FmtHdr.Channels); - fread (&FmtHdr.SamplesPerSec, 4, 1, fp); + uio_fread (&FmtHdr.SamplesPerSec, 4, 1, fp); FmtHdr.SamplesPerSec = UQM_SwapLE32 (FmtHdr.SamplesPerSec); - fread (&FmtHdr.BytesPerSec, 4, 1, fp); + uio_fread (&FmtHdr.BytesPerSec, 4, 1, fp); FmtHdr.BytesPerSec = UQM_SwapLE32 (FmtHdr.BytesPerSec); - fread (&FmtHdr.BlockAlign, 2, 1, fp); + uio_fread (&FmtHdr.BlockAlign, 2, 1, fp); FmtHdr.BlockAlign = UQM_SwapLE16 (FmtHdr.BlockAlign); - fread (&FmtHdr.BitsPerSample, 2, 1, fp); + uio_fread (&FmtHdr.BitsPerSample, 2, 1, fp); FmtHdr.BitsPerSample = UQM_SwapLE16 (FmtHdr.BitsPerSample); if (FmtHdr.Format == 0x0001) @@ -112,12 +112,12 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, : decoder_formats.stereo16) ); *freq = FmtHdr.SamplesPerSec; - fseek (fp, ChunkHdr.Size - 16, SEEK_CUR); + uio_fseek (fp, ChunkHdr.Size - 16, SEEK_CUR); } else { fprintf (stderr, "LoadWAVFile(): unsupported format %x\n", FmtHdr.Format); - fclose (fp); + uio_fclose (fp); return; } } @@ -125,18 +125,18 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, { *size = ChunkHdr.Size; if ((*data = HMalloc (ChunkHdr.Size + 31))) - fread (*data, FmtHdr.BlockAlign, ChunkHdr.Size / FmtHdr.BlockAlign, fp); + uio_fread (*data, FmtHdr.BlockAlign, ChunkHdr.Size / FmtHdr.BlockAlign, fp); memset(((char *)*data) + ChunkHdr.Size, 0, 31); } else { - fseek(fp, ChunkHdr.Size, SEEK_CUR); + uio_fseek(fp, ChunkHdr.Size, SEEK_CUR); } - fseek (fp, ChunkHdr.Size & 1, SEEK_CUR); + uio_fseek (fp, ChunkHdr.Size & 1, SEEK_CUR); FileHdr.Size -= (((ChunkHdr.Size + 1) & ~1) + 8); } - fclose(fp); + uio_fclose(fp); } if (want_big_endian && @@ -148,3 +148,4 @@ LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, if (*size == 0) fprintf (stderr, "LoadWAVFile(): loading %s failed!\n", file); } + diff --git a/sc2/src/sc2code/libs/sound/decoders/wav.h b/sc2/src/sc2code/libs/sound/decoders/wav.h index 81aa23bbb..725967ced 100644 --- a/sc2/src/sc2code/libs/sound/decoders/wav.h +++ b/sc2/src/sc2code/libs/sound/decoders/wav.h @@ -19,9 +19,11 @@ #ifndef WAV_H #define WAV_H +#include "port.h" #include "types.h" +#include "uio.h" -void LoadWAVFile (const char *file, uint32 *format, void **data, uint32 *size, - uint32 *freq, bool want_big_endian); +void LoadWAVFile (uio_DirHandle *dir, const char *file, uint32 *format, + void **data, uint32 *size, uint32 *freq, bool want_big_endian); #endif diff --git a/sc2/src/sc2code/libs/sound/fileinst.c b/sc2/src/sc2code/libs/sound/fileinst.c index 4fbe2bc6f..2f0e86ba3 100644 --- a/sc2/src/sc2code/libs/sound/fileinst.c +++ b/sc2/src/sc2code/libs/sound/fileinst.c @@ -17,20 +17,21 @@ */ #include "sndintrn.h" +#include "options.h" extern char *_cur_resfile_name; SOUND_REF LoadSoundFile (PVOID pStr) { - FILE *fp; + uio_Stream *fp; // FIXME: this theoretically needs a mechanism to prevent races if (_cur_resfile_name) // something else is loading resources atm return 0; - fp = res_OpenResFile (pStr, "rb"); + fp = res_OpenResFile (contentDir, pStr, "rb"); if (fp) { MEM_HANDLE hData; @@ -50,14 +51,14 @@ LoadSoundFile (PVOID pStr) MUSIC_REF LoadMusicFile (PVOID pStr) { - FILE *fp; + uio_Stream *fp; // FIXME: this theoretically needs a mechanism to prevent races if (_cur_resfile_name) // something else is loading resources atm return 0; - fp = res_OpenResFile (pStr, "rb"); + fp = res_OpenResFile (contentDir, pStr, "rb"); if (fp) { MEM_HANDLE hData; diff --git a/sc2/src/sc2code/libs/sound/music.c b/sc2/src/sc2code/libs/sound/music.c index 789d3b867..32a0f93f7 100644 --- a/sc2/src/sc2code/libs/sound/music.c +++ b/sc2/src/sc2code/libs/sound/music.c @@ -107,7 +107,7 @@ SetMusicVolume (COUNT Volume) } MEM_HANDLE -_GetMusicData (FILE *fp, DWORD length) +_GetMusicData (uio_Stream *fp, DWORD length) { MEM_HANDLE h; extern char *_cur_resfile_name; @@ -142,20 +142,21 @@ _GetMusicData (FILE *fp, DWORD length) strcpy (threedoname, filename); strcpy (&threedoname[strlen (threedoname)-3], "ogg"); - if (fileExists (threedoname)) + if (fileExists2 (contentDir, threedoname)) { strcpy (filename, threedoname); - } - break; + } + break; } case OPT_PC: { break; - } + } } - fprintf (stderr, "_GetMusicData(): loading %s\n", filename); - if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096, 0, 0)) == 0) + fprintf (stderr, "_GetMusicData(): loading %s\n", filename); + if (((*pmus)->decoder = SoundDecoder_Load (contentDir, filename, + 4096, 0, 0)) == 0) { fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename); diff --git a/sc2/src/sc2code/libs/sound/sfx.c b/sc2/src/sc2code/libs/sound/sfx.c index 4fc9c74df..c4216172c 100644 --- a/sc2/src/sc2code/libs/sound/sfx.c +++ b/sc2/src/sc2code/libs/sound/sfx.c @@ -165,11 +165,8 @@ GetSampleRate (SOUND sound) } MEM_HANDLE -_GetSoundBankData (FILE *fp, DWORD length) +_GetSoundBankData (uio_Stream *fp, DWORD length) { -#ifdef WIN32 - int omode; -#endif int snd_ct, n; DWORD opos; char CurrentLine[1024], filename[1024]; @@ -178,7 +175,7 @@ _GetSoundBankData (FILE *fp, DWORD length) STRING_TABLE Snd; (void) length; // ignored - opos = ftell (fp); + opos = uio_ftell (fp); { char *s1, *s2; @@ -197,11 +194,9 @@ _GetSoundBankData (FILE *fp, DWORD length) } } -#ifdef WIN32 - omode = _setmode (fileno (fp), O_TEXT); -#endif snd_ct = 0; - while (fgets (CurrentLine, sizeof (CurrentLine), fp) && snd_ct < MAX_FX) + while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) && + snd_ct < MAX_FX) { if (sscanf(CurrentLine, "%s", &filename[n]) == 1) { @@ -211,7 +206,8 @@ _GetSoundBankData (FILE *fp, DWORD length) sndfx[snd_ct]->buffer_tag = 0; sndfx[snd_ct]->read_chain_ptr = NULL; - sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096, 0, 0); + sndfx[snd_ct]->decoder = SoundDecoder_Load (contentDir, + filename, 4096, 0, 0); if (!sndfx[snd_ct]->decoder) { fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); @@ -244,12 +240,9 @@ _GetSoundBankData (FILE *fp, DWORD length) } // pkunk insult fix 2002/11/12 (ftell shouldn't be needed for loop to terminate) - /*if (ftell (fp) - opos >= length) + /*if (uio_ftell (fp) - opos >= length) break;*/ } -#ifdef WIN32 - _setmode (fileno (fp), omode); -#endif Snd = 0; if (snd_ct && (Snd = AllocStringTable ( diff --git a/sc2/src/sc2code/libs/sound/sndintrn.h b/sc2/src/sc2code/libs/sound/sndintrn.h index 63e1d59ca..c6b63bedc 100644 --- a/sc2/src/sc2code/libs/sound/sndintrn.h +++ b/sc2/src/sc2code/libs/sound/sndintrn.h @@ -23,10 +23,10 @@ #include "sndlib.h" #include "reslib.h" -extern MEM_HANDLE _GetMusicData (FILE *fp, DWORD length); +extern MEM_HANDLE _GetMusicData (uio_Stream *fp, DWORD length); extern BOOLEAN _ReleaseMusicData (MEM_HANDLE handle); -extern MEM_HANDLE _GetSoundBankData (FILE *fp, DWORD length); +extern MEM_HANDLE _GetSoundBankData (uio_Stream *fp, DWORD length); extern BOOLEAN _ReleaseSoundBankData (MEM_HANDLE handle); #define AllocMusicData(s) AllocResourceData((s),MEM_ZEROINIT) diff --git a/sc2/src/sc2code/libs/sound/trackplayer.c b/sc2/src/sc2code/libs/sound/trackplayer.c index a3fe161e9..99d92335c 100644 --- a/sc2/src/sc2code/libs/sound/trackplayer.c +++ b/sc2/src/sc2code/libs/sound/trackplayer.c @@ -19,6 +19,7 @@ #include "sound.h" #include "libs/sound/trackplayer.h" #include "comm.h" +#include "options.h" static int tct; //total number of subtitle tracks static int tcur; //currently playing subtitle track @@ -316,7 +317,8 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) fprintf (stderr, "SpliceMultiTrack(): loading...\n"); for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++) { - track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768, 0, - 3 * TEXT_SPEED); + track_decs[tracks] = SoundDecoder_Load (contentDir, *TrackNames, + 32768, 0, - 3 * TEXT_SPEED); if (track_decs[tracks]) { fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n", @@ -471,7 +473,8 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers); sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers); TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); - decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[page_counter]); + decoder = SoundDecoder_Load (contentDir, TrackName, 4096, + startTime, time_stamps[page_counter]); sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0); sound_sample->decoder = decoder; first_chain = last_chain = sound_sample->read_chain_ptr; @@ -481,7 +484,8 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* else { TFB_SoundDecoder *decoder; - decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[page_counter]); + decoder = SoundDecoder_Load (contentDir, TrackName, 4096, + startTime, time_stamps[page_counter]); last_chain->next = create_soundchain (decoder, sound_sample->length); last_chain = last_chain->next; } diff --git a/sc2/src/sc2code/libs/strings/getstr.c b/sc2/src/sc2code/libs/strings/getstr.c index ee2f2d140..c9fac3849 100644 --- a/sc2/src/sc2code/libs/strings/getstr.c +++ b/sc2/src/sc2code/libs/strings/getstr.c @@ -18,6 +18,7 @@ #include "strintrn.h" #include "libs/graphics/gfx_common.h" +#include "options.h" #ifdef WIN32 #include #endif @@ -39,7 +40,7 @@ dword_convert (PDWORD dword_array, COUNT num_dwords) } MEM_HANDLE -_GetStringData (FILE *fp, DWORD length) +_GetStringData (uio_Stream *fp, DWORD length) { MEM_HANDLE hData; @@ -51,16 +52,13 @@ _GetStringData (FILE *fp, DWORD length) { #define MAX_STRINGS 2048 #define POOL_SIZE 4096 -#ifdef WIN32 - int omode; -#endif int n, path_len, num_data_sets; DWORD opos, slen[MAX_STRINGS], StringOffs, tot_string_size, clen[MAX_STRINGS], ClipOffs, tot_clip_size, tslen[MAX_STRINGS], TSOffs, tot_ts_size; char CurrentLine[1024], clip_path[1024], *strdata, *clipdata, *ts_data; - FILE *timestamp_fp = NULL; + uio_Stream *timestamp_fp = NULL; if ((strdata = HMalloc (tot_string_size = POOL_SIZE)) == 0) return (0); @@ -97,7 +95,8 @@ _GetStringData (FILE *fp, DWORD length) s += 2; *s++ = 's'; *s = '\0'; - if ((timestamp_fp = fopen (ts_file_name, "rb"))) + if ((timestamp_fp = uio_fopen (contentDir, ts_file_name, + "rb"))) { fprintf (stderr, "Found timestamp file: %s\n", ts_file_name); if ((ts_data = HMalloc (tot_ts_size = POOL_SIZE)) == 0) @@ -105,13 +104,10 @@ _GetStringData (FILE *fp, DWORD length) } } - opos = ftell (fp); -#ifdef WIN32 - omode = _setmode (fileno (fp), O_TEXT); -#endif + opos = uio_ftell (fp); n = -1; StringOffs = ClipOffs = TSOffs = 0; - while (fgets (CurrentLine, sizeof (CurrentLine), fp) && n < MAX_STRINGS - 1) + while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) && n < MAX_STRINGS - 1) { int l; @@ -139,7 +135,7 @@ _GetStringData (FILE *fp, DWORD length) { char TimeStampLine[1024], *tsptr; BOOLEAN ts_ok = FALSE; - fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp); + uio_fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp); if (TimeStampLine[0] == '#') { tslen[n] = 0; @@ -171,7 +167,7 @@ _GetStringData (FILE *fp, DWORD length) // timestamp data is invalid, remove all of it fprintf (stderr, "Invalid timestamp data for '%s'. Disabling timestamps\n", s); HFree (ts_data); - fclose (timestamp_fp); + uio_fclose (timestamp_fp); timestamp_fp = NULL; TSOffs = 0; } @@ -219,12 +215,9 @@ _GetStringData (FILE *fp, DWORD length) strcpy (s, CurrentLine); } - if ((int)ftell (fp) - (int)opos >= (int)length) + if ((int)uio_ftell (fp) - (int)opos >= (int)length) break; } - #ifdef WIN32 - _setmode (fileno (fp), omode); - #endif if (n >= 0) { while (slen[n] > 1 && strdata[StringOffs - 2] == '\n') @@ -236,7 +229,7 @@ _GetStringData (FILE *fp, DWORD length) } if (timestamp_fp) - fclose (timestamp_fp); + uio_fclose (timestamp_fp); hData = 0; num_data_sets = (ClipOffs ? 1 : 0) + (TSOffs ? 1 : 0) + 1; diff --git a/sc2/src/sc2code/libs/strings/sfileins.c b/sc2/src/sc2code/libs/strings/sfileins.c index 5c5872116..b193cd63c 100644 --- a/sc2/src/sc2code/libs/strings/sfileins.c +++ b/sc2/src/sc2code/libs/strings/sfileins.c @@ -16,26 +16,28 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "port.h" #include "strintrn.h" +#include "uio.h" extern char *_cur_resfile_name; STRING_TABLE -LoadStringTableFile (PVOID pStr) +LoadStringTableFile (uio_DirHandle *dir, char *fileName) { - FILE *fp; + uio_Stream *fp; // FIXME: this theoretically needs a mechanism to prevent races if (_cur_resfile_name) // something else is loading resources atm return 0; - fp = res_OpenResFile (pStr, "rb"); + fp = res_OpenResFile (dir, fileName, "rb"); if (fp) { MEM_HANDLE hData; - _cur_resfile_name = pStr; + _cur_resfile_name = fileName; hData = _GetStringData (fp, LengthResFile (fp)); _cur_resfile_name = 0; res_CloseResFile (fp); diff --git a/sc2/src/sc2code/libs/strings/strintrn.h b/sc2/src/sc2code/libs/strings/strintrn.h index 8f9eebb08..c9d02eaf7 100644 --- a/sc2/src/sc2code/libs/strings/strintrn.h +++ b/sc2/src/sc2code/libs/strings/strintrn.h @@ -46,7 +46,7 @@ typedef STRING_TABLE_DESC *PSTRING_TABLE_DESC; #define BUILD_STRING(h,i) ((STRING_TABLE)MAKE_DWORD(h,i)) #define BUILD_STRING_TABLE(h) (STRING_TABLE)(h) -extern MEM_HANDLE _GetStringData (FILE *fp, DWORD length); +extern MEM_HANDLE _GetStringData (uio_Stream *fp, DWORD length); #endif /* _STRINTRN_H */ diff --git a/sc2/src/sc2code/libs/strlib.h b/sc2/src/sc2code/libs/strlib.h index 1da628398..93f60394a 100644 --- a/sc2/src/sc2code/libs/strlib.h +++ b/sc2/src/sc2code/libs/strlib.h @@ -20,6 +20,8 @@ #define _STRLIB_H #include "compiler.h" +#include "port.h" +#include "libs/uio.h" typedef DWORD STRING_TABLE; typedef DWORD STRING; @@ -27,7 +29,8 @@ typedef PBYTE STRINGPTR; extern BOOLEAN InstallStringTableResType (COUNT string_type); extern STRING_TABLE LoadStringTableInstance (DWORD res); -extern STRING_TABLE LoadStringTableFile (PVOID pStr); +extern STRING_TABLE LoadStringTableFile (uio_DirHandle *dir, + char *fileName); extern BOOLEAN DestroyStringTable (STRING_TABLE StringTable); extern STRING CaptureStringTable (STRING_TABLE StringTable); extern STRING_TABLE ReleaseStringTable (STRING String); diff --git a/sc2/src/sc2code/libs/uio.h b/sc2/src/sc2code/libs/uio.h new file mode 100644 index 000000000..15acfc467 --- /dev/null +++ b/sc2/src/sc2code/libs/uio.h @@ -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 */ + diff --git a/sc2/src/sc2code/libs/uio/COPYING b/sc2/src/sc2code/libs/uio/COPYING new file mode 100644 index 000000000..2774fef74 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/COPYING @@ -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. + + + Copyright (C) + + 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. + + , 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. + + diff --git a/sc2/src/sc2code/libs/uio/Makeinfo b/sc2/src/sc2code/libs/uio/Makeinfo new file mode 100644 index 000000000..1231c0f19 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/Makeinfo @@ -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 + diff --git a/sc2/src/sc2code/libs/uio/charhashtable.c b/sc2/src/sc2code/libs/uio/charhashtable.c new file mode 100644 index 000000000..ba5b09032 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/charhashtable.c @@ -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); +} + + diff --git a/sc2/src/sc2code/libs/uio/charhashtable.h b/sc2/src/sc2code/libs/uio/charhashtable.h new file mode 100644 index 000000000..b30a021b5 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/charhashtable.h @@ -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 */ + diff --git a/sc2/src/sc2code/libs/uio/debug.c b/sc2/src/sc2code/libs/uio/debug.c new file mode 100644 index 000000000..b1d56ce10 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/debug.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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; +} + + diff --git a/sc2/src/sc2code/libs/uio/debug.h b/sc2/src/sc2code/libs/uio/debug.h new file mode 100644 index 000000000..2d3a4de46 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/debug.h @@ -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 */ + + diff --git a/sc2/src/sc2code/libs/uio/defaultfs.c b/sc2/src/sc2code/libs/uio/defaultfs.c new file mode 100644 index 000000000..bf6d247ae --- /dev/null +++ b/sc2/src/sc2code/libs/uio/defaultfs.c @@ -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]; +} + + diff --git a/sc2/src/sc2code/libs/uio/defaultfs.h b/sc2/src/sc2code/libs/uio/defaultfs.h new file mode 100644 index 000000000..711ac0c8a --- /dev/null +++ b/sc2/src/sc2code/libs/uio/defaultfs.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#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 */ + diff --git a/sc2/src/sc2code/libs/uio/doc/basics b/sc2/src/sc2code/libs/uio/doc/basics new file mode 100644 index 000000000..9ea3af2f4 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/doc/basics @@ -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 + + diff --git a/sc2/src/sc2code/libs/uio/doc/conventions b/sc2/src/sc2code/libs/uio/doc/conventions new file mode 100644 index 000000000..ccc6b0b5e --- /dev/null +++ b/sc2/src/sc2code/libs/uio/doc/conventions @@ -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. + + diff --git a/sc2/src/sc2code/libs/uio/doc/notes b/sc2/src/sc2code/libs/uio/doc/notes new file mode 100644 index 000000000..a09e8c613 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/doc/notes @@ -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. + + diff --git a/sc2/src/sc2code/libs/uio/doc/todo b/sc2/src/sc2code/libs/uio/doc/todo new file mode 100644 index 000000000..740837386 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/doc/todo @@ -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 + + diff --git a/sc2/src/sc2code/libs/uio/fileblock.c b/sc2/src/sc2code/libs/uio/fileblock.c new file mode 100644 index 000000000..d8f0f6a0a --- /dev/null +++ b/sc2/src/sc2code/libs/uio/fileblock.c @@ -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 + +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); +} + + diff --git a/sc2/src/sc2code/libs/uio/fileblock.h b/sc2/src/sc2code/libs/uio/fileblock.h new file mode 100644 index 000000000..04e049007 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/fileblock.h @@ -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 + +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 */ + + diff --git a/sc2/src/sc2code/libs/uio/fstypes.c b/sc2/src/sc2code/libs/uio/fstypes.c new file mode 100644 index 000000000..e76773449 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/fstypes.c @@ -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 +#include + +#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); +} + + diff --git a/sc2/src/sc2code/libs/uio/fstypes.h b/sc2/src/sc2code/libs/uio/fstypes.h new file mode 100644 index 000000000..8a7416e54 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/fstypes.h @@ -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 +#include +#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 */ + diff --git a/sc2/src/sc2code/libs/uio/gphys.c b/sc2/src/sc2code/libs/uio/gphys.c new file mode 100644 index 000000000..ecb89416a --- /dev/null +++ b/sc2/src/sc2code/libs/uio/gphys.c @@ -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 +#include + +#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 + + diff --git a/sc2/src/sc2code/libs/uio/gphys.h b/sc2/src/sc2code/libs/uio/gphys.h new file mode 100644 index 000000000..bafa26513 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/gphys.h @@ -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 +#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 */ + diff --git a/sc2/src/sc2code/libs/uio/hashtable.c b/sc2/src/sc2code/libs/uio/hashtable.c new file mode 100644 index 000000000..5f8dc252c --- /dev/null +++ b/sc2/src/sc2code/libs/uio/hashtable.c @@ -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 +#include +#include +#include + +#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); +} + diff --git a/sc2/src/sc2code/libs/uio/hashtable.h b/sc2/src/sc2code/libs/uio/hashtable.h new file mode 100644 index 000000000..fc89cee06 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/hashtable.h @@ -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) */ + + diff --git a/sc2/src/sc2code/libs/uio/io.c b/sc2/src/sc2code/libs/uio/io.c new file mode 100644 index 000000000..db7c0c755 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/io.c @@ -0,0 +1,1371 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "iointrn.h" +#include "ioaux.h" +#include "mount.h" +#include "fstypes.h" +#include "mounttree.h" +#include "physical.h" +#include "paths.h" +#include "mem.h" +#include "uioutils.h" +#include "uioport.h" +#ifdef uio_MEM_DEBUG +# include "memdebug.h" +#endif + +static void uio_PDirHandles_delete(uio_PDirHandle *pDirHandles[], + int numPDirHandles); + +static inline uio_PDirHandle *uio_PDirHandle_alloc(void); +static inline void uio_PDirHandle_free(uio_PDirHandle *pDirHandle); +static inline uio_PFileHandle *uio_PFileHandle_alloc(void); +static inline void uio_PFileHandle_free(uio_PFileHandle *pFileHandle); + +static uio_DirHandle *uio_newDirHandle(uio_Repository *repository, char *path, + char *rootEnd); +static inline uio_DirHandle *uio_allocDirHandle(void); +static inline void uio_DirHandle_free(uio_DirHandle *dirHandle); + +static inline uio_Handle *uio_Handle_alloc(void); +static inline void uio_Handle_free(uio_Handle *handle); + +static uio_MountHandle *uio_MountHandle_new(uio_Repository *repository, + uio_MountInfo *mountInfo); +static inline void uio_MountHandle_delete(uio_MountHandle *mountHandle); +static inline uio_MountHandle *uio_MountHandle_alloc(void); +static inline void uio_MountHandle_free(uio_MountHandle *mountHandle); + + + +void +uio_init(void) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_init(); +#endif + uio_registerDefaultFileSystems(); +} + +void +uio_unInit(void) { + uio_unRegisterDefaultFileSystems(); +#ifdef uio_MEM_DEBUG +# ifdef DEBUG + uio_MemDebug_printPointers(stderr); + fflush(stderr); +# endif + uio_MemDebug_unInit(); +#endif +} + +uio_Repository * +uio_openRepository(int flags) { + return uio_newRepository(flags); +} + +void +uio_closeRepository(uio_Repository *repository) { + uio_unmountAllDirs(repository); + uio_Repository_unref(repository); +} + +/* + * Function name: uio_mountDir + * Description: Grafts a directory from inside a physical fileSystem + * into the locical filesystem, at a specified directory. + * Arguments: destRep - the repository where the newly mounted dir + * is to be grafted. + * mountPoint - the path to the directory where the dir + * is to be grafted. + * fsType - the file system type of physical fileSystem + * pointed to by sourcePath. + * sourceDir - the directory to which 'sourcePath' is to + * be taken relative. + * sourcePath - a path relative to sourceDir, which contains + * the file/directory to be mounted. + * inPath - the location relative to the root of the newly + * mounted fileSystem, pointing to the directory + * that is to be grafted. + * autoMount - array of automount options in function + * in this mountPoint. + * flags - one of uio_MOUNT_TOP, uio_MOUNT_BOTTOM, + * uio_MOUNT_BELOW, uio_MOUNT_ABOVE, specifying + * the precedence of this mount, OR'ed with + * one or more of the following flags: + * uio_MOUNT_RDONLY (no writing is allowed) + * relative - If 'flags' includes uio_MOUNT_BELOW or + * uio_MOUNT_ABOVE, this is the mount handle + * where the new mount is relative to. + * Otherwise, it should be NULL. + * Returns: a handle suitable for uio_unmountDir() + * NULL if an error occured. In this case 'errno' is set. + */ +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) { + uio_PRoot *pRoot; + uio_Handle *handle; + uio_FileSystemHandler *handler; + uio_MountInfo *relativeInfo; + + switch (flags & uio_MOUNT_LOCATION_MASK) { + case uio_MOUNT_TOP: + case uio_MOUNT_BOTTOM: + if (relative != NULL) { + errno = EINVAL; + return NULL; + } + relativeInfo = NULL; + break; + case uio_MOUNT_BELOW: + case uio_MOUNT_ABOVE: + if (relative == NULL) { + errno = EINVAL; + return NULL; + } + relativeInfo = relative->mountInfo; + break; + default: + abort(); + } + + if (mountPoint[0] == '/') + mountPoint++; + if (!validPathName(mountPoint, strlen(mountPoint))) { + errno = EINVAL; + return NULL; + } + + // TODO: check if the filesystem is already mounted, and if so, reuse it. + // A RO filedescriptor will need to be replaced though if the + // filesystem needs to be remounted RW now. + if (sourceDir == NULL) { + if (sourcePath != NULL) { + // bad: sourceDir is NULL, but sourcePath isn't + errno = EINVAL; + return NULL; + } + handle = NULL; + } else { + if (sourcePath == NULL) { + // bad: sourcePath is NULL, but sourceDir isn't + errno = EINVAL; + return NULL; + } + handle = uio_open(sourceDir, sourcePath, + ((flags & uio_MOUNT_RDONLY) == uio_MOUNT_RDONLY ? + O_RDONLY : O_RDWR) +#ifdef WIN32 + | O_BINARY +#endif + , 0); + if (handle == NULL) { + // errno is set + return NULL; + } + } + + handler = uio_getFileSystemHandler(fsType); + if (handler == NULL) { + if (handle) + uio_close(handle); + errno = ENODEV; + return NULL; + } + + assert(handler->mount != NULL); + pRoot = handler->mount(handle, flags); + if (pRoot == NULL) { + int savedErrno; + + savedErrno = errno; + if (handle) + uio_close(handle); + errno = savedErrno; + return NULL; + } + + if (handle) { + // Close this reference to handle. + // The physical layer may store the link in pRoot, in which it + // will be cleaned up from uio_unmount(). + uio_close(handle); + } + + // The new file system is ready, now we need to find the specified + // dir inside it and put it in its place in the mountTree. + { + uio_PDirHandle *endDirHandle; + const char *endInPath; + char *dirName; + uio_MountInfo *mountInfo; + uio_MountTree *mountTree; + uio_PDirHandle *pRootHandle; +#ifdef WIN32 + char *unixPath; + + unixPath = dosToUnixPath(inPath); + inPath = unixPath; +#endif + + if (inPath[0] == '/') + inPath++; + pRootHandle = uio_PRoot_getRootDirHandle(pRoot); + uio_walkPhysicalPath(pRootHandle, inPath, strlen(inPath), + &endDirHandle, &endInPath); + if (*endInPath != '\0') { + // Path inside the filesystem to mount does not exist. +#ifdef WIN32 + uio_free(unixPath); +#endif + uio_PDirHandle_unref(endDirHandle); + uio_PRoot_unrefMount(pRoot); + if (handle) + uio_close(handle); + errno = ENOENT; + return NULL; + } + + dirName = uio_malloc(endInPath - inPath + 1); + memcpy(dirName, inPath, endInPath - inPath); + dirName[endInPath - inPath] = '\0'; +#ifdef WIN32 + // InPath is a copy with the paths fixed. + uio_free(unixPath); +#endif + mountInfo = uio_newMountInfo(fsType, NULL, endDirHandle, dirName, + autoMount, NULL, flags); + uio_repositoryAddMount(destRep, mountInfo, + flags & uio_MOUNT_LOCATION_MASK, relativeInfo); + mountTree = uio_mountTreeAddMountInfo(destRep, destRep->mountTree, + mountInfo, mountPoint, flags & uio_MOUNT_LOCATION_MASK, + relativeInfo); + // mountTree is the node in destRep->mountTree where mountInfo + // leads to. + mountInfo->mountTree = mountTree; + mountInfo->mountHandle = uio_MountHandle_new(destRep, mountInfo); + return mountInfo->mountHandle; + } +} + +int +uio_unmountDir(uio_MountHandle *mountHandle) { + uio_PRoot *pRoot; + + pRoot = mountHandle->mountInfo->pDirHandle->pRoot; + + // check if it's in use +#ifdef DEBUG + if (pRoot->mountRef == 1 && pRoot->handleRef > 0) { + fprintf(stderr, "Warning: File system to be unmounted still " + "has file descriptors open. The file system will not " + "be deallocated until these are all closed.\n"); + } +#endif + + // TODO: lock (and furtheron unlock) repository + + // remove from mount tree + uio_mountTreeRemoveMountInfo(mountHandle->repository, + mountHandle->mountInfo->mountTree, + mountHandle->mountInfo); + + // remove from mount list. + uio_repositoryRemoveMount(mountHandle->repository, + mountHandle->mountInfo); + + uio_deleteMountInfo(mountHandle->mountInfo); + + uio_MountHandle_delete(mountHandle); + uio_PRoot_unrefMount(pRoot); + return 0; +} + +int +uio_unmountAllDirs(uio_Repository *repository) { + int i; + + i = repository->numMounts; + while (i--) + uio_unmountDir(repository->mounts[i]->mountHandle); + return 0; +} + +int +uio_close(uio_Handle *handle) { + uio_Handle_unref(handle); + return 0; +} + +int +uio_fstat(uio_Handle *handle, struct stat *statBuf) { + if (handle->root->handler->fstat == NULL) { + errno = ENOSYS; + return -1; + } + return handle->root->handler->fstat(handle, statBuf); +} + +int +uio_stat(uio_DirHandle *dir, const char *path, struct stat *statBuf) { + uio_PDirHandle *pReadDir; + uio_MountInfo *readMountInfo; + char *name; + int result; + + // TODO: If it's a dir, check all physical dirs, and merge the + // direntry times. + if (uio_getPhysicalAccess(dir, path, O_RDONLY, + &readMountInfo, &pReadDir, + NULL, NULL, &name) == -1) { + if (errno == EISDIR) { + // Need to merge the dirs. + memset(statBuf, '\0', sizeof (struct stat)); + statBuf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | + S_IRGRP | S_IWGRP | S_IXOTH | + S_IROTH | S_IWOTH | S_IXOTH; + statBuf->st_uid = 0; + statBuf->st_gid = 0; + return 0; + } + return -1; + } + + if (pReadDir->pRoot->handler->stat == NULL) { + uio_PDirHandle_unref(pReadDir); + errno = ENOSYS; + return -1; + } + + result = pReadDir->pRoot->handler->stat(pReadDir, name, statBuf); + uio_PDirHandle_unref(pReadDir); + return result; +} + +int +uio_mkdir(uio_DirHandle *dir, const char *path, mode_t mode) { + uio_PDirHandle *pReadDir, *pWriteDir; + uio_MountInfo *readMountInfo, *writeMountInfo; + char *name; + uio_PDirHandle *newDirHandle; + + if (uio_getPhysicalAccess(dir, path, O_WRONLY | O_CREAT | O_EXCL, + &readMountInfo, &pReadDir, + &writeMountInfo, &pWriteDir, &name) == -1) { + // errno is set + if (errno == EISDIR) + errno = EEXIST; + return -1; + } + uio_PDirHandle_unref(pReadDir); + + if (pWriteDir->pRoot->handler->mkdir == NULL) { + uio_free(name); + uio_PDirHandle_unref(pWriteDir); + errno = ENOSYS; + return -1; + } + + newDirHandle = pWriteDir->pRoot->handler->mkdir(pWriteDir, name, mode); + if (newDirHandle == NULL) { + int saveErrno = errno; + uio_free(name); + uio_PDirHandle_unref(pWriteDir); + errno = saveErrno; + return -1; + } + + uio_PDirHandle_unref(pWriteDir); + uio_PDirHandle_unref(newDirHandle); + uio_free(name); + return 0; +} + +uio_Handle * +uio_open(uio_DirHandle *dir, const char *path, int flags, mode_t mode) { + uio_PDirHandle *readPDirHandle, *writePDirHandle, *pDirHandle; + uio_MountInfo *readMountInfo, *writeMountInfo; + char *name; + uio_Handle *handle; + + if (uio_getPhysicalAccess(dir, path, flags, + &readMountInfo, &readPDirHandle, + &writeMountInfo, &writePDirHandle, &name) == -1) { + // errno is set + return NULL; + } + + if ((flags & O_ACCMODE) == O_RDONLY) { + // WritePDirHandle is not filled in. + pDirHandle = readPDirHandle; + } else if (readPDirHandle == writePDirHandle) { + // In general, the dirs can be the same even when the handles are + // not the same. But here it works, because uio_getPhysicalAccess + // guarantees it. + uio_PDirHandle_unref(writePDirHandle); + pDirHandle = readPDirHandle; + } else { + // need to write + uio_PDirEntryHandle *entry; + + entry = uio_getPDirEntryHandle(readPDirHandle, name); + if (entry != NULL) { + // file already exists + uio_PDirEntryHandle_unref(entry); + if ((flags & O_CREAT) == O_CREAT && + (flags & O_EXCL) == O_EXCL) { + uio_free(name); + uio_PDirHandle_unref(readPDirHandle); + uio_PDirHandle_unref(writePDirHandle); + errno = EEXIST; + return NULL; + } + if ((flags & O_TRUNC) == O_TRUNC) { + // No use copying the file to the writable dir. + // As it doesn't exists there, O_TRUNC needs to be turned off + // though. + flags &= ~O_TRUNC; + } else { + // file needs to be copied + if (uio_copyFilePhysical(readPDirHandle, name, writePDirHandle, + name) == -1) { + int saveErrno = errno; + uio_free(name); + uio_PDirHandle_unref(readPDirHandle); + uio_PDirHandle_unref(writePDirHandle); + errno = saveErrno; + return NULL; + } + } + } else { + // file does not exist + if (((flags & O_ACCMODE) == O_RDONLY) || + (flags & O_CREAT) != O_CREAT) { + uio_free(name); + uio_PDirHandle_unref(readPDirHandle); + uio_PDirHandle_unref(writePDirHandle); + errno = ENOENT; + return NULL; + } + } + uio_PDirHandle_unref(readPDirHandle); + pDirHandle = writePDirHandle; + } + + handle = pDirHandle->pRoot->handler->open(pDirHandle, name, flags, mode); + // Also adds a new entry to the physical dir if appropriate. + if (handle == NULL) { + int saveErrno = errno; + uio_free(name); + uio_PDirHandle_unref(pDirHandle); + errno = saveErrno; + return NULL; + } + + uio_free(name); + uio_PDirHandle_unref(pDirHandle); + return handle; +} + +uio_DirHandle * +uio_openDir(uio_Repository *repository, const char *path, int flags) { + uio_DirHandle *dirHandle; + const char * const rootStr = "/"; + + dirHandle = uio_newDirHandle(repository, + unconst(rootStr), unconst(rootStr)); + if (uio_verifyPath(dirHandle, path, &dirHandle->path) == -1) { + int saveErrno = errno; + uio_DirHandle_free(dirHandle); + errno = saveErrno; + return NULL; + } + // TODO: increase ref in repository? + dirHandle->rootEnd = dirHandle->path; + if (flags & uio_OD_ROOT) + dirHandle->rootEnd += strlen(dirHandle->path); + return dirHandle; +} + +uio_DirHandle * +uio_openDirRelative(uio_DirHandle *base, const char *path, int flags) { + uio_DirHandle *dirHandle; + char *newPath; + + if (uio_verifyPath(base, path, &newPath) == -1) { + // errno is set + return NULL; + } + if (flags & uio_OD_ROOT) { + dirHandle = uio_newDirHandle(base->repository, + newPath, newPath + strlen(newPath)); + // TODO: increase ref in base->repository? + } else { + // use the root of the base dir + dirHandle = uio_newDirHandle(base->repository, + newPath, newPath + (base->rootEnd - base->path)); + } + return dirHandle; +} + +int +uio_closeDir(uio_DirHandle *dirHandle) { + uio_free(dirHandle->path); + uio_DirHandle_free(dirHandle); + return 0; +} + +ssize_t +uio_read(uio_Handle *handle, void *buf, size_t count) { + return handle->root->handler->read(handle, buf, count); +} + +int +uio_rmdir(uio_DirHandle *dirHandle, const char *path) { + int numPDirHandles; + uio_PDirHandle *pDirHandle, **pDirHandles; + const char *pathEnd, *name; + uio_PDirEntryHandle *entry; + uio_MountTreeItem **items; + int i; + int numDeleted; + + pathEnd = strrchr(path, '/'); + if (pathEnd == NULL) { + pathEnd = path; + name = path; + } else + name = pathEnd + 1; + + if (uio_getPathPhysicalDirs(dirHandle, path, pathEnd - path, + &pDirHandles, &numPDirHandles, &items) == -1) { + // errno is set + return -1; + } + + entry = NULL; + // Should be set before a possible goto. + + if (name[0] == '\0') { + // path was of the form "foo/bar/" or "/foo/bar/" + // These are intentionally not accepted. + // I see this as a path and not as a directory identifier. + errno = ENOENT; + goto err; + } + + numDeleted = 0; + for (i = 0; i < numPDirHandles; i++) { + pDirHandle = pDirHandles[i]; + entry = uio_getPDirEntryHandle(pDirHandle, name); + + if (entry == NULL) + continue; + + if (!uio_PDirEntryHandle_isDir(entry)) { + errno = ENOTDIR; + goto err; + } + + if (uio_mountInfoIsReadOnly(items[i]->mountInfo)) { + errno = EROFS; + goto err; + } + + if (pDirHandle->pRoot->handler->rmdir == NULL) { + errno = ENOSYS; + goto err; + } + + if (pDirHandle->pRoot->handler->rmdir(pDirHandle, name) == -1) { + // errno is set + goto err; + } + numDeleted++; + uio_PDirEntryHandle_unref(entry); + } + entry = NULL; + + if (numDeleted == 0) { + errno = ENOENT; + goto err; + } + + uio_PDirHandles_delete(pDirHandles, numPDirHandles); + uio_free(items); + return 0; + +err: + { + int saveErrno = errno; + uio_PDirHandles_delete(pDirHandles, numPDirHandles); + uio_free(items); + if (entry != NULL) + uio_PDirEntryHandle_unref(entry); + errno = saveErrno; + return -1; + } +} + +static void +uio_PDirHandles_delete(uio_PDirHandle *pDirHandles[], int numPDirHandles) { + while (numPDirHandles--) + uio_PDirHandle_unref(pDirHandles[numPDirHandles]); + uio_free(pDirHandles); +} + +int +uio_lseek(uio_Handle *handle, off_t offset, int whence) { + if (handle->root->handler->seek == NULL) { + errno = ENOSYS; + return -1; + } + return handle->root->handler->seek(handle, offset, whence); +} + +int +uio_write(uio_Handle *handle, const void *buf, size_t count) { + if (handle->root->handler->write == NULL) { + errno = ENOSYS; + return -1; + } + return handle->root->handler->write(handle, buf, count); +} + +int +uio_unlink(uio_DirHandle *dirHandle, const char *path) { + int numPDirHandles; + uio_PDirHandle *pDirHandle, **pDirHandles; + const char *pathEnd, *name; + uio_PDirEntryHandle *entry; + uio_MountTreeItem **items; + int i; + int numDeleted; + + pathEnd = strrchr(path, '/'); + if (pathEnd == NULL) { + pathEnd = path; + name = path; + } else + name = pathEnd + 1; + + if (uio_getPathPhysicalDirs(dirHandle, path, pathEnd - path, + &pDirHandles, &numPDirHandles, &items) == -1) { + // errno is set + return -1; + } + + entry = NULL; + // Should be set before a possible goto. + + if (name[0] == '\0') { + // path was of the form "foo/bar/" or "/foo/bar/" + errno = ENOENT; + goto err; + } + + numDeleted = 0; + for (i = 0; i < numPDirHandles; i++) { + pDirHandle = pDirHandles[i]; + entry = uio_getPDirEntryHandle(pDirHandle, name); + + if (entry == NULL) + continue; + + if (uio_PDirEntryHandle_isDir(entry)) { + errno = EISDIR; + goto err; + } + + if (uio_mountInfoIsReadOnly(items[i]->mountInfo)) { + errno = EROFS; + goto err; + } + + if (pDirHandle->pRoot->handler->unlink == NULL) { + errno = ENOSYS; + goto err; + } + + if (pDirHandle->pRoot->handler->unlink(pDirHandle, name) == -1) { + // errno is set + goto err; + } + numDeleted++; + uio_PDirEntryHandle_unref(entry); + } + entry = NULL; + + if (numDeleted == 0) { + errno = ENOENT; + goto err; + } + + uio_PDirHandles_delete(pDirHandles, numPDirHandles); + uio_free(items); + return 0; + +err: + { + int saveErrno = errno; + uio_PDirHandles_delete(pDirHandles, numPDirHandles); + uio_free(items); + if (entry != NULL) + uio_PDirEntryHandle_unref(entry); + errno = saveErrno; + return -1; + } +} + +// *** begin dirList stuff *** // + +#define uio_DIR_BUFFER_SIZE 2048 + // Large values will give significantly better speed for large + // directories. What is stored in the buffer is file names + // plus one pointer per file name, so with an average size of 16 + // characters per file (including \0), a buffer of size 2048 will + // store approximately 100 files. + // It should be at least big enough to store one entry (NAME_MAX is + // 255 on POSIX systems). + // TODO: add a compile-time check for this + +typedef struct uio_DirBufferLink { + char *buffer; + int numEntries; + struct uio_DirBufferLink *next; +} uio_DirBufferLink; + +static int strPtrCmp(const char * const *ptr1, const char * const *ptr2); +static void uio_freeDirBufferLink(uio_DirBufferLink *sdbl); +static void uio_freeDirBufferChain(uio_DirBufferLink *dirBufferLink); +static uio_DirList *uio_getDirListMulti(uio_PDirHandle **pDirHandles, + int numPDirHandles, const char *pattern, match_MatchType matchType); +static uio_DirList *uio_makeDirList(const char **newNames, + const char * const *names, int numNames); +static uio_DirList *uio_newDirList(const char **names, int numNames, + char *buffer); +static void uio_collectDirEntries(uio_PDirHandle *pDirHandle, + uio_DirBufferLink **linkPtr, int *numEntries); +static inline uio_DirList *uio_allocDirList(void); +static void uio_filterNames(const char * const *names, int numNames, + const char **newNames, int *numNewNames, + match_MatchContext *matchContext); + +static uio_EntriesContext *uio_openEntriesPhysical(uio_PDirHandle *dirHandle); +static int uio_readEntriesPhysical(uio_EntriesContext *iterator, char *buf, + size_t len); +static void uio_closeEntriesPhysical(uio_EntriesContext *iterator); +static uio_EntriesContext *uio_EntriesContext_new(uio_PRoot *pRoot, + uio_NativeEntriesContext *native); +static inline uio_EntriesContext *uio_EntriesContext_alloc(void); +static inline void uio_EntriesContext_delete(uio_EntriesContext *entriesContext); +static inline void uio_EntriesContext_free(uio_EntriesContext + *entriesContext); + +// The caller may modify the elements of dirHandle->names, but +// dirHandle->names itself, and the rest of the elements of dirHandle +// should be left alone, so that they will be freed by uio_freeDirList(). +uio_DirList * +uio_getDirList(uio_DirHandle *dirHandle, const char *path, const char *pattern, + match_MatchType matchType) { + int numPDirHandles; + uio_PDirHandle **pDirHandles; + uio_DirList *result; + + if (uio_getPathPhysicalDirs(dirHandle, path, strlen(path), + &pDirHandles, &numPDirHandles, NULL) == -1) { + // errno is set + return NULL; + } + + if (numPDirHandles == 0) { + assert(pDirHandles == NULL); + // nothing to free + return uio_newDirList(NULL, 0, NULL); + } + + result = uio_getDirListMulti(pDirHandles, numPDirHandles, pattern, + matchType); + + { + int saveErrno; + saveErrno = errno; + uio_PDirHandles_delete(pDirHandles, numPDirHandles); + errno = saveErrno; + } + return result; +} + +// Names and newNames may point to the same location. +// &numNames and numNewNames may point to the same location. +static void +uio_filterDoubleNames(const char * const *names, int numNames, + const char **newNames, int *numNewNames) { + const char * const *endNames; + const char *prevName; + int newNum; + + if (numNames == 0) { + *numNewNames = 0; + return; + } + + endNames = names + numNames; + prevName = *names; + *newNames = *names; + newNames++; + names++; + newNum = 1; + while (names < endNames) { + if (strcmp(prevName, *names) != 0) { + *newNames = *names; + newNum++; + prevName = *names; + newNames++; + } + names++; + } + *numNewNames = newNum; +} + +static uio_DirList * +uio_getDirListMulti(uio_PDirHandle **pDirHandles, + int numPDirHandles, const char *pattern, match_MatchType matchType) { + int pDirI; // physical dir iterator + uio_DirBufferLink **links; // array of bufferLinks for each physical dir + uio_DirBufferLink *linkPtr; + int *numNames; // number of entries in each physical dir + int totalNumNames; + const char **bigNameBuffer; // buffer where all names will end up together + const char **destPtr; + uio_DirList *result; + match_Result matchResult; + match_MatchContext *matchContext; + + matchResult = match_prepareContext(pattern, &matchContext, matchType); + if (matchResult != match_OK) { +#ifdef DEBUG + fprintf(stderr, "Error compiling match function: %s.\n", + match_errorString(matchContext, matchResult)); +#endif + match_freeContext(matchContext); + errno = EIO; + // I actually want to signal an internal error. + // EIO comes closes + return NULL; + } + + // first get the directory listings for all seperate relevant dirs. + totalNumNames = 0; + links = uio_malloc(numPDirHandles * sizeof (uio_DirBufferLink *)); + numNames = uio_malloc(numPDirHandles * sizeof (int)); + for (pDirI = 0; pDirI < numPDirHandles; pDirI++) { + uio_collectDirEntries(pDirHandles[pDirI], &links[pDirI], + &numNames[pDirI]); + totalNumNames += numNames[pDirI]; + } + + bigNameBuffer = uio_malloc(totalNumNames * sizeof (uio_DirBufferLink *)); + + // Fill the bigNameBuffer with all the names from all the DirBufferLinks + // of all the physical dirs. + destPtr = bigNameBuffer; + totalNumNames = 0; + for (pDirI = 0; pDirI < numPDirHandles; pDirI++) { + for (linkPtr = links[pDirI]; linkPtr != NULL; + linkPtr = linkPtr->next) { + int numNewNames; + uio_filterNames((const char * const *) linkPtr->buffer, + linkPtr->numEntries, destPtr, + &numNewNames, matchContext); + totalNumNames += numNewNames; + destPtr += numNewNames; + } + } + + match_freeContext(matchContext); + + // Sort the bigNameBuffer + // Necessary for removing doubles. + // Not really necessary if the big list was the result of only one + // physical dir, but let's output a sorted list anyhow. + qsort((void *) bigNameBuffer, totalNumNames, sizeof (char *), + (int (*)(const void *, const void *)) strPtrCmp); + + // remove doubles + // (unnecessary if the big list was the result of only one physical dir) + if (numPDirHandles > 1) { + uio_filterDoubleNames(bigNameBuffer, totalNumNames, + bigNameBuffer, &totalNumNames); + } + + // resize the bigNameBuffer + bigNameBuffer = uio_realloc((void *) bigNameBuffer, + totalNumNames * sizeof (char *)); + + // put the lot in a DirList, copying the strings themselves + result = uio_makeDirList(bigNameBuffer, bigNameBuffer, + totalNumNames); + + // free the old junk + for (pDirI = 0; pDirI < numPDirHandles; pDirI++) + uio_freeDirBufferChain(links[pDirI]); + uio_free(links); + uio_free(numNames); + + return result; +} + +// 'buffer' and 'names' may be the same dir +// 'names' contains an array of 'numNames' pointers. +// 'newNames', if non-NULL, will be used as the array of new pointers +// (to a copy of the strings) in the DirList. +static uio_DirList * +uio_makeDirList(const char **newNames, const char * const *names, + int numNames) { + int i; + size_t len, totLen; + char *bufPtr; + uio_DirList *result; + + if (newNames == NULL) + newNames = uio_malloc(numNames * sizeof (char *)); + + totLen = 0; + for (i = 0; i < numNames; i++) + totLen += strlen(names[i]); + totLen += numNames; + // for the \0's + + result = uio_newDirList(newNames, numNames, uio_malloc(totLen)); + + bufPtr = result->buffer; + for (i = 0; i < numNames; i++) { + len = strlen(names[i]) + 1; + memcpy(bufPtr, names[i], len); + newNames[i] = bufPtr; + bufPtr += len; + } + return result; +} + +static void +uio_collectDirEntries(uio_PDirHandle *pDirHandle, uio_DirBufferLink **linkPtr, + int *numEntries) { + uio_EntriesContext *entriesContext; + uio_DirBufferLink **linkEndPtr; // where to attach the next link + int numRead; + int totalEntries; + char *buffer; + + entriesContext = uio_openEntriesPhysical(pDirHandle); + if (entriesContext == NULL) { +#ifdef DEBUG + fprintf(stderr, "Error: uio_openEntriesPhysical() failed: %s\n", + strerror(errno)); +#endif + *linkPtr = NULL; + *numEntries = 0; + return; + } + linkEndPtr = linkPtr; + totalEntries = 0; + while (1) { + *linkEndPtr = uio_malloc(sizeof (uio_DirBufferLink)); + buffer = uio_malloc(uio_DIR_BUFFER_SIZE); + (*linkEndPtr)->buffer = buffer; + numRead = uio_readEntriesPhysical(entriesContext, buffer, + uio_DIR_BUFFER_SIZE); + if (numRead == 0) { + fprintf(stderr, "Warning: uio_DIR_BUFFER_SIZE is too small to " + "hold a certain large entry on its own!\n"); + uio_freeDirBufferLink(*linkEndPtr); + break; + } + totalEntries += numRead; + (*linkEndPtr)->numEntries = numRead; + if (((char **) buffer)[numRead - 1] == NULL) { + // The entry being NULL means this is the last buffer + // Decrement the amount of queries to get the real number. + (*linkEndPtr)->numEntries--; + totalEntries--; + linkEndPtr = &(*linkEndPtr)->next; + break; + } + linkEndPtr = &(*linkEndPtr)->next; + } + *linkEndPtr = NULL; + uio_closeEntriesPhysical(entriesContext); + *numEntries = totalEntries; +} + +static void +uio_filterNames(const char * const *names, int numNames, + const char **newNames, int *numNewNames, + match_MatchContext *matchContext) { + int newNum; + const char * const *namesEnd; + match_Result matchResult; + + newNum = 0; + namesEnd = names + numNames; + while (names < namesEnd) { + matchResult = match_matchPattern(matchContext, *names); + if (matchResult == match_MATCH) { + *newNames = *names; + newNames++; + newNum++; + } else if (matchResult != match_NOMATCH) { + fprintf(stderr, "Error trying to match pattern: %s.\n", + match_errorString(matchContext, matchResult)); + } + names++; + } + *numNewNames = newNum; +} + +static int +strPtrCmp(const char * const *ptr1, const char * const *ptr2) { + return strcmp(*ptr1, *ptr2); +} + +static uio_EntriesContext * +uio_openEntriesPhysical(uio_PDirHandle *dirHandle) { + uio_NativeEntriesContext *native; + uio_PRoot *pRoot; + + pRoot = dirHandle->pRoot; + + assert(pRoot->handler->openEntries != NULL); + native = pRoot->handler->openEntries(dirHandle); + if (native == NULL) + return NULL; + uio_PRoot_refHandle(pRoot); + return uio_EntriesContext_new(pRoot, native); +} + +static int +uio_readEntriesPhysical(uio_EntriesContext *iterator, char *buf, size_t len) { + assert(iterator->pRoot->handler->readEntries != NULL); + return iterator->pRoot->handler->readEntries(&iterator->native, buf, len); +} + +static void +uio_closeEntriesPhysical(uio_EntriesContext *iterator) { + assert(iterator->pRoot->handler->closeEntries != NULL); + iterator->pRoot->handler->closeEntries(iterator->native); + uio_PRoot_unrefHandle(iterator->pRoot); + uio_EntriesContext_delete(iterator); +} + +static uio_EntriesContext * +uio_EntriesContext_new(uio_PRoot *pRoot, uio_NativeEntriesContext *native) { + uio_EntriesContext *result; + result = uio_EntriesContext_alloc(); + result->pRoot = pRoot; + result->native = native; + return result; +} + +static inline uio_EntriesContext * +uio_EntriesContext_alloc(void) { + return uio_malloc(sizeof (uio_EntriesContext)); +} + +static inline void +uio_EntriesContext_delete(uio_EntriesContext *entriesContext) { + uio_EntriesContext_free(entriesContext); +} + +static inline void +uio_EntriesContext_free(uio_EntriesContext *entriesContext) { + uio_free(entriesContext); +} + +static void +uio_freeDirBufferLink(uio_DirBufferLink *dirBufferLink) { + uio_free(dirBufferLink->buffer); + uio_free(dirBufferLink); +} + +static void +uio_freeDirBufferChain(uio_DirBufferLink *dirBufferLink) { + uio_DirBufferLink *next; + + while (dirBufferLink != NULL) { + next = dirBufferLink->next; + uio_freeDirBufferLink(dirBufferLink); + dirBufferLink = next; + } +} + +static uio_DirList * +uio_newDirList(const char **names, int numNames, char *buffer) { + uio_DirList *result; + + result = uio_allocDirList(); + result->names = names; + result->numNames = numNames; + result->buffer = buffer; + return result; +} + +static uio_DirList * +uio_allocDirList(void) { + return uio_malloc(sizeof (uio_DirList)); +} + +void +uio_freeDirList(uio_DirList *dirList) { + if (dirList->buffer) + uio_free(dirList->buffer); + if (dirList->names) + uio_free((void *) dirList->names); + uio_free(dirList); +} + +// *** end DirList stuff *** // + + +// *** PDirEntryHandle stuff *** // + +uio_PDirEntryHandle * +uio_getPDirEntryHandle(const uio_PDirHandle *dirHandle, + const char *name) { + assert(dirHandle->pRoot->handler != NULL); + return dirHandle->pRoot->handler->getPDirEntryHandle(dirHandle, name); +} + +void +uio_PDirHandle_deletePDirHandleExtra(uio_PDirHandle *pDirHandle) { + if (pDirHandle->extra == NULL) + return; + assert(pDirHandle->pRoot->handler->deletePDirHandleExtra != NULL); + pDirHandle->pRoot->handler->deletePDirHandleExtra(pDirHandle->extra); +} + +void +uio_PFileHandle_deletePFileHandleExtra(uio_PFileHandle *pFileHandle) { + if (pFileHandle->extra == NULL) + return; + assert(pFileHandle->pRoot->handler->deletePFileHandleExtra != NULL); + pFileHandle->pRoot->handler->deletePFileHandleExtra(pFileHandle->extra); +} + +uio_PDirHandle * +uio_PDirHandle_new(uio_PRoot *pRoot, uio_PDirHandleExtra extra) { + uio_PDirHandle *result; + + result = uio_PDirHandle_alloc(); + result->flags = uio_PDirEntryHandle_TYPE_DIR; + result->ref = 1; + result->pRoot = pRoot; + result->extra = extra; + return result; +} + +void +uio_PDirEntryHandle_delete(uio_PDirEntryHandle *pDirEntryHandle) { + if (uio_PDirEntryHandle_isDir(pDirEntryHandle)) { + uio_PDirHandle_delete((uio_PDirHandle *) pDirEntryHandle); + } else { + uio_PFileHandle_delete((uio_PFileHandle *) pDirEntryHandle); + } +} + +void +uio_PDirHandle_delete(uio_PDirHandle *pDirHandle) { + uio_PDirHandle_deletePDirHandleExtra(pDirHandle); + uio_PDirHandle_free(pDirHandle); +} + +static inline uio_PDirHandle * +uio_PDirHandle_alloc(void) { + uio_PDirHandle *result = uio_malloc(sizeof (uio_PDirHandle)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(uio_PDirHandle, (void *) result); +#endif + return result; +} + +static inline void +uio_PDirHandle_free(uio_PDirHandle *pDirHandle) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(uio_PDirHandle, (void *) pDirHandle); +#endif + uio_free(pDirHandle); +} + +uio_PFileHandle * +uio_PFileHandle_new(uio_PRoot *pRoot, uio_PFileHandleExtra extra) { + uio_PFileHandle *result; + + result = uio_PFileHandle_alloc(); + result->flags = uio_PDirEntryHandle_TYPE_REG; + result->ref = 1; + result->pRoot = pRoot; + result->extra = extra; + return result; +} + +void +uio_PFileHandle_delete(uio_PFileHandle *pFileHandle) { + uio_PFileHandle_deletePFileHandleExtra(pFileHandle); + uio_PFileHandle_free(pFileHandle); +} + +static inline uio_PFileHandle * +uio_PFileHandle_alloc(void) { + uio_PFileHandle *result = uio_malloc(sizeof (uio_PFileHandle)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(uio_PFileHandle, (void *) result); +#endif + return result; +} + +static inline void +uio_PFileHandle_free(uio_PFileHandle *pFileHandle) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(uio_PFileHandle, (void *) pFileHandle); +#endif + uio_free(pFileHandle); +} + +// *** PDirEntryHandle stuff *** // + + +// ref count set to 1 +uio_Handle * +uio_Handle_new(uio_PRoot *root, uio_NativeHandle native, int openFlags) { + uio_Handle *handle; + + handle = uio_Handle_alloc(); + handle->ref = 1; + uio_PRoot_refHandle(root); + handle->root = root; + handle->native = native; + handle->openFlags = openFlags; + return handle; +} + +void +uio_Handle_delete(uio_Handle *handle) { + handle->root->handler->close(handle); + uio_PRoot_unrefHandle(handle->root); + uio_Handle_free(handle); +} + +static inline uio_Handle * +uio_Handle_alloc(void) { + uio_Handle *result = uio_malloc(sizeof (uio_Handle)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(uio_Handle, (void *) result); +#endif + return result; +} + +static inline void +uio_Handle_free(uio_Handle *handle) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(uio_Handle, (void *) handle); +#endif + uio_free(handle); +} + +static uio_DirHandle * +uio_newDirHandle(uio_Repository *repository, char *path, char *rootEnd) { + uio_DirHandle *result; + + result = uio_allocDirHandle(); + result->repository = repository; + result->path = path; + result->rootEnd = rootEnd; + return result; +} + +static inline uio_DirHandle * +uio_allocDirHandle(void) { + uio_DirHandle *result = uio_malloc(sizeof (uio_DirHandle)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(uio_DirHandle, (void *) result); +#endif + return result; +} + +static inline void +uio_DirHandle_free(uio_DirHandle *dirHandle) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(uio_DirHandle, (void *) dirHandle); +#endif + uio_free(dirHandle); +} + +void +uio_DirHandle_print(const uio_DirHandle *dirHandle, FILE *out) { + fprintf(out, "["); + fwrite(dirHandle->path, dirHandle->path - dirHandle->rootEnd, 1, out); + fprintf(out, "]%s", dirHandle->rootEnd); +} + +static uio_MountHandle * +uio_MountHandle_new(uio_Repository *repository, uio_MountInfo *mountInfo) { + uio_MountHandle *result; + + result = uio_MountHandle_alloc(); + result->repository = repository; + result->mountInfo = mountInfo; + return result; +} + +static inline void +uio_MountHandle_delete(uio_MountHandle *mountHandle) { + uio_MountHandle_free(mountHandle); +} + +static inline uio_MountHandle * +uio_MountHandle_alloc(void) { + uio_MountHandle *result = uio_malloc(sizeof (uio_MountHandle)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(uio_MountHandle, (void *) result); +#endif + return result; +} + +static inline void +uio_MountHandle_free(uio_MountHandle *mountHandle) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(uio_MountHandle, (void *) mountHandle); +#endif + uio_free(mountHandle); +} + + + diff --git a/sc2/src/sc2code/libs/uio/io.h b/sc2/src/sc2code/libs/uio/io.h new file mode 100644 index 000000000..5d4b93af7 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/io.h @@ -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 +#include + +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 */ + diff --git a/sc2/src/sc2code/libs/uio/ioaux.c b/sc2/src/sc2code/libs/uio/ioaux.c new file mode 100644 index 000000000..762aa0881 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/ioaux.c @@ -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 +#include + +#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; +} + + diff --git a/sc2/src/sc2code/libs/uio/ioaux.h b/sc2/src/sc2code/libs/uio/ioaux.h new file mode 100644 index 000000000..68093631a --- /dev/null +++ b/sc2/src/sc2code/libs/uio/ioaux.h @@ -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 */ + diff --git a/sc2/src/sc2code/libs/uio/iointrn.h b/sc2/src/sc2code/libs/uio/iointrn.h new file mode 100644 index 000000000..83c52fa41 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/iointrn.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _IOINTERN_H +#define _IOINTERN_H + +#define uio_INTERNAL + +typedef struct uio_PDirEntryHandle uio_PDirEntryHandle; +typedef struct uio_PDirHandle uio_PDirHandle; +typedef struct uio_PFileHandle uio_PFileHandle; +typedef struct uio_EntriesContext uio_EntriesContext; + +#ifndef uio_INTERNAL_PHYSICAL +typedef void *uio_PDirHandleExtra; +typedef void *uio_PFileHandleExtra; +#endif + +#include "io.h" +#include "uioport.h" +#include "physical.h" +#include "mount.h" +#include "mounttree.h" +#include "match.h" +#include "mem.h" + +struct uio_Handle { + int ref; + struct uio_PRoot *root; + uio_NativeHandle native; + int openFlags; + // need to know whether the handle is a RO or RW handle. +}; + +struct uio_DirHandle { + struct uio_Repository *repository; + char *path; + // does not contain any '.' or '..' + char *rootEnd; + // points to the end of the part of path that is considered + // the root dir. (you can't use '..' to get above the root dir) +}; + +struct uio_MountHandle { + struct uio_Repository *repository; + struct uio_MountInfo *mountInfo; +}; + +struct uio_DirList { + const char **names; + int numNames; + char *buffer; +}; + + +#define uio_PHandle_COMMON \ + int flags; \ + int ref; \ + uio_PRoot *pRoot; + +#define uio_PDirEntryHandle_TYPE_REG 0x0000 +#define uio_PDirEntryHandle_TYPE_DIR 0x0001 +#define uio_PDirEntryHandle_TYPEMASK 0x0001 + +struct uio_PDirEntryHandle { + uio_PHandle_COMMON +}; + +struct uio_PDirHandle { + uio_PHandle_COMMON + uio_PDirHandleExtra extra; +}; + +struct uio_PFileHandle { + uio_PHandle_COMMON + uio_PFileHandleExtra extra; +}; + +struct uio_EntriesContext { + uio_PRoot *pRoot; + uio_NativeEntriesContext native; +}; + + +uio_Handle *uio_Handle_new(uio_PRoot *root, uio_NativeHandle native, + int openFlags); +void uio_Handle_delete(uio_Handle *handle); + +uio_PDirEntryHandle *uio_getPDirEntryHandle( + const uio_PDirHandle *dirHandle, const char *name); +void uio_PDirHandle_deletePDirHandleExtra(uio_PDirHandle *pDirHandle); +void uio_PFileHandle_deletePFileHandleExtra(uio_PFileHandle *pFileHandle); + +uio_PDirHandle *uio_PDirHandle_new(uio_PRoot *pRoot, + uio_PDirHandleExtra extra); +uio_PFileHandle *uio_PFileHandle_new(uio_PRoot *pRoot, + uio_PFileHandleExtra extra); +void uio_PDirEntryHandle_delete(uio_PDirEntryHandle *pDirEntryHandle); +void uio_PDirHandle_delete(uio_PDirHandle *pDirHandle); +void uio_PFileHandle_delete(uio_PFileHandle *pFileHandle); + + +static inline void +uio_Handle_ref(uio_Handle *handle) { + handle->ref++; +} + +static inline void +uio_Handle_unref(uio_Handle *handle) { + assert(handle->ref > 0); + handle->ref--; + if (handle->ref == 0) + uio_Handle_delete(handle); +} + +static inline uio_bool +uio_PDirEntryHandle_isDir(const uio_PDirEntryHandle *handle) { + return (handle->flags & uio_PDirEntryHandle_TYPEMASK) == + uio_PDirEntryHandle_TYPE_DIR; +} + +static inline void +uio_PDirEntryHandle_ref(uio_PDirEntryHandle *handle) { + handle->ref++; +} + +static inline void +uio_PDirEntryHandle_unref(uio_PDirEntryHandle *handle) { + assert(handle->ref > 0); + handle->ref--; + if (handle->ref == 0) + uio_PDirEntryHandle_delete(handle); +} + +static inline void +uio_PDirHandle_ref(uio_PDirHandle *handle) { + handle->ref++; +} + +static inline void +uio_PDirHandle_unref(uio_PDirHandle *handle) { + assert(handle->ref > 0); + handle->ref--; + if (handle->ref == 0) + uio_PDirHandle_delete(handle); +} + +static inline void +uio_PFileHandle_ref(uio_PFileHandle *handle) { + handle->ref++; +} + +static inline void +uio_PFileHandle_unref(uio_PFileHandle *handle) { + assert(handle->ref > 0); + handle->ref--; + if (handle->ref == 0) + uio_PFileHandle_delete(handle); +} + + +#endif /* _IOINTERN_H */ + + diff --git a/sc2/src/sc2code/libs/uio/match.c b/sc2/src/sc2code/libs/uio/match.c new file mode 100644 index 000000000..8d18bc2a4 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/match.c @@ -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 +#ifdef DEBUG +# include +#endif + +#include "iointrn.h" +#include "match.h" +#include "mem.h" +#include "uioport.h" + +#ifdef HAVE_GLOB +# include +#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 */ + diff --git a/sc2/src/sc2code/libs/uio/match.h b/sc2/src/sc2code/libs/uio/match.h new file mode 100644 index 000000000..c60097474 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/match.h @@ -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 + +// 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 +#ifdef HAVE_REGEX +# include +#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 */ + diff --git a/sc2/src/sc2code/libs/uio/mem.h b/sc2/src/sc2code/libs/uio/mem.h new file mode 100644 index 000000000..887de1669 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/mem.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _MEM_H +#define _MEM_H + +#include +#include +#ifdef WIN32 +# include +# define alloca _alloca +#elif defined (__linux__) +# include +#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 + + diff --git a/sc2/src/sc2code/libs/uio/memdebug.c b/sc2/src/sc2code/libs/uio/memdebug.c new file mode 100644 index 000000000..c908bc0cc --- /dev/null +++ b/sc2/src/sc2code/libs/uio/memdebug.c @@ -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 +#include + +#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); +} + diff --git a/sc2/src/sc2code/libs/uio/memdebug.h b/sc2/src/sc2code/libs/uio/memdebug.h new file mode 100644 index 000000000..11c980b93 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/memdebug.h @@ -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 +#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 */ + diff --git a/sc2/src/sc2code/libs/uio/mount.c b/sc2/src/sc2code/libs/uio/mount.c new file mode 100644 index 000000000..ac1d78f98 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/mount.c @@ -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 +#include + +#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); +} + + diff --git a/sc2/src/sc2code/libs/uio/mount.h b/sc2/src/sc2code/libs/uio/mount.h new file mode 100644 index 000000000..f754529d3 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/mount.h @@ -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 */ + diff --git a/sc2/src/sc2code/libs/uio/mounttree.c b/sc2/src/sc2code/libs/uio/mounttree.c new file mode 100644 index 000000000..fdef5a6f9 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/mounttree.c @@ -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 +#include +#ifdef DEBUG +# include +#endif +#include + +#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); +} + + diff --git a/sc2/src/sc2code/libs/uio/mounttree.h b/sc2/src/sc2code/libs/uio/mounttree.h new file mode 100644 index 000000000..3b045f35c --- /dev/null +++ b/sc2/src/sc2code/libs/uio/mounttree.h @@ -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 +#include "mount.h" + +void uio_printMounts(FILE *outStream, const uio_Repository *repository); + +/* *** Internal definitions follow *** */ +#ifdef uio_INTERNAL + +#include + +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 */ + diff --git a/sc2/src/sc2code/libs/uio/paths.c b/sc2/src/sc2code/libs/uio/paths.c new file mode 100644 index 000000000..0b4dd9521 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/paths.c @@ -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 +#include +#include + +#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; +} + + diff --git a/sc2/src/sc2code/libs/uio/paths.h b/sc2/src/sc2code/libs/uio/paths.h new file mode 100644 index 000000000..aa65dec08 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/paths.h @@ -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 */ + diff --git a/sc2/src/sc2code/libs/uio/physical.c b/sc2/src/sc2code/libs/uio/physical.c new file mode 100644 index 000000000..3e09d4d84 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/physical.c @@ -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 +#include +#include +#include +#include + +#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); +} + + diff --git a/sc2/src/sc2code/libs/uio/physical.h b/sc2/src/sc2code/libs/uio/physical.h new file mode 100644 index 000000000..3de3b0a33 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/physical.h @@ -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 */ + + diff --git a/sc2/src/sc2code/libs/uio/stdio/Makeinfo b/sc2/src/sc2code/libs/uio/stdio/Makeinfo new file mode 100644 index 000000000..a41976f9b --- /dev/null +++ b/sc2/src/sc2code/libs/uio/stdio/Makeinfo @@ -0,0 +1,3 @@ +uqm_CFILES="stdio.c" + + diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.c b/sc2/src/sc2code/libs/uio/stdio/stdio.c new file mode 100644 index 000000000..06789f0d4 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.c @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "./stdio.h" + +#ifdef WIN32 +# include +#else +# include +# include +# define _POSIX_THREAD_SAFEFUNCTIONS + // for readdir_r +# include +#endif +#include +#include +#include +#include +#include +#include + +#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); +} + + diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.h b/sc2/src/sc2code/libs/uio/stdio/stdio.h new file mode 100644 index 000000000..b231c5c7e --- /dev/null +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.h @@ -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 +#ifndef WIN32 +# include +#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); + + + diff --git a/sc2/src/sc2code/libs/uio/types.h b/sc2/src/sc2code/libs/uio/types.h new file mode 100644 index 000000000..a30cad9e2 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/types.h @@ -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 */ + + diff --git a/sc2/src/sc2code/libs/uio/uioport.h b/sc2/src/sc2code/libs/uio/uioport.h new file mode 100644 index 000000000..f100c21ce --- /dev/null +++ b/sc2/src/sc2code/libs/uio/uioport.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _UIOPORT_H +#define _UIOPORT_H + +#ifdef WIN32 +# include +# 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 + /* PATH_MAX is per POSIX defined in */ +# define inline __inline__ +#endif +#ifdef _MSC_VER +# include +#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 +#undef mkdir +# include +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 +#endif + + +#endif /* _UIOPORT_H */ + diff --git a/sc2/src/sc2code/libs/uio/uiostream.c b/sc2/src/sc2code/libs/uio/uiostream.c new file mode 100644 index 000000000..2b69e166c --- /dev/null +++ b/sc2/src/sc2code/libs/uio/uiostream.c @@ -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 +#include + +#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); +} + diff --git a/sc2/src/sc2code/libs/uio/uiostream.h b/sc2/src/sc2code/libs/uio/uiostream.h new file mode 100644 index 000000000..11ffecfa1 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/uiostream.h @@ -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 +#include +#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 */ + + diff --git a/sc2/src/sc2code/libs/uio/uioutils.c b/sc2/src/sc2code/libs/uio/uioutils.c new file mode 100644 index 000000000..a8233d64a --- /dev/null +++ b/sc2/src/sc2code/libs/uio/uioutils.c @@ -0,0 +1,200 @@ +/* + * 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 +#include + +#include "uioutils.h" +#include "mem.h" +#include "uioport.h" + +// concattenate two strings into a newly allocated buffer. +// It's up to the caller to free it. +char * +strcata(const char *first, const char *second) { + char *result, *resPtr; + size_t firstLen, secondLen; + + firstLen = strlen(first); + secondLen = strlen(second); + result = uio_malloc(firstLen + secondLen + 1); + resPtr = result; + + memcpy(resPtr, first, firstLen); + resPtr += firstLen; + + memcpy(resPtr, second, secondLen); + resPtr += secondLen; + + *resPtr = '\0'; + return result; +} + +// returns a copy of a generic array 'array' with 'element' inserted in +// position 'insertPos' +void * +insertArray(const void *array, size_t oldNumElements, int insertPos, + const void *element, size_t elementSize) { + void *newArray, *newArrayPtr; + const void *arrayPtr; + size_t preInsertSize; + + newArray = uio_malloc((oldNumElements + 1) * elementSize); + preInsertSize = insertPos * elementSize; + memcpy(newArray, array, preInsertSize); + newArrayPtr = (char *) newArray + preInsertSize; + arrayPtr = (const char *) array + preInsertSize; + memcpy(newArrayPtr, element, elementSize); + newArrayPtr = (char *) newArrayPtr + elementSize; + memcpy(newArrayPtr, arrayPtr, + (oldNumElements - insertPos) * elementSize); + return newArray; +} + +// returns a copy of a pointer array 'array' with 'element' inserted in +// position 'insertPos' +void ** +insertArrayPointer(const void **array, size_t oldNumElements, int insertPos, + const void *element) { + void **newArray, **newArrayPtr; + const void **arrayPtr; + size_t preInsertSize; + + newArray = uio_malloc((oldNumElements + 1) * sizeof (void *)); + preInsertSize = insertPos * sizeof (void *); + memcpy(newArray, array, preInsertSize); + newArrayPtr = newArray + insertPos; + arrayPtr = array + insertPos; + *newArrayPtr = unconst(element); + newArrayPtr++; + memcpy(newArrayPtr, arrayPtr, + (oldNumElements - insertPos) * sizeof (void *)); + return newArray; +} + +// returns a copy of a generic array 'array' with 'numExclude' elements, +// starting from startpos, removed. +void * +excludeArray(const void *array, size_t oldNumElements, int startPos, + int numExclude, size_t elementSize) { + void *newArray, *newArrayPtr; + const void *arrayPtr; + size_t preExcludeSize; + + newArray = uio_malloc((oldNumElements - numExclude) * elementSize); + preExcludeSize = startPos * elementSize; + memcpy(newArray, array, preExcludeSize); + newArrayPtr = (char *) newArray + preExcludeSize; + arrayPtr = (const char *) array + + (startPos + numExclude) * sizeof (elementSize); + memcpy(newArrayPtr, arrayPtr, + (oldNumElements - startPos - numExclude) * elementSize); + return newArray; +} + +// returns a copy of a pointer array 'array' with 'numExclude' elements, +// starting from startpos, removed. +void ** +excludeArrayPointer(const void **array, size_t oldNumElements, int startPos, + int numExclude) { + void **newArray; + + newArray = uio_malloc((oldNumElements - numExclude) * sizeof (void *)); + memcpy(newArray, array, startPos * sizeof (void *)); + memcpy(&newArray[startPos], &array[startPos + numExclude], + (oldNumElements - startPos - numExclude) * sizeof (void *)); + return newArray; +} + +// If the given DOS date/time is invalid, the result is unspecified, +// but the function won't crash. +time_t +dosToUnixTime(uio_uint16 date, uio_uint16 tm) { + // DOS date has the following format: + // bits 0-4 specify the number of the day in the month (1-31). + // bits 5-8 specify the number of the month in the year (1-12). + // bits 9-15 specify the year number since 1980 (0-127) + // DOS time has the fillowing format: + // bits 0-4 specify the number of seconds/2 in the minute (0-29) + // (only accurate on 2 seconds) + // bits 5-10 specify the number of minutes in the hour (0-59) + // bits 11-15 specify the number of hours since midnight (0-23) + + int year, month, day; + int hours, minutes, seconds; + long result; + + static const int daysUntilMonth[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, + 334, 334, 334, 334 }; + // Last 4 entries are there so that there's no + // invalid memory access if the date is invalid. + + year = date >> 9; + month = ((date >> 5) - 1) & 0x0f; // Number in [0..15] + day = (date - 1) & 0x1f; // Number in [0..31] + hours = tm >> 11; + minutes = (tm >> 5) & 0x3f; + seconds = (tm & 0x1f) * 2; // Even number in [0..62] + + result = year * 365 + daysUntilMonth[month] + day; + // Count the (non-leap) days in all those years + + // Add a leapday for each 4th year + if (year % 4 == 0 && month <= 2) { + // The given date is a leap-year but the leapday hasn't occured yet. + result += year / 4; + } else { + result += 1 + year / 4; + } + // result now is the number of days between 1980-01-01 and the given day. + + // Add the days between 1970-01-01 and 1980-01-01 + // (2 leapdays in this period) + result += 365 * 10 + 2; + + result = (result * 24) + hours; // days to hours + result = (result * 60) + minutes; // hours to minutes + result = (result * 60) + seconds; // minutes to seconds + + return (time_t) result; +} + +char * +dosToUnixPath(const char *path) { + const char *srcPtr; + char *result, *dstPtr; + + result = uio_malloc(strlen(path) + 1); + srcPtr = path; + dstPtr = result; + while (*srcPtr != '\0') { + if (*srcPtr == '\\') { + *dstPtr = '/'; + } else + *dstPtr = *srcPtr; + srcPtr++; + dstPtr++; + } + *dstPtr = '\0'; + return result; +} + + diff --git a/sc2/src/sc2code/libs/uio/uioutils.h b/sc2/src/sc2code/libs/uio/uioutils.h new file mode 100644 index 000000000..54b4abb3c --- /dev/null +++ b/sc2/src/sc2code/libs/uio/uioutils.h @@ -0,0 +1,92 @@ +/* + * 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 _UTILS_H +#define _UTILS_H + +#include + +#include "types.h" +#include "uioport.h" + +char *strcata(const char *first, const char *second); +void *insertArray(const void *array, size_t oldNumElements, int insertPos, + const void *element, size_t elementSize); +void **insertArrayPointer(const void **array, size_t oldNumElements, + int insertPos, const void *element); +void *excludeArray(const void *array, size_t oldNumElements, int startPos, + int numExclude, size_t elementSize); +void **excludeArrayPointer(const void **array, size_t oldNumElements, + int startPos, int numExclude); +time_t dosToUnixTime(uio_uint16 date, uio_uint16 tm); +char *dosToUnixPath(const char *path); + +/* Sometimes you just have to remove a 'const'. + * (for instance, when implementing a function like strchr) + */ +static inline void * +unconst(const void *arg) { + union { + char *c; + const char *cc; + } u; + u.cc = arg; + return u.c; +} + +// byte1 is the lowest byte, byte4 the highest +static inline uio_uint32 +makeUInt32(uio_uint8 byte1, uio_uint8 byte2, uio_uint8 byte3, uio_uint8 byte4) { + return byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24); +} + +static inline uio_uint16 +makeUInt16(uio_uint8 byte1, uio_uint8 byte2) { + return byte1 | (byte2 << 8); +} + +static inline uio_sint32 +makeSInt32(uio_uint8 byte1, uio_uint8 byte2, uio_uint8 byte3, uio_uint8 byte4) { + return byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24); +} + +static inline uio_sint16 +makeSInt16(uio_uint8 byte1, uio_uint8 byte2) { + return byte1 | (byte2 << 8); +} + +static inline uio_bool +isBitSet(uio_uint32 bitField, int bit) { + return ((bitField >> bit) & 1) == 1; +} + +static inline int +mins(int i1, int i2) { + return i1 <= i2 ? i1 : i2; +} + +static inline unsigned int +minu(unsigned int i1, unsigned int i2) { + return i1 <= i2 ? i1 : i2; +} + + +#endif + diff --git a/sc2/src/sc2code/libs/uio/zip/Makeinfo b/sc2/src/sc2code/libs/uio/zip/Makeinfo new file mode 100644 index 000000000..ab1778015 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/zip/Makeinfo @@ -0,0 +1,3 @@ +uqm_CFILES="zip.c" + + diff --git a/sc2/src/sc2code/libs/uio/zip/zip.c b/sc2/src/sc2code/libs/uio/zip/zip.c new file mode 100644 index 000000000..a89dec01c --- /dev/null +++ b/sc2/src/sc2code/libs/uio/zip/zip.c @@ -0,0 +1,1360 @@ +/* + * 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 + * + */ + +/* + * This file makes use of zlib (http://www.gzip.org/zlib/) + * + * References: + * The .zip format description from PKWare: + * http://www.pkware.com/products/enterprise/white_papers/appnote.html + * The .zip format description from InfoZip: + * ftp://ftp.info-zip.org/pub/infozip/doc/appnote-011203-iz.zip + */ + +#include +#include +#include +#include + +#include "zip.h" +#include "../physical.h" +#include "../uioport.h" +#include "../paths.h" +#include "../uioutils.h" +#ifdef uio_MEM_DEBUG +# include "../memdebug.h" +#endif + + +static int zip_badFile(zip_GPFileData *gPFileData, char *fileName); +static int zip_fillDirStructure(uio_GPDir *top, uio_Handle *handle); +#if zip_USE_HEADERS == zip_USE_LOCAL_HEADERS +static int zip_fillDirStructureLocal(uio_GPDir *top, uio_Handle *handle); +static int zip_fillDirStructureLocalProcessFile(uio_GPDir *topGPDir, + uio_FileBlock *fileBlock, off_t *pos); +#endif +#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS +static off_t zip_findEndOfCentralDirectoryRecord(uio_Handle *handle, + uio_FileBlock *fileBlock); +static int zip_fillDirStructureCentral(uio_GPDir *top, uio_Handle *handle); +static int zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir, + uio_FileBlock *fileBlock, off_t *pos); +static int zip_updatePFileDataFromLocalFileHeader(zip_GPFileData *gPFileData, + uio_FileBlock *fileBlock, int pos); +#endif +static int zip_fillDirStructureProcessExtraFields( + uio_FileBlock *fileBlock, off_t extraFieldLength, + zip_GPFileData *gPFileData, const char *fileName, off_t pos); +static inline int zip_foundFile(uio_GPDir *gPDir, const char *fileName, + zip_GPFileData *gPFileData); +//static inline uio_GPDir *zip_foundDir(uio_GPDir *gPDir, const char *dirName); +static int zip_initZipStream(z_stream *zipStream); +static int zip_unInitZipStream(z_stream *zipStream); +static int zip_reInitZipStream(z_stream *zipStream); + +static voidpf zip_alloc(voidpf opaque, uInt items, uInt size); +static void zip_free(voidpf opaque, voidpf address); + +static inline zip_GPFileData * zip_GPFileData_new(void); +static inline void zip_GPFileData_delete(zip_GPFileData *gPFileData); +static inline zip_GPFileData *zip_GPFileData_alloc(void); +static inline void zip_GPFileData_free(zip_GPFileData *gPFileData); + +static ssize_t zip_readStored(uio_Handle *handle, void *buf, size_t count); +static ssize_t zip_readDeflated(uio_Handle *handle, void *buf, size_t count); +static off_t zip_seekStored(uio_Handle *handle, off_t offset); +static off_t zip_seekDeflated(uio_Handle *handle, off_t offset); + +uio_FileSystemHandler zip_fileSystemHandler = { + /* .init = */ NULL, + /* .unInit = */ NULL, + /* .cleanup = */ NULL, + + /* .mount = */ zip_mount, + /* .umount = */ uio_GPRoot_umount, + + /* .close = */ zip_close, + /* .fstat = */ zip_fstat, + /* .stat = */ zip_stat, + /* .mkdir = */ NULL, + /* .open = */ zip_open, + /* .read = */ zip_read, + /* .rmdir = */ NULL, + /* .seek = */ zip_seek, + /* .write = */ NULL, + /* .unlink = */ NULL, + + /* .openEntries = */ uio_GPDir_openEntries, + /* .readEntries = */ uio_GPDir_readEntries, + /* .closeEntries = */ uio_GPDir_closeEntries, + + /* .getPDirEntryHandle = */ uio_GPDir_getPDirEntryHandle, + /* .deletePRootExtra = */ uio_GPRoot_delete, + /* .deletePDirHandleExtra = */ uio_GPDirHandle_delete, + /* .deletePFileHandleExtra = */ uio_GPFileHandle_delete, +}; + +uio_GPRoot_Operations zip_GPRootOperations = { + /* .fillGPDir = */ NULL, + /* .deleteGPRootExtra = */ NULL, + /* .deleteGPDirExtra = */ NULL, + /* .deleteGPFileExtra = */ zip_GPFileData_delete, +}; + + +#define NUM_COMPRESSION_METHODS 11 +/* + * [0] = stored uncompressed + * [1] = Shrunk + * [2] = Reduced with compression factor 1 + * [3] = Reduced with compression factor 2 + * [4] = Reduced with compression factor 3 + * [5] = Reduced with compression factor 4 + * [6] = Imploded + * [7] = Reserved for Tokenizing + * [8] = Deflated + * [9] = Deflate64 + * [10] = "PKWARE Data Compression Library Imploding" + */ +static const uio_bool + zip_compressionMethodSupported[NUM_COMPRESSION_METHODS] = { + true, false, false, false, false, false, false, false, + true, false, false }; + +typedef ssize_t (*zip_readFunctionType)(uio_Handle *handle, + void *buf, size_t count); +zip_readFunctionType zip_readMethods[NUM_COMPRESSION_METHODS] = { + zip_readStored, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + zip_readDeflated, NULL, NULL +}; +typedef off_t (*zip_seekFunctionType)(uio_Handle *handle, off_t offset); +zip_seekFunctionType zip_seekMethods[NUM_COMPRESSION_METHODS] = { + zip_seekStored, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + zip_seekDeflated, NULL, NULL +}; + + +#define zip_INPUT_BUFFER_SIZE 0x10000 + // TODO: make this configurable a la sysctl? +#define zip_SEEK_BUFFER_SIZE zip_INPUT_BUFFER_SIZE + + +void +zip_close(uio_Handle *handle) { + zip_Handle *zip_handle; + +#if defined(DEBUG) && DEBUG > 1 + fprintf(stderr, "zip_close - handle=%p\n", (void *) handle); +#endif + zip_handle = handle->native; + uio_GPFile_unref(zip_handle->file); + zip_unInitZipStream(&zip_handle->zipStream); + uio_closeFileBlock(zip_handle->fileBlock); + uio_free(zip_handle); +} + +static void +zip_fillStat(struct stat *statBuf, const zip_GPFileData *gPFileData) { + memset(statBuf, '\0', sizeof (struct stat)); + statBuf->st_size = gPFileData->uncompressedSize; + statBuf->st_uid = gPFileData->uid; + statBuf->st_gid = gPFileData->gid; + statBuf->st_mode = gPFileData->mode; + statBuf->st_atime = gPFileData->atime; + statBuf->st_mtime = gPFileData->mtime; + statBuf->st_ctime = gPFileData->ctime; +} + +int +zip_fstat(uio_Handle *handle, struct stat *statBuf) { + zip_fillStat(statBuf, handle->native->file->extra); + return 0; +} + +int +zip_stat(uio_PDirHandle *pDirHandle, const char *name, struct stat *statBuf) { + uio_GPDirEntry *entry; + + entry = uio_GPDir_getGPDirEntry(pDirHandle->extra, name); + if (entry == NULL) { + errno = ENOENT; + return -1; + } + + if (uio_GPDirEntry_isDir(entry)) { + // No dir data is read from zip file. + // We'll have to make something up for the time being. + memset(statBuf, '\0', sizeof (struct stat)); + statBuf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | + S_IRGRP | S_IWGRP | S_IXOTH | + S_IROTH | S_IWOTH | S_IXOTH; + statBuf->st_uid = 0; + statBuf->st_gid = 0; + return 0; + } + + zip_fillStat(statBuf, ((uio_GPFile *) entry)->extra); + return 0; +} + +/* + * Function name: zip_open + * Description: open a file in zip file + * Arguments: pDirHandle - handle to the dir where to open the file + * name - the name of the file to open + * flags - flags, as to stdio open() + * mode - mode, as to stdio open() + * Returns: handle, as from stdio open() + * If failed, errno is set and handle is -1. + */ +uio_Handle * +zip_open(uio_PDirHandle *pDirHandle, const char *name, int flags, + mode_t mode) { + zip_Handle *handle; + uio_GPFile *gPFile; + +#if defined(DEBUG) && DEBUG > 1 + fprintf(stderr, "zip_open - pDirHandle=%p name=%s flags=%d mode=0%o\n", + (void *) pDirHandle, name, flags, mode); +#endif + + if ((flags & O_ACCMODE) != O_RDONLY) { + errno = EACCES; + return NULL; + } + + gPFile = (uio_GPFile *) uio_GPDir_getGPDirEntry(pDirHandle->extra, name); + if (gPFile == NULL) { + errno = ENOENT; + return NULL; + } + +#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS + if (gPFile->extra->fileOffset == -1) { + // the local header wasn't read in yet. + uio_FileBlock *fileBlock; + zip_GPFileData *gPFileData; + + fileBlock = uio_openFileBlock(pDirHandle->pRoot->handle); + if (fileBlock == NULL) { + // errno is set + return NULL; + } + gPFileData = gPFile->extra; + if (zip_updatePFileDataFromLocalFileHeader(gPFileData, + fileBlock, gPFile->extra->headerOffset) == -1) { + int saveErrno = errno; + uio_closeFileBlock(fileBlock); + errno = saveErrno; + return NULL; + } + if (gPFileData->ctime == (time_t) 0) + gPFileData->ctime = gPFileData->mtime; + if (gPFileData->atime == (time_t) 0) + gPFileData->atime = gPFileData->mtime; + uio_closeFileBlock(fileBlock); + } +#endif + + handle = uio_malloc(sizeof (zip_Handle)); + uio_GPFile_ref(gPFile); + handle->file = gPFile; + handle->fileBlock = uio_openFileBlock2(pDirHandle->pRoot->handle, + gPFile->extra->fileOffset, gPFile->extra->compressedSize); + if (handle->fileBlock == NULL) { + // errno is set + return NULL; + } + + if (zip_initZipStream(&handle->zipStream) == -1) { + uio_GPFile_unref(gPFile); + uio_closeFileBlock(handle->fileBlock); + return NULL; + } + handle->compressedOffset = 0; + handle->uncompressedOffset = 0; + + (void) mode; + return uio_Handle_new(pDirHandle->pRoot, handle, flags); +} + +ssize_t +zip_read(uio_Handle *handle, void *buf, size_t count) { + ssize_t result; + +#if defined(DEBUG) && DEBUG > 1 + fprintf(stderr, "zip_read - handle=%p buf=%p count=%d: ", (void *) handle, + (void *) buf, count); +#endif + result = zip_readMethods[handle->native->file->extra->compressionMethod] + (handle, buf, count); +#if defined(DEBUG) && DEBUG > 1 + fprintf(stderr, "%d\n", result); +#endif + return result; +} + +static ssize_t +zip_readStored(uio_Handle *handle, void *buf, size_t count) { + int numBytes; + zip_Handle *zipHandle; + + zipHandle = handle->native; + numBytes = uio_copyFileBlock(zipHandle->fileBlock, + zipHandle->uncompressedOffset, buf, count); + if (numBytes == -1) { + // errno is set + return -1; + } + zipHandle->uncompressedOffset += numBytes; + zipHandle->compressedOffset += numBytes; + return numBytes; +} + +static ssize_t +zip_readDeflated(uio_Handle *handle, void *buf, size_t count) { + zip_Handle *zipHandle; + int inflateResult; + + zipHandle = handle->native; + + if (count > ((zip_GPFileData *) (zipHandle->file->extra))-> + uncompressedSize - zipHandle->zipStream.total_out) + count = ((zip_GPFileData *) (zipHandle->file->extra))-> + uncompressedSize - zipHandle->zipStream.total_out; + + zipHandle->zipStream.next_out = (Bytef *) buf; + zipHandle->zipStream.avail_out = count; + while (zipHandle->zipStream.avail_out > 0) { + if (zipHandle->zipStream.avail_in == 0) { + ssize_t numBytes; + numBytes = uio_accessFileBlock(zipHandle->fileBlock, + zipHandle->compressedOffset, zip_INPUT_BUFFER_SIZE, + (char **) &zipHandle->zipStream.next_in); + if (numBytes == -1) { + // errno is set + return -1; + } +#if 0 + if (numBytes == 0) { + if (zipHandle->uncompressedOffset != + zipHandle->file->extra->uncompressedSize) { + // premature eof + errno = EIO; + return -1; + } + break; + } +#endif + zipHandle->zipStream.avail_in = numBytes; + zipHandle->compressedOffset += numBytes; + } + inflateResult = inflate(&zipHandle->zipStream, Z_SYNC_FLUSH); + zipHandle->uncompressedOffset = zipHandle->zipStream.total_out; + if (inflateResult == Z_STREAM_END) { + // Everything is decompressed + break; + } + if (inflateResult != Z_OK) { + switch (inflateResult) { + case Z_VERSION_ERROR: + fprintf(stderr, "Error: Incompatible version problem for " + " decompression.\n"); + break; + case Z_NEED_DICT: + fprintf(stderr, "Error: Decompressing requires " + "preset dictionary.\n"); + break; + case Z_DATA_ERROR: + fprintf(stderr, "Error: Compressed file is corrupted.\n"); + break; + case Z_STREAM_ERROR: + // This means zipHandle->zipStream is bad, which is + // most likely an error in the code using zlib. + fprintf(stderr, "Fatal: internal error using zlib.\n"); + abort(); + break; + case Z_MEM_ERROR: + fprintf(stderr, "Error: Not enough memory available " + "while decompressing.\n"); + break; + case Z_BUF_ERROR: + // No progress possible. Probably caused by premature + // end of input file. + fprintf(stderr, "Error: When decompressing: premature " + "end of input file.\n"); + errno = EIO; + return -1; +#if 0 + // If this happens, either the input buffer is empty + // or the output buffer is full. This should not happen. + fprintf(stderr, "Fatal: internal error using zlib: " + " no progress is possible in decompression.\n"); + abort(); + break; +#endif + default: + fprintf(stderr, "Fatal: unknown error from inflate().\n"); + abort(); + } + if (zipHandle->zipStream.msg != NULL) + fprintf(stderr, "ZLib reports: %s\n", + zipHandle->zipStream.msg); + errno = EIO; + // Using EIO to report an error in the backend. + return -1; + } + } + return count - zipHandle->zipStream.avail_out; +} + +off_t +zip_seek(uio_Handle *handle, off_t offset, int whence) { + zip_Handle *zipHandle; + +#if defined(DEBUG) && DEBUG > 1 + fprintf(stderr, "zip_seek - handle=%p offset=%d whence=%s\n", + (void *) handle, (int) offset, + whence == SEEK_SET ? "SEEK_SET" : + whence == SEEK_CUR ? "SEEK_CUR" : + whence == SEEK_END ? "SEEK_END" : "INVALID"); +#endif + zipHandle = handle->native; + + assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END); + switch(whence) { + case SEEK_SET: + break; + case SEEK_CUR: + offset += zipHandle->uncompressedOffset; + break; + case SEEK_END: + offset += zipHandle->file->extra->uncompressedSize; + break; + } + if (offset < 0) { + offset = 0; + } else if (offset > zipHandle->file->extra->uncompressedSize) { + offset = zipHandle->file->extra->uncompressedSize; + } + return zip_seekMethods[handle->native->file->extra->compressionMethod] + (handle, offset); +} + +static off_t +zip_seekStored(uio_Handle *handle, off_t offset) { + zip_Handle *zipHandle; + + zipHandle = handle->native; + if (offset > zipHandle->file->extra->uncompressedSize) + offset = zipHandle->file->extra->uncompressedSize; + + zipHandle->compressedOffset = offset; + zipHandle->uncompressedOffset = offset; + return offset; +} + +static off_t +zip_seekDeflated(uio_Handle *handle, off_t offset) { + zip_Handle *zipHandle; + + zipHandle = handle->native; + + if (offset < zipHandle->uncompressedOffset) { + // The new offset is earlier than the current offset. We need to + // seek from the beginning. + if (zip_reInitZipStream(&zipHandle->zipStream) == -1) { + // Need to abort. Handle would get in an inconsistent state. + // Should not fail anyhow. + fprintf(stderr, "Fatal: Could not reinitialise zip stream: " + "%s.\n", strerror(errno)); + abort(); + } + zipHandle->compressedOffset = 0; + zipHandle->uncompressedOffset = 0; + } + + if (offset == zipHandle->uncompressedOffset) + return offset; + + // Seek from the current position. + { + char *buffer; + ssize_t numRead; + size_t toRead; + + buffer = uio_malloc(zip_SEEK_BUFFER_SIZE); + toRead = offset - zipHandle->uncompressedOffset; + while (toRead > 0) { + numRead = zip_read(handle, buffer, + toRead < zip_SEEK_BUFFER_SIZE ? + toRead : zip_SEEK_BUFFER_SIZE); + if (numRead == -1) { + fprintf(stderr, "Warning: Could not read zipped file: %s\n", + strerror(errno)); + break; + // The current location is returned. + } + toRead -= numRead; + } + uio_free(buffer); + } + return zipHandle->uncompressedOffset; +} + +uio_PRoot * +zip_mount(uio_Handle *handle, int flags) { + uio_PRoot *result; + uio_PDirHandle *rootDirHandle; + + if ((flags & uio_MOUNT_RDONLY) != uio_MOUNT_RDONLY) { + errno = EACCES; + return NULL; + } + + uio_Handle_ref(handle); + result = uio_GPRoot_makePRoot( + uio_getFileSystemHandler(uio_FSTYPE_ZIP), flags, + &zip_GPRootOperations, NULL, uio_GPRoot_PERSISTENT, + handle, NULL, uio_GPDir_COMPLETE); + + rootDirHandle = uio_PRoot_getRootDirHandle(result); + zip_fillDirStructure(rootDirHandle->extra, handle); + + return result; +} + +static int +zip_fillDirStructure(uio_GPDir *top, uio_Handle *handle) { +#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS + return zip_fillDirStructureCentral(top, handle); +#endif +#if zip_USE_HEADERS == zip_USE_LOCAL_HEADERS + return zip_fillDirStructureLocal(top, handle); +#endif +} + +#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS +static int +zip_fillDirStructureCentral(uio_GPDir *top, uio_Handle *handle) { + uio_FileBlock *fileBlock; + off_t pos; + char *buf; + ssize_t numBytes; + uio_uint16 numEntries; + // TODO: use numEntries to initialise the hash table + // to a smart size + off_t eocdr; + off_t startCentralDir; + + fileBlock = uio_openFileBlock(handle); + if (fileBlock == NULL) { + // errno is set + goto err; + } + + // first find the 'End of Central Directory Record' + eocdr = zip_findEndOfCentralDirectoryRecord(handle, fileBlock); + if (eocdr == -1) { + // errno is set + goto err; + } + + numBytes = uio_accessFileBlock(fileBlock, eocdr, 22, &buf); + if (numBytes == -1) { + // errno is set + goto err; + } + if (numBytes != 22) { + errno = EIO; + goto err; + } + + numEntries = makeUInt16(buf[10], buf[11]); + if (numEntries == 0xffff) { + fprintf(stderr, "Error: Zip64 .zip files are not supported.\n"); + errno = ENOSYS; + goto err; + } + + startCentralDir = makeUInt32(buf[16], buf[17], buf[18], buf[19]); + + pos = startCentralDir; + while (numEntries--) { + if (zip_fillDirStructureCentralProcessFile(top, fileBlock, &pos) + == -1) { + // errno is set + goto err; + } + } + + uio_closeFileBlock(fileBlock); + return 0; + +err: + { + int saveErrno = errno; + + if (fileBlock != NULL) + uio_closeFileBlock(fileBlock); + errno = saveErrno; + return -1; + } +} + +static int +zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir, + uio_FileBlock *fileBlock, off_t *pos) { + char *buf; + zip_GPFileData *gPFileData; + ssize_t numBytes; + + uio_uint32 signature; + uio_uint16 lastModTime; + uio_uint16 lastModDate; + uio_uint32 crc; + uio_uint16 fileNameLength; + uio_uint16 extraFieldLength; + uio_uint16 fileCommentLength; + char *fileName; + + off_t nextEntryOffset; + + numBytes = uio_accessFileBlock(fileBlock, *pos, 46, &buf); + if (numBytes != 46) + return zip_badFile(NULL, NULL); + + signature = makeUInt32(buf[0], buf[1], buf[2], buf[3]); + if (signature != 0x02014b50) { + fprintf(stderr, "Error: Premature end of central directory.\n"); + errno = EIO; + return -1; + } + + gPFileData = zip_GPFileData_new(); + gPFileData->compressionFlags = makeUInt16(buf[8], buf[9]); + gPFileData->compressionMethod = makeUInt16(buf[10], buf[11]); + lastModTime = makeUInt16(buf[12], buf[13]); + lastModDate = makeUInt16(buf[14], buf[15]); + gPFileData->atime = (time_t) 0; + gPFileData->mtime = dosToUnixTime(lastModDate, lastModTime); + gPFileData->ctime = (time_t) 0; + gPFileData->uid = 0; + gPFileData->gid = 0; + gPFileData->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + crc = makeUInt32(buf[16], buf[17], buf[18], buf[19]); + gPFileData->compressedSize = + makeUInt32(buf[20], buf[21], buf[22], buf[23]); + gPFileData->uncompressedSize = + makeUInt32(buf[24], buf[25], buf[26], buf[27]); + fileNameLength = makeUInt16(buf[28], buf[29]); + extraFieldLength = makeUInt16(buf[30], buf[31]); + fileCommentLength = makeUInt16(buf[32], buf[33]); + gPFileData->headerOffset = + (off_t) makeSInt32(buf[42], buf[43], buf[44], buf[45]); + gPFileData->fileOffset = (off_t) -1; + + *pos += 46; + nextEntryOffset = *pos + fileNameLength + extraFieldLength + + fileCommentLength; + + numBytes = uio_accessFileBlock(fileBlock, *pos, fileNameLength, &buf); + if (numBytes != fileNameLength) + return zip_badFile(gPFileData, NULL); + fileName = uio_malloc(fileNameLength + 1); + memcpy(fileName, buf, fileNameLength); + fileName[fileNameLength] = '\0'; + *pos += fileNameLength; + + if (gPFileData->compressionMethod >= NUM_COMPRESSION_METHODS || + !zip_compressionMethodSupported[gPFileData->compressionMethod]) { + fprintf(stderr, "Warning: File '%s' is compressed with " + "unsupported method %d - skipped.\n", fileName, + gPFileData->compressionMethod); + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + return 0; + } + + if (gPFileData->compressedSize == (off_t) 0xffffffff || + gPFileData->uncompressedSize == (off_t) 0xffffffff || + gPFileData->headerOffset < 0) { + fprintf(stderr, "Warning: Skipping Zip64 file '%s'\n", fileName); + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + return 0; + } + + if (isBitSet(gPFileData->compressionFlags, 0)) { + fprintf(stderr, "Warning: Skipping encrypted file '%s'\n", fileName); + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + return 0; + } + + switch (zip_fillDirStructureProcessExtraFields(fileBlock, + extraFieldLength, gPFileData, fileName, *pos)) { + case 0: // file is ok + break; + case 1: // file is not acceptable - skip file + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + uio_free(fileName); + return 0; + case -1: + return zip_badFile(gPFileData, fileName); + } + + *pos += extraFieldLength; + + // If ctime or atime is 0, they will be filled in when the local + // file header is read. + + if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) { + if (errno == EISDIR) { + zip_GPFileData_delete(gPFileData); + uio_free(fileName); + return 0; + } + return zip_badFile(gPFileData, fileName); + } + +#if defined(DEBUG) && DEBUG > 1 + fprintf(stderr, "Debug: Found file '%s'.\n", fileName); +#endif + + uio_free(fileName); + return 0; +} + +static off_t +zip_findEndOfCentralDirectoryRecord(uio_Handle *handle, + uio_FileBlock *fileBlock) { + off_t fileSize; + off_t endPos, startPos; + char *buf, *bufPtr; + ssize_t bufLen; + + struct stat statBuf; + if (uio_fstat(handle, &statBuf) == -1) { + // errno is set + return -1; + } + fileSize = statBuf.st_size; + startPos = fileSize - 0xffff - 22; // max comment and record size + if (startPos < 0) + startPos = 0; + endPos = fileSize - 22; // last position to be checked + bufLen = uio_accessFileBlock(fileBlock, startPos, endPos - startPos + 4, + &buf); + if (bufLen == -1) { + int saveErrno = errno; + fprintf(stderr, "Error: Read error while searching for " + "'end-of-central-directory record'.\n"); + errno = saveErrno; + return -1; + } + if (bufLen != endPos - startPos + 4) { + fprintf(stderr, "Error: Read error while searching for " + "'end-of-central-directory record'.\n"); + errno = EIO; + return -1; + } + bufPtr = buf + (endPos - startPos); + while (1) { + if (bufPtr < buf) { + fprintf(stderr, "Error: Zip file corrupt; could not find " + "'end-of-central-directory record'.\n"); + errno = EIO; + return -1; + } + if (bufPtr[0] == 0x50 && bufPtr[1] == 0x4b && bufPtr[2] == 0x05 && + bufPtr[3] == 0x06) + break; + bufPtr--; + } + return startPos + (bufPtr - buf); +} + +// If the data is read from the central directory, certain data +// will need to be updated from the local directory when it is needed. +// This function does that. +// returns 0 for success, -1 for error (errno is set) +// NB: Only the fields that may offer new information are checked. +// the fields that were already read from the central directory +// aren't verified. +static int +zip_updatePFileDataFromLocalFileHeader(zip_GPFileData *gPFileData, + uio_FileBlock *fileBlock, int pos) { + ssize_t numBytes; + char *buf; + uio_uint32 signature; + uio_uint16 fileNameLength; + uio_uint16 extraFieldLength; + + numBytes = uio_accessFileBlock(fileBlock, pos, 30, &buf); + if (numBytes != 30) { + errno = EIO; + return -1; + } + signature = makeUInt32(buf[0], buf[1], buf[2], buf[3]); + if (signature != 0x04034b50) { + errno = EIO; + return -1; + } + fileNameLength = makeUInt16(buf[26], buf[27]); + extraFieldLength = makeUInt16(buf[28], buf[29]); + pos += 30 + fileNameLength; + + switch (zip_fillDirStructureProcessExtraFields(fileBlock, + extraFieldLength, gPFileData, "", pos)) { + case 0: // file is ok + break; + case 1: + // File is not acceptable (but according to the central header + // it was) + fprintf(stderr, "Warning: according to the central directory " + "of a zip file, some file inside is acceptable, " + "but according to the local header it isn't.\n"); + errno = EIO; + return -1; + case -1: + errno = EIO; + return -1; + } + pos += extraFieldLength; + gPFileData->fileOffset = pos; + return 0; +} +#endif /* zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS */ + +#if zip_USE_HEADERS == zip_USE_LOCAL_HEADERS +static int +zip_fillDirStructureLocal(uio_GPDir *top, uio_Handle *handle) { + uio_FileBlock *fileBlock; + off_t pos; + char *buf; + ssize_t numBytes; + + pos = uio_lseek(handle, 0, SEEK_SET); + if (pos == -1) { + int saveErrno = errno; + errno = saveErrno; + return -1; + } + if (pos != 0) { + errno = EIO; + // Using EIO to report an error in the backend. + return -1; + } + + // We read all the files from the beginning of the zip file to the end. + // (the directory record at the end of the file is ignored) + fileBlock = uio_openFileBlock(handle); + if (fileBlock == NULL) { + // errno is set + return -1; + } + + pos = 0; + while (1) { + uio_uint32 signature; + + numBytes = uio_accessFileBlock(fileBlock, pos, 4, &buf); + if (numBytes == -1) + goto err; + if (numBytes != 4) + break; + signature = makeUInt32(buf[0], buf[1], buf[2], buf[3]); + if (signature != 0x04034b50) { + // End of file data reached. + break; + } + pos += 4; + if (zip_fillDirStructureLocalProcessFile(top, fileBlock, &pos) == -1) + goto err; + } + + uio_closeFileBlock(fileBlock); + return 0; + +err: + { + int saveErrno = errno; + + uio_closeFileBlock(fileBlock); + errno = saveErrno; + return -1; + } +} + +static int +zip_fillDirStructureLocalProcessFile(uio_GPDir *topGPDir, + uio_FileBlock *fileBlock, off_t *pos) { + char *buf; + zip_GPFileData *gPFileData; + ssize_t numBytes; + + uio_uint16 lastModTime; + uio_uint16 lastModDate; + uio_uint32 crc; + uio_uint16 fileNameLength; + uio_uint16 extraFieldLength; + char *fileName; + + off_t nextEntryOffset; + + numBytes = uio_accessFileBlock(fileBlock, *pos, 26, &buf); + if (numBytes != 26) + return zip_badFile(NULL, NULL); + + gPFileData = zip_GPFileData_new(); + gPFileData->compressionFlags = makeUInt16(buf[2], buf[3]); + gPFileData->compressionMethod = makeUInt16(buf[4], buf[5]); + lastModTime = makeUInt16(buf[6], buf[7]); + lastModDate = makeUInt16(buf[8], buf[9]); + gPFileData->atime = (time_t) 0; + gPFileData->mtime = dosToUnixTime(lastModDate, lastModTime); + gPFileData->ctime = (time_t) 0; + gPFileData->uid = 0; + gPFileData->gid = 0; + gPFileData->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (!isBitSet(gPFileData->compressionFlags, 3)) { + // If bit 3 is not set, this info will be in the data descriptor + // behind the file data. + crc = makeUInt32(buf[10], buf[11], buf[12], buf[13]); + gPFileData->compressedSize = + makeUInt32(buf[14], buf[15], buf[16], buf[17]); + gPFileData->uncompressedSize = + makeUInt32(buf[18], buf[19], buf[20], buf[21]); + } + fileNameLength = makeUInt16(buf[22], buf[23]); + extraFieldLength = makeUInt16(buf[24], buf[25]); + *pos += 26; + nextEntryOffset = *pos + fileNameLength + extraFieldLength + + gPFileData->compressedSize; + if (isBitSet(gPFileData->compressionFlags, 3)) { + // There's a data descriptor present behind the file data. + nextEntryOffset += 16; + } + + if (gPFileData->compressionMethod >= NUM_COMPRESSION_METHODS || + !zip_compressionMethodSupported[gPFileData->compressionMethod]) { + fprintf(stderr, "Warning: File '%s' is compressed with " + "unsupported method %d - skipped.\n", fileName, + gPFileData->compressionMethod); + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + return 0; + } + + if (gPFileData->compressedSize == (off_t) 0xffffffff || + gPFileData->uncompressedSize == (off_t) 0xffffffff) { + fprintf(stderr, "Warning: Skipping Zip64 file '%s'\n", fileName); + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + return 0; + } + + if (isBitSet(gPFileData->compressionFlags, 0)) { + fprintf(stderr, "Warning: Skipping encrypted file '%s'\n", fileName); + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + return 0; + } + + numBytes = uio_accessFileBlock(fileBlock, *pos, fileNameLength, &buf); + if (numBytes != fileNameLength) + return zip_badFile(gPFileData, NULL); + fileName = uio_malloc(fileNameLength + 1); + memcpy(fileName, buf, fileNameLength); + fileName[fileNameLength] = '\0'; + *pos += fileNameLength; + + switch (zip_fillDirStructureProcessExtraFields(fileBlock, + extraFieldLength, gPFileData, fileName, *pos)) { + case 0: // file is ok + break; + case 1: // file is not acceptable - skip file + *pos = nextEntryOffset; + zip_GPFileData_delete(gPFileData); + uio_free(fileName); + return 0; + case -1: + return zip_badFile(gPFileData, fileName); + } + *pos += extraFieldLength; + + gPFileData->fileOffset = *pos; + + *pos += gPFileData->compressedSize; + if (isBitSet(gPFileData->compressionFlags, 3)) { + // Now comes a data descriptor. + // The PKWare version (which was never used) misses the signature. + // The InfoZip version is used below. + uio_uint32 signature; + + numBytes = uio_accessFileBlock(fileBlock, *pos, 16, &buf); + if (numBytes != 16) + return zip_badFile(gPFileData, fileName); + + signature = makeUInt32(buf[0], buf[1], buf[2], buf[3]); + if (signature != 0x08074b50) + return zip_badFile(gPFileData, fileName); + crc = makeUInt32(buf[4], buf[5], buf[6], buf[7]); + gPFileData->compressedSize = + makeUInt32(buf[8], buf[9], buf[10], buf[11]); + gPFileData->uncompressedSize = + makeUInt32(buf[12], buf[13], buf[14], buf[15]); + } + + if (gPFileData->ctime == (time_t) 0) + gPFileData->ctime = gPFileData->mtime; + + if (gPFileData->atime == (time_t) 0) + gPFileData->atime = gPFileData->mtime; + + if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) { + if (errno == EISDIR) { + zip_GPFileData_delete(gPFileData); + uio_free(fileName); + return 0; + } + return zip_badFile(gPFileData, fileName); + } + +#ifdef DEBUG + fprintf(stderr, "Debug: Found file '%s'.\n", fileName); +#endif + + uio_free(fileName); + return 0; +} +#endif /* zip_USE_HEADERS == zip_USE_LOCAL_HEADERS */ + +// If the zip file is bad, -1 is returned (no errno set!) +// If the file in the zip file should be skipped, 1 is returned. +// If the file in the zip file is ok, 0 is returned. +static int +zip_fillDirStructureProcessExtraFields(uio_FileBlock *fileBlock, + off_t extraFieldLength, zip_GPFileData *gPFileData, + const char *fileName, off_t pos) { + off_t posEnd; + uio_uint16 headerID; + ssize_t dataSize; + ssize_t numBytes; + char *buf; + + posEnd = pos + extraFieldLength; + while (pos < posEnd) { + numBytes = uio_accessFileBlock(fileBlock, pos, 4, &buf); + if (numBytes != 4) + return -1; + headerID = makeUInt16(buf[0], buf[1]); + dataSize = (ssize_t) makeUInt16(buf[2], buf[3]); + pos += 4; + numBytes = uio_accessFileBlock(fileBlock, pos, dataSize, &buf); + if (numBytes != dataSize) + return -1; + switch(headerID) { + case 0x000d: // 'Unix0' + // fallthrough + case 0x5855: // 'Unix1' + gPFileData->atime = (time_t) makeUInt32( + buf[0], buf[1], buf[2], buf[3]); + gPFileData->mtime = (time_t) makeUInt32( + buf[4], buf[5], buf[6], buf[7]); + if (dataSize > 8) { + gPFileData->uid = (uid_t) makeUInt16(buf[8], buf[9]); + gPFileData->gid = (uid_t) makeUInt16(buf[10], buf[11]); + } + // Unix0 has an extra (ignored) field at the end. + break; + case 0x5455: { // 'time' + uio_uint8 flags; + const char *bufPtr; + flags = buf[0]; + bufPtr = buf + 1; + if (isBitSet(flags, 0)) { + // modification time is present + gPFileData->mtime = (time_t) makeUInt32( + bufPtr[0], bufPtr[1], bufPtr[2], bufPtr[3]); + bufPtr += 4; + } + if (isBitSet(flags, 1)) { + // modification time is present + gPFileData->atime = (time_t) makeUInt32( + bufPtr[0], bufPtr[1], bufPtr[2], bufPtr[3]); + bufPtr += 4; + } + // Creation time and possible other times are skipped. + break; + } + case 0x7855: // 'Unix2' + gPFileData->uid = (uid_t) makeUInt16(buf[0], buf[1]); + gPFileData->gid = (uid_t) makeUInt16(buf[2], buf[3]); + break; + case 0x756e: { // 'Unix3' + mode_t mode; + mode = (mode_t) makeUInt16(buf[4], buf[5]); + if (!S_ISREG(mode)) { + fprintf(stderr, "Warning: Skipping '%s'; not a regular " + "file.\n", fileName); + return 1; + } + gPFileData->uid = (uid_t) makeUInt16(buf[10], buf[11]); + gPFileData->gid = (uid_t) makeUInt16(buf[12], buf[13]); + break; + } + default: +#ifdef DEBUG + fprintf(stderr, "Debug: Extra field 0x%04x unsupported, " + "used for file '%s' - ignored.\n", headerID, + fileName); +#endif + break; + } // switch + pos += dataSize; + } // while + if (pos != posEnd) + return -1; + return 0; +} + +static int +zip_badFile(zip_GPFileData *gPFileData, char *fileName) { + fprintf(stderr, "Error: Bad file format for .zip file.\n"); + if (gPFileData != NULL) + zip_GPFileData_delete(gPFileData); + if (fileName != NULL) + uio_free(fileName); + errno = EINVAL; // Is this the best choice? + return -1; +} + +static inline int +zip_foundFile(uio_GPDir *gPDir, const char *path, zip_GPFileData *gPFileData) { + uio_GPFile *file; + size_t pathLen; + const char *pathEnd; + const char *start, *end; + char *buf; + + if (path[0] == '/') + path++; + pathLen = strlen(path); + if (path[pathLen - 1] == '/') { + fprintf(stderr, "Warning: '%s' is not a valid file name - skipped.\n", + path); + errno = EISDIR; + return -1; + } + pathEnd = path + pathLen; + + switch (uio_walkGPPath(gPDir, path, pathLen, &gPDir, &path)) { + case 0: + // The entire path was matched. The last part was not supposed + // to be a dir. + fprintf(stderr, "Warning: '%s' already exists as a dir - " + "skipped.\n", path); + errno = EISDIR; + return -1; + case ENOTDIR: + fprintf(stderr, "Warning: A component to '%s' is not a " + "directory - file skipped.\n", path); + errno = ENOTDIR; + return -1; + case ENOENT: + break; + } + + buf = uio_malloc(pathLen + 1); + getFirstPathComponent(path, pathEnd, &start, &end); + while (1) { + uio_GPDir *newGPDir; + + if (end == start || (end - start == 1 && start[0] == '.') || + (end - start == 2 && start[0] == '.' && start[1] == '.')) { + fprintf(stderr, "Warning: file '%s' has an invalid path - " + "file skipped.\n", path); + uio_free(buf); + errno = EINVAL; + return -1; + } + if (end == pathEnd) { + // This is the last component; the should be the name of the dir. + path = start; + break; + } + memcpy(buf, start, end - start); + buf[end - start] = '\0'; + newGPDir = uio_GPDir_prepareSubDir(gPDir, buf); + newGPDir->flags |= uio_GPDir_COMPLETE; + // It will be complete when we're done with adding + // all files, and it won't be used before that. + uio_GPDir_commitSubDir(gPDir, buf, newGPDir); + + gPDir = newGPDir; + getNextPathComponent(pathEnd, &start, &end); + } + + uio_free(buf); + + file = uio_GPFile_new(gPDir->pRoot, (uio_GPFileExtra) gPFileData, + uio_gPFileFlagsFromPRootFlags(gPDir->pRoot->flags)); + uio_GPDir_addFile(gPDir, path, file); + return 0; +} + +static int +zip_initZipStream(z_stream *zipStream) { + int retVal; + + zipStream->next_in = Z_NULL; + zipStream->avail_in = 0; + zipStream->zalloc = zip_alloc; + zipStream->zfree = zip_free; + zipStream->opaque = NULL; + retVal = inflateInit2(zipStream, -MAX_WBITS); + // Negative window size means that no zlib header is present. + // This feature is undocumented in zlib, but it's used + // in the minizip program from the zlib contrib dir. + // The absolute value is used as real Window size. + if (retVal != Z_OK) { + switch (retVal) { + case Z_MEM_ERROR: + fprintf(stderr, "Error: Not enough memory available for " + " decompression.\n"); + break; + case Z_VERSION_ERROR: + fprintf(stderr, "Error: Incompatible version problem for " + " decompression.\n"); + break; + default: + fprintf(stderr, "Fatal: unknown error from inflateInit().\n"); + abort(); + } + if (zipStream->msg != NULL) + fprintf(stderr, "ZLib reports: %s\n", zipStream->msg); + errno = EIO; + // Using EIO to report an error in the backend. + return -1; + } + return 0; +} + +static int +zip_unInitZipStream(z_stream *zipStream) { + int retVal; + + retVal = inflateEnd(zipStream); + if (retVal != Z_OK) { + switch (retVal) { + case Z_STREAM_ERROR: + // This means zipHandle->zipStream is bad, which is + // most likely an error in the code using zlib. + fprintf(stderr, "Fatal: internal error using zlib.\n"); + abort(); + break; + default: + fprintf(stderr, "Fatal: unknown error from inflateEnd().\n"); + abort(); + } + if (zipStream->msg != NULL) + fprintf(stderr, "ZLib reports: %s\n", zipStream->msg); + errno = EIO; + // Using EIO to report an error in the backend. + return -1; + } + return 0; +} + +static int +zip_reInitZipStream(z_stream *zipStream) { + int retVal; + + zipStream->next_in = Z_NULL; + zipStream->avail_in = 0; + retVal = inflateReset(zipStream); + if (retVal != Z_OK) { + switch (retVal) { + case Z_STREAM_ERROR: + // This means zipHandle->zipStream is bad, which is + // most likely an error in the code using zlib. + fprintf(stderr, "Fatal: internal error using zlib.\n"); + abort(); + break; + default: + fprintf(stderr, "Fatal: unknown error from inflateInit().\n"); + abort(); + } + if (zipStream->msg != NULL) + fprintf(stderr, "ZLib reports: %s\n", zipStream->msg); + errno = EIO; + // Using EIO to report an error in the backend. + return -1; + } + return 0; +} + + +// Used internally by zlib for allocating memory. +static voidpf +zip_alloc(voidpf opaque, uInt items, uInt size) { + (void) opaque; + return (voidpf) uio_calloc((size_t) items, (size_t) size); +} + +// Used internally by zlib for freeing memory. +static void +zip_free(voidpf opaque, voidpf address) { + (void) opaque; + uio_free((void *) address); +} + +static inline zip_GPFileData * +zip_GPFileData_new(void) { + return zip_GPFileData_alloc(); +} + +static inline void +zip_GPFileData_delete(zip_GPFileData *gPFileData) { + zip_GPFileData_free(gPFileData); +} + +static inline zip_GPFileData * +zip_GPFileData_alloc(void) { + zip_GPFileData *result = uio_malloc(sizeof (zip_GPFileData)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(zip_GPFileData, (void *) result); +#endif + return result; +} + +static inline void +zip_GPFileData_free(zip_GPFileData *gPFileData) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(zip_GPFileData, (void *) gPFileData); +#endif + uio_free(gPFileData); +} + + + diff --git a/sc2/src/sc2code/libs/uio/zip/zip.h b/sc2/src/sc2code/libs/uio/zip/zip.h new file mode 100644 index 000000000..877ec8d75 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/zip/zip.h @@ -0,0 +1,92 @@ +/* + * 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 zip_Handle *uio_NativeHandle; +typedef void *uio_GPRootExtra; +typedef void *uio_GPDirExtra; +typedef struct zip_GPFileData *uio_GPFileExtra; +typedef struct uio_GPDirEntries_Iterator *uio_NativeEntriesContext; + +#define uio_INTERNAL_PHYSICAL + +#include "../gphys.h" +#include "../iointrn.h" +#include "../uioport.h" +#include "../physical.h" +#include "../types.h" +#include "../fileblock.h" + +#include +#include +#include + +// zip_USE_HEADERS determinines what header for files within a .zip file +// is used when building the directory structure. +// Set to 'zip_USE_CENTRAL_HEADERS' to use the central directory header, +// set to 'zip_USE_LOCAL_HEADERS' to use the local file header. +// Central is highly adviced: it uses much less seeking, and hence is much +// faster. +#define zip_USE_HEADERS zip_USE_CENTRAL_HEADERS +#define zip_USE_CENTRAL_HEADERS 1 +#define zip_USE_LOCAL_HEADERS 2 + +typedef struct zip_GPFileData { + off_t compressedSize; + off_t uncompressedSize; + uio_uint16 compressionFlags; + uio_uint16 compressionMethod; +#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS + off_t headerOffset; // start of the local header for this file +#endif + off_t fileOffset; // start of the compressed data in the .zip file + uid_t uid; + gid_t gid; + mode_t mode; + time_t atime; // access time + time_t mtime; // modification time + time_t ctime; // change time +} zip_GPFileData; + +typedef struct zip_Handle { + uio_GPFile *file; + z_stream zipStream; + uio_FileBlock *fileBlock; + off_t uncompressedOffset; + // seek location in the uncompressed stream + off_t compressedOffset; + // seek location in the compressed stream, from the start + // of the compressed file +} zip_Handle; + + +uio_PRoot *zip_mount(uio_Handle *handle, int flags); +int zip_umount(struct uio_PRoot *); +uio_Handle *zip_open(uio_PDirHandle *pDirHandle, const char *file, int flags, + mode_t mode); +void zip_close(uio_Handle *handle); +int zip_fstat(uio_Handle *handle, struct stat *statBuf); +int zip_stat(uio_PDirHandle *pDirHandle, const char *name, + struct stat *statBuf); +ssize_t zip_read(uio_Handle *handle, void *buf, size_t count); +off_t zip_seek(uio_Handle *handle, off_t offset, int whence); + + + + diff --git a/sc2/src/sc2code/load.c b/sc2/src/sc2code/load.c index 649100c75..7af4b0e86 100644 --- a/sc2/src/sc2code/load.c +++ b/sc2/src/sc2code/load.c @@ -76,7 +76,7 @@ LoadShipQueue (DECODE_REF fh, PQUEUE pQueue, BOOLEAN MakeQ) } BOOLEAN -LoadSummary (FILE *in_fp) +LoadSummary (uio_Stream *in_fp) { SUMMARY_DESC S; @@ -86,14 +86,14 @@ LoadSummary (FILE *in_fp) BOOLEAN LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) { - FILE *in_fp; + uio_Stream *in_fp; char buf[256], file[PATH_MAX]; - sprintf (file, "%sstarcon2.%02u", saveDir, which_game); - in_fp = res_OpenResFile (file, "rb"); + sprintf (file, "starcon2.%02u", which_game); + in_fp = res_OpenResFile (saveDir, file, "rb"); if (in_fp) { - FILE *fp; + uio_Stream *fp; DECODE_REF fh; COUNT num_links; Semaphore clock_sem; @@ -229,7 +229,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) } } - fp = res_OpenResFile (tempFilePath (STARINFO_FILE), "wb"); + fp = res_OpenResFile (tempDir, STARINFO_FILE, "wb"); if (fp) { DWORD flen; @@ -248,7 +248,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) res_CloseResFile (fp); } - fp = res_OpenResFile (tempFilePath (DEFGRPINFO_FILE), "wb"); + fp = res_OpenResFile (tempDir, DEFGRPINFO_FILE, "wb"); if (fp) { DWORD flen; @@ -267,7 +267,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) res_CloseResFile (fp); } - fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "wb"); + fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "wb"); if (fp) { DWORD flen; diff --git a/sc2/src/sc2code/melee.c b/sc2/src/sc2code/melee.c index 495c1e471..254d7c6f1 100644 --- a/sc2/src/sc2code/melee.c +++ b/sc2/src/sc2code/melee.c @@ -666,27 +666,24 @@ GetTeamValue (TEAM_IMAGE *pTI) } static int -ReadTeamImage (TEAM_IMAGE *pTI, FILE *load_fp) +ReadTeamImage (TEAM_IMAGE *pTI, uio_Stream *load_fp) { return (ReadResFile (pTI, sizeof (*pTI), 1, load_fp) == 1 ? 0 : -1); } static int LoadTeamImage(DIRENTRY DirEntry, TEAM_IMAGE* pTI, - UNICODE* pFilePath, UNICODE** ppFileName) + UNICODE* pFilePath) { - UNICODE file[PATH_MAX]; // local buf if needed + UNICODE file[NAME_MAX]; // local buf if needed UNICODE *pfile; - UNICODE *loc_buf; - FILE *load_fp; + uio_Stream *load_fp; int status; pfile = pFilePath != NULL_PTR ? pFilePath : file; - strcpy (pfile, meleeDir); - loc_buf = pfile + strlen (pfile); - GetDirEntryContents (DirEntry, (STRINGPTR)loc_buf, FALSE); - if ((load_fp = res_OpenResFile (pfile, "rb")) == 0) + GetDirEntryContents (DirEntry, (STRINGPTR)pfile, FALSE); + if ((load_fp = res_OpenResFile (meleeDir, pfile, "rb")) == 0) status = -1; else { @@ -697,9 +694,6 @@ LoadTeamImage(DIRENTRY DirEntry, TEAM_IMAGE* pTI, res_CloseResFile (load_fp); } - if (pFilePath != NULL_PTR && ppFileName != NULL_PTR) - *ppFileName = loc_buf; - return status; } @@ -790,8 +784,7 @@ DrawFileStrings (PMELEE_STATE pMS, int HiLiteState) pMS->TeamDE, bot - NUM_PREBUILT ); if (-1 == LoadTeamImage (pMS->TeamDE, - &pMS->FileList[bot - top], NULL_PTR, NULL_PTR - )) + &pMS->FileList[bot - top], NULL_PTR)) { pMS->FileList[bot - top] = pMS->PreBuiltList[0]; } @@ -1031,7 +1024,7 @@ DoTextEntry (PMELEE_STATE pMS) } static int -WriteTeamImage (TEAM_IMAGE *pTI, FILE *save_fp) +WriteTeamImage (TEAM_IMAGE *pTI, uio_Stream *save_fp) { return (WriteResFile (pTI, sizeof (*pTI), 1, save_fp)); } @@ -1040,17 +1033,13 @@ static void LoadTeamList (PMELEE_STATE pMS, UNICODE *pbuf) { COUNT num_entries; - char dir[PATH_MAX]; - char file[PATH_MAX]; - UNICODE *loc_buf; + char file[NAME_MAX]; - sprintf (dir, "%s*.mle", meleeDir); - GetNewList: DestroyDirEntryTable (ReleaseDirEntryTable (pMS->TeamDE)); pMS->TeamDE = CaptureDirEntryTable ( - LoadDirEntryTable (dir, &num_entries) - ); + LoadDirEntryTable (meleeDir, "", ".mle", match_MATCH_SUFFIX, + &num_entries)); pMS->CurIndex = 0; while (num_entries--) @@ -1058,15 +1047,15 @@ GetNewList: int status; TEAM_IMAGE TI; - status = LoadTeamImage(pMS->TeamDE, &TI, file, &loc_buf); + status = LoadTeamImage(pMS->TeamDE, &TI, file); if (status == -1) { - DeleteResFile (file); + DeleteResFile (meleeDir, file); goto GetNewList; } - if (pbuf && wstricmp (loc_buf, pbuf) == 0) + if (pbuf && wstricmp (file, pbuf) == 0) { pMS->CurIndex = GetDirEntryTableIndex (pMS->TeamDE) + NUM_PREBUILT; pbuf = 0; @@ -1080,20 +1069,17 @@ static BOOLEAN DoSaveTeam (PMELEE_STATE pMS) { STAMP MsgStamp; - char buf[PATH_MAX]; - char *file; - FILE *save_fp; + char file[NAME_MAX]; + uio_Stream *save_fp; CONTEXT OldContext; - strcpy(buf, meleeDir); - file = buf + strlen (buf); sprintf (file, "%s.mle", pMS->TeamImage[pMS->side].TeamName); RetrySave: SetSemaphore (GraphicsSem); OldContext = SetContext (ScreenContext); ConfirmSaveLoad (&MsgStamp); - save_fp = res_OpenResFile (buf, "wb"); + save_fp = res_OpenResFile (meleeDir, file, "wb"); if (save_fp) { BOOLEAN err; @@ -1113,7 +1099,7 @@ RetrySave: SetContext (OldContext); ClearSemaphore (GraphicsSem); - DeleteResFile (buf); + DeleteResFile (meleeDir, file); if (SaveProblem ()) goto RetrySave; } @@ -1858,15 +1844,9 @@ Melee (void) GameSounds = CaptureSound (LoadSound (GAME_SOUNDS)); LoadMeleeInfo (&MenuState); { - FILE *load_fp; - char configFile[PATH_MAX]; - int res; + uio_Stream *load_fp; - res = snprintf (configFile, PATH_MAX, "%smelee.cfg", configDir); - assert (res != -1); - // strlen (configDir) is supposed to be checked to be - // <= PATH_MAX - 13 - load_fp = res_OpenResFile (configFile, "rb"); + load_fp = res_OpenResFile (configDir, "melee.cfg", "rb"); if (load_fp) { int status; @@ -1909,17 +1889,11 @@ Melee (void) WaitForSoundEnd (TFBSOUND_WAIT_ALL); { - FILE *save_fp; + uio_Stream *save_fp; BOOLEAN err; - char configFile[PATH_MAX]; - int res; err = FALSE; - res = snprintf (configFile, PATH_MAX, "%smelee.cfg", configDir); - assert (res != -1); - // strlen (configDir) is supposed to be checked to be - // <= PATH_MAX - 13 - save_fp = res_OpenResFile (configFile, "wb"); + save_fp = res_OpenResFile (configDir, "melee.cfg", "wb"); if (save_fp) { if (PutResFileChar (PlayerControl[0], save_fp) == -1) @@ -1938,7 +1912,7 @@ Melee (void) if (err) { - DeleteResFile ("melee.cfg"); + DeleteResFile (configDir, "melee.cfg"); } } FreeMeleeInfo (&MenuState); diff --git a/sc2/src/sc2code/save.c b/sc2/src/sc2code/save.c index 8e8dec062..c88d334f0 100644 --- a/sc2/src/sc2code/save.c +++ b/sc2/src/sc2code/save.c @@ -307,7 +307,7 @@ RetrySave: } else { - FILE *fp; + uio_Stream *fp; DWORD flen; COUNT num_links; FRAME frame; @@ -385,7 +385,7 @@ RetrySave: } } - fp = res_OpenResFile (tempFilePath (STARINFO_FILE), "rb"); + fp = res_OpenResFile (tempDir, STARINFO_FILE, "rb"); if (fp) { flen = LengthResFile (fp); @@ -403,7 +403,7 @@ RetrySave: res_CloseResFile (fp); } - fp = res_OpenResFile (tempFilePath (DEFGRPINFO_FILE), "rb"); + fp = res_OpenResFile (tempDir, DEFGRPINFO_FILE, "rb"); if (fp) { flen = LengthResFile (fp); @@ -421,7 +421,7 @@ RetrySave: res_CloseResFile (fp); } - fp = res_OpenResFile (tempFilePath (RANDGRPINFO_FILE), "rb"); + fp = res_OpenResFile (tempDir, RANDGRPINFO_FILE, "rb"); if (fp) { flen = LengthResFile (fp); @@ -443,9 +443,9 @@ RetrySave: flen = cclose (fh); - sprintf (file, "%sstarcon2.%02u", saveDir, which_game); + sprintf (file, "starcon2.%02u", which_game); // fprintf (stderr, "'%s' is %lu bytes long\n", file, flen + sizeof (*summary_desc)); - if (flen && (out_fp = (PVOID)res_OpenResFile (file, "wb"))) + if (flen && (out_fp = (PVOID)res_OpenResFile (saveDir, file, "wb"))) { PrepareSummary (summary_desc); @@ -456,7 +456,7 @@ RetrySave: success = FALSE; mem_unlock (h); - if (res_CloseResFile ((FILE *)out_fp) == 0) + if (res_CloseResFile ((uio_Stream *)out_fp) == 0) success = FALSE; } @@ -464,7 +464,7 @@ RetrySave: success = FALSE; if (!success) - DeleteResFile (file); + DeleteResFile (saveDir, file); } mem_unlock (h); diff --git a/sc2/src/sc2code/shipyard.c b/sc2/src/sc2code/shipyard.c index bbea30b56..8128cc544 100644 --- a/sc2/src/sc2code/shipyard.c +++ b/sc2/src/sc2code/shipyard.c @@ -19,6 +19,7 @@ #include "starcon.h" #include "melee.h" #include "controls.h" +#include "options.h" #include "libs/graphics/gfx_common.h" //Added by Chris @@ -1215,7 +1216,7 @@ DoShipyard (PMENU_STATE pMS) ); pMS->CurString = CaptureColorMap (LoadColorMapFile ( - "lbm/dockpani.ct")); + contentDir, "lbm/dockpani.ct")); pMS->hMusic = LoadMusicInstance (SHIPYARD_MUSIC); diff --git a/sc2/src/sc2code/starcon.h b/sc2/src/sc2code/starcon.h index 89d31f5d7..2f745892b 100644 --- a/sc2/src/sc2code/starcon.h +++ b/sc2/src/sc2code/starcon.h @@ -43,6 +43,7 @@ extern int ScreenHeight; #include "config.h" #include "../port.h" +#include "libs/file.h" #include #include "gfxlib.h" #include "inplib.h" @@ -166,15 +167,9 @@ extern Semaphore GraphicsSem; extern CondVar RenderingCond; extern STRING GameStrings; -typedef enum -{ - PACKAGE_ERROR, - LOAD_ERROR, - SAVE_ERROR -} DISK_ERROR; - extern void Introduction (void); -extern BOOLEAN TheftProtection (BOOLEAN WaitForInput); +int initIO (void); +void uninitIO (void); extern void SetFlashRect (PRECT pRect, FRAME f); @@ -183,8 +178,6 @@ extern void DrawStarConBox (PRECT pRect, SIZE BorderWidth, COLOR InteriorColor); extern BOOLEAN ConfirmExit (void); extern DWORD SeedRandomNumbers (void); -extern BOOLEAN StarConDiskError (PSTR pFileName); -extern void ReportDiskError (PSTR pFileName, DISK_ERROR ErrorCondition); extern void DoInput (PVOID pInputState, BOOLEAN resetInput); extern BOOLEAN Battle (void); extern void EncounterBattle (void); diff --git a/sc2/src/sc2code/state.c b/sc2/src/sc2code/state.c index 20b68b0f4..595dfebd7 100644 --- a/sc2/src/sc2code/state.c +++ b/sc2/src/sc2code/state.c @@ -27,7 +27,7 @@ InitPlanetInfo (void) { PVOID fp; - fp = res_OpenResFile (tempFilePath (STARINFO_FILE), "wb"); + fp = res_OpenResFile (tempDir, STARINFO_FILE, "wb"); if (fp) { DWORD offset; @@ -60,7 +60,7 @@ GetPlanetInfo (void) pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask[BIOLOGICAL_SCAN] = pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask[MINERAL_SCAN] = pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask[ENERGY_SCAN] = 0; - fp = res_OpenResFile (tempFilePath (STARINFO_FILE), "rb"); + fp = res_OpenResFile (tempDir, STARINFO_FILE, "rb"); if (fp) { COUNT star_index, planet_index, moon_index; @@ -107,7 +107,7 @@ PutPlanetInfo (void) { PVOID fp; - fp = res_OpenResFile (tempFilePath (STARINFO_FILE), "r+b"); + fp = res_OpenResFile (tempDir, STARINFO_FILE, "r+b"); if (fp) { COUNT i; diff --git a/sc2/src/starcon2.c b/sc2/src/starcon2.c index d71846668..0c8aa04b8 100644 --- a/sc2/src/starcon2.c +++ b/sc2/src/starcon2.c @@ -44,21 +44,6 @@ // Including this is actually necessary on OSX. #endif -static void -CDToContentDir (char *contentdir) -{ - const char *testfile = "starcon.txt"; - - if (!fileExists (testfile)) - { - if ((chdir (contentdir) || !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); - } - } -} static int Check_PC_3DO_opt (const char *value, DWORD mask, const char *opt) @@ -322,11 +307,12 @@ main (int argc, char *argv[]) InitThreadSystem (); mem_init (); + initIO(); initTempDir(); - CDToContentDir (contentdir); - prepareConfigDir(); - prepareMeleeDir(); - prepareSaveDir(); + prepareContentDir (contentdir); + prepareConfigDir (); + prepareMeleeDir (); + prepareSaveDir (); InitTimeSystem (); InitTaskSystem (); @@ -350,6 +336,7 @@ main (int argc, char *argv[]) } unInitTempDir(); + uninitIO(); exit(EXIT_SUCCESS); }