diff --git a/.github/workflows/cpp-linter.yml b/.github/workflows/cpp-linter.yml index 006dc1ed6e..9f166e1027 100644 --- a/.github/workflows/cpp-linter.yml +++ b/.github/workflows/cpp-linter.yml @@ -42,6 +42,9 @@ jobs: ,clang-analyzer-* ,cppcoreguidelines-* ,-cppcoreguidelines-avoid-magic-numbers + ,-cppcoreguidelines-init-variables + ,-readability-identifier-length + ,-readability-isolate-declaration ,-readability-magic-numbers - name: Fail fast?! diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d7fefad519..46605afde1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,7 +90,6 @@ jobs: run: | brew install \ automake \ - dylibbundler \ sdl2 \ sdl2_mixer \ sdl2_net \ diff --git a/configure.ac b/configure.ac index 20df4620fc..b368790522 100644 --- a/configure.ac +++ b/configure.ac @@ -205,7 +205,7 @@ CFLAGS="$CFLAGS $SDL_CFLAGS ${SAMPLERATE_CFLAGS:-} ${PNG_CFLAGS:-} ${FLUIDSYNTH_ LDFLAGS="$LDFLAGS $SDL_LIBS ${SAMPLERATE_LIBS:-} ${PNG_LIBS:-} ${FLUIDSYNTH_LIBS:-} ${LIBZ_LIBS:-}" case "$host" in *-*-mingw* | *-*-cygwin* | *-*-msvc* ) - LDFLAGS="$LDFLAGS -lwinmm" + LDFLAGS="$LDFLAGS -lwinmm -lshlwapi" ;; *) esac diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index f15af6c286..2517de15c0 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -432,7 +432,7 @@ static void WriteRegister(unsigned int reg_num, unsigned int value) if ((value & 0x20) == 0) { - timer1.enabled = (value & 0x02) != 0; + timer2.enabled = (value & 0x02) != 0; OPLTimer_CalculateEndTime(&timer2); } } diff --git a/pkg/Makefile.am b/pkg/Makefile.am index 823851b8f0..3a287b2464 100644 --- a/pkg/Makefile.am +++ b/pkg/Makefile.am @@ -21,5 +21,5 @@ win32/GNUmakefile \ win32/cp-with-libs \ win32/README -EXTRA_DIST=$(OSX_FILES) $(WIN32_FILES) +EXTRA_DIST=style.html $(OSX_FILES) $(WIN32_FILES) diff --git a/pkg/osx/GNUmakefile b/pkg/osx/GNUmakefile index 94e20830f1..55d7ac8101 100644 --- a/pkg/osx/GNUmakefile +++ b/pkg/osx/GNUmakefile @@ -18,12 +18,6 @@ DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-$(POSTFIX).dmg TOPLEVEL=../.. TOPLEVEL_DOCS=$(patsubst %,../../%,$(DOC_FILES)) -ifeq (, $(shell which dylibbundler)) - CP=./cp-with-libs -else - CP=cp -endif - # DMG file containing package: $(DMG) : tmp.dmg @@ -75,26 +69,17 @@ $(STAGING_DIR): launcher $(TOPLEVEL_DOCS) app.icns wadfile.icns cp launcher "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/launcher" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)strife "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)strife "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)strife" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)setup" - -dylibbundler --bundle-deps --overwrite-files \ - --install-path "@executable_path/" \ - --dest-dir "$(APP_BIN_DIR)" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)strife" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)setup" - $(TOPLEVEL)/man/simplecpp -DPRECOMPILED -D__MACOSX__ \ -DDOOM -DHERETIC -DHEXEN -DSTRIFE \ < $(TOPLEVEL)/man/INSTALL.template \ diff --git a/pkg/osx/cp-with-libs b/pkg/osx/cp-with-libs index 04fb5bc6cb..f4869063f4 100755 --- a/pkg/osx/cp-with-libs +++ b/pkg/osx/cp-with-libs @@ -27,6 +27,9 @@ is_sys_lib() { /System/*) true ;; + /usr/local/*) # homebrew/manual install + false + ;; /usr/*) true ;; @@ -54,7 +57,7 @@ install_with_deps() { if [ -e "$dest_file" ]; then return - fi + fi echo "Installing $bin_name..." @@ -65,7 +68,6 @@ install_with_deps() { # Copy libraries that this file depends on: otool -L "$src_file" | tail -n +2 | sed 's/^.//; s/ (.*//' | while read; do - # Don't copy system libraries if is_sys_lib "$REPLY"; then @@ -92,6 +94,11 @@ install_with_deps() { if is_dylib "$dest_file"; then install_name_tool -id "@executable_path/$bin_name" "$dest_file" fi + + # The install_name_tool calls above break signatures. Recent versions + # of macOS make signatures mandatory, even if just ad-hoc ones. + codesign --remove-signature "$dest_file" + codesign --force -s - "$dest_file" # ad-hoc signature } # Install the file, and recursively install any libraries: diff --git a/pkg/style.html b/pkg/style.html new file mode 100644 index 0000000000..4ae291a3c1 --- /dev/null +++ b/pkg/style.html @@ -0,0 +1,48 @@ + + + + + diff --git a/pkg/win32/GNUmakefile b/pkg/win32/GNUmakefile index e8b69b36ab..0c0900f57a 100644 --- a/pkg/win32/GNUmakefile +++ b/pkg/win32/GNUmakefile @@ -9,6 +9,8 @@ else POSTFIX=win32 endif +PANDOC_FLAGS = -f gfm -s --template=default.html5 -H ../style.html + DOOM_ZIP=$(PROGRAM_PREFIX)doom-$(PACKAGE_VERSION)-$(POSTFIX).zip HERETIC_ZIP=$(PROGRAM_PREFIX)heretic-$(PACKAGE_VERSION)-$(POSTFIX).zip HEXEN_ZIP=$(PROGRAM_PREFIX)hexen-$(PACKAGE_VERSION)-$(POSTFIX).zip @@ -32,12 +34,12 @@ $(STRIFE_ZIP): staging-strife hook-strife # Special hooks to custom modify files for particular games. hook-doom: staging-doom - -pandoc -f gfm -s -o $ // @category compat // - // Emulate a specific version of Doom. Valid values are "1.2", - // "1.666", "1.7", "1.8", "1.9", "ultimate", "final", "final2", - // "hacx" and "chex". + // Emulate a specific version of Doom. Valid values are "1.2", + // "1.5", "1.666", "1.7", "1.8", "1.9", "ultimate", "final", + // "final2", "hacx" and "chex". // p = M_CheckParmWithArgs("-gameversion", 1); diff --git a/src/doom/p_enemy.c b/src/doom/p_enemy.c index ad5a62ab92..010b899157 100644 --- a/src/doom/p_enemy.c +++ b/src/doom/p_enemy.c @@ -180,7 +180,7 @@ boolean P_CheckMeleeRange (mobj_t* actor) pl = actor->target; dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y); - if (gameversion <= exe_doom_1_2) + if (gameversion < exe_doom_1_5) range = MELEERANGE; else range = MELEERANGE-20*FRACUNIT+pl->info->radius; @@ -958,7 +958,7 @@ void A_SargAttack (mobj_t* actor) A_FaceTarget (actor); - if (gameversion > exe_doom_1_2) + if (gameversion >= exe_doom_1_5) { if (!P_CheckMeleeRange (actor)) return; diff --git a/src/doom/p_inter.c b/src/doom/p_inter.c index 42ccc5e924..1198d7290b 100644 --- a/src/doom/p_inter.c +++ b/src/doom/p_inter.c @@ -979,7 +979,7 @@ P_DamageMobj target->reactiontime = 0; // we're awake now... if ( (!target->threshold || target->type == MT_VILE) - && source && (source != target || gameversion <= exe_doom_1_2) + && source && (source != target || gameversion < exe_doom_1_5) && source->type != MT_VILE) { // if not intent on another player, diff --git a/src/i_glob.c b/src/i_glob.c index 90c531076e..8b7612837b 100644 --- a/src/i_glob.c +++ b/src/i_glob.c @@ -24,8 +24,7 @@ #include "m_misc.h" #include "config.h" -#if defined(_MSC_VER) -// For Visual C++, we need to include the win_opendir module. +#if defined(_WIN32) #include #define S_ISDIR(m) (((m)& S_IFMT) == S_IFDIR) #elif defined(HAVE_DIRENT_H) @@ -102,7 +101,6 @@ glob_t *I_StartMultiGlob(const char *directory, int flags, int num_globs; glob_t *result; va_list args; - char *directory_native; globs = malloc(sizeof(char *)); if (globs == NULL) @@ -141,18 +139,15 @@ glob_t *I_StartMultiGlob(const char *directory, int flags, return NULL; } - directory_native = M_ConvertUtf8ToSysNativeMB(directory); - - result->dir = opendir(directory_native); + result->dir = opendir(directory); if (result->dir == NULL) { FreeStringList(globs, num_globs); free(result); - free(directory_native); return NULL; } - result->directory = directory_native; + result->directory = M_StringDuplicate(directory); result->globs = globs; result->num_globs = num_globs; result->flags = flags; @@ -246,7 +241,6 @@ static boolean MatchesAnyGlob(const char *name, glob_t *glob) static char *NextGlob(glob_t *glob) { struct dirent *de; - char *temp, *ret; do { @@ -259,13 +253,7 @@ static char *NextGlob(glob_t *glob) || !MatchesAnyGlob(de->d_name, glob)); // Return the fully-qualified path, not just the bare filename. - temp = M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL); - - ret = M_ConvertSysNativeMBToUtf8(temp); - - free(temp); - - return ret; + return M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL); } static void ReadAllFilenames(glob_t *glob) diff --git a/src/i_video.c b/src/i_video.c index 2e8a1baea7..8bd95b78ea 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -87,8 +87,6 @@ static SDL_Rect blit_rect = { }; #endif -static uint32_t pixel_format; - // palette #ifdef CRISPY_TRUECOLOR @@ -733,7 +731,7 @@ static void CreateUpscaledTexture(boolean force) SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); new_texture = SDL_CreateTexture(renderer, - pixel_format, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, w_upscale*SCREENWIDTH, h_upscale*SCREENHEIGHT); @@ -866,14 +864,16 @@ void I_FinishUpdate (void) } // Blit from the paletted 8-bit screen buffer to the intermediate - // 32-bit RGBA buffer that we can load into the texture. + // 32-bit RGBA buffer and update the intermediate texture with the + // contents of the RGBA buffer. + SDL_LockTexture(texture, &blit_rect, &argbbuffer->pixels, + &argbbuffer->pitch); SDL_LowerBlit(screenbuffer, &blit_rect, argbbuffer, &blit_rect); -#endif - - // Update the intermediate texture with the contents of the RGBA buffer. - + SDL_UnlockTexture(texture); +#else SDL_UpdateTexture(texture, NULL, argbbuffer->pixels, argbbuffer->pitch); +#endif // Make sure the pillarboxes are kept clear each frame. @@ -1005,6 +1005,7 @@ void I_SetPalette (byte *doompalette) // controller only supports 6 bits of accuracy. // [crispy] intermediate gamma levels + palette[i].a = 0xFFU; palette[i].r = gamma2table[crispy->gamma][*doompalette++] & ~3; palette[i].g = gamma2table[crispy->gamma][*doompalette++] & ~3; palette[i].b = gamma2table[crispy->gamma][*doompalette++] & ~3; @@ -1456,10 +1457,6 @@ static void SetVideoMode(void) { int w, h; int x, y; -#ifndef CRISPY_TRUECOLOR - unsigned int rmask, gmask, bmask, amask; -#endif - int bpp; int window_flags = 0, renderer_flags = 0; SDL_DisplayMode mode; @@ -1517,8 +1514,6 @@ static void SetVideoMode(void) SDL_GetError()); } - pixel_format = SDL_GetWindowPixelFormat(screen); - SDL_SetWindowMinimumSize(screen, SCREENWIDTH, actualheight); I_InitWindowTitle(); @@ -1635,12 +1630,10 @@ static void SetVideoMode(void) if (argbbuffer == NULL) { - SDL_PixelFormatEnumToMasks(pixel_format, &bpp, - &rmask, &gmask, &bmask, &amask); - argbbuffer = SDL_CreateRGBSurface(0, - SCREENWIDTH, SCREENHEIGHT, bpp, - rmask, gmask, bmask, amask); #ifdef CRISPY_TRUECOLOR + argbbuffer = SDL_CreateRGBSurfaceWithFormat( + 0, SCREENWIDTH, SCREENHEIGHT, 32, SDL_PIXELFORMAT_ARGB8888); + SDL_FillRect(argbbuffer, NULL, I_MapRGB(0xff, 0x0, 0x0)); redpane = SDL_CreateTextureFromSurface(renderer, argbbuffer); SDL_SetTextureBlendMode(redpane, SDL_BLENDMODE_BLEND); @@ -1668,8 +1661,12 @@ static void SetVideoMode(void) SDL_FillRect(argbbuffer, NULL, I_MapRGB(0x96, 0x6e, 0x0)); // 150, 110, 0 orngpane = SDL_CreateTextureFromSurface(renderer, argbbuffer); SDL_SetTextureBlendMode(orngpane, SDL_BLENDMODE_BLEND); +#else + // pixels and pitch will be filled with the texture's values + // in I_FinishUpdate() + argbbuffer = SDL_CreateRGBSurfaceWithFormatFrom( + NULL, w, h, 0, 0, SDL_PIXELFORMAT_ARGB8888); #endif - SDL_FillRect(argbbuffer, NULL, 0); } if (texture != NULL) @@ -1688,7 +1685,7 @@ static void SetVideoMode(void) // is going to change frequently. texture = SDL_CreateTexture(renderer, - pixel_format, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREENWIDTH, SCREENHEIGHT); @@ -1898,9 +1895,6 @@ void I_ReInitGraphics (int reinit) // [crispy] re-set rendering resolution and re-create framebuffers if (reinit & REINIT_FRAMEBUFFERS) { - unsigned int rmask, gmask, bmask, amask; - int unused_bpp; - I_GetScreenDimensions(); #ifndef CRISPY_TRUECOLOR @@ -1919,11 +1913,9 @@ void I_ReInitGraphics (int reinit) #endif SDL_FreeSurface(argbbuffer); - SDL_PixelFormatEnumToMasks(pixel_format, &unused_bpp, - &rmask, &gmask, &bmask, &amask); - argbbuffer = SDL_CreateRGBSurface(0, - SCREENWIDTH, SCREENHEIGHT, 32, - rmask, gmask, bmask, amask); + argbbuffer = SDL_CreateRGBSurfaceWithFormat(0, + SCREENWIDTH, SCREENHEIGHT, 32, + SDL_PIXELFORMAT_ARGB8888); #ifndef CRISPY_TRUECOLOR // [crispy] re-set the framebuffer pointer I_VideoBuffer = screenbuffer->pixels; @@ -1968,7 +1960,7 @@ void I_ReInitGraphics (int reinit) SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); texture = SDL_CreateTexture(renderer, - pixel_format, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREENWIDTH, SCREENHEIGHT); diff --git a/src/m_misc.c b/src/m_misc.c index ea531ea3ac..28882d0b03 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -28,23 +28,15 @@ #define WIN32_LEAN_AND_MEAN #include #include -#ifdef _MSC_VER #include -#endif #else #include #endif #include "doomtype.h" -#include "deh_str.h" - -#include "i_swap.h" #include "i_system.h" -#include "i_video.h" #include "m_misc.h" -#include "v_video.h" -#include "w_wad.h" #include "z_zone.h" #ifdef _WIN32 @@ -122,16 +114,6 @@ char *M_ConvertWideToUtf8(const wchar_t *wstr) return ConvertWideToMultiByte(wstr, CP_UTF8); } -static wchar_t *ConvertSysNativeMBToWide(const char *str) -{ - return ConvertMultiByteToWide(str, CP_ACP); -} - -static char *ConvertWideToSysNativeMB(const wchar_t *wstr) -{ - return ConvertWideToMultiByte(wstr, CP_ACP); -} - // Convert UTF8 string to a wide string. The result is newly allocated and must // be freed by the caller after use. @@ -141,58 +123,6 @@ wchar_t *M_ConvertUtf8ToWide(const char *str) } #endif -// Convert multibyte string in system encoding to UTF8. The result is newly -// allocated and must be freed by the caller after use. - -char *M_ConvertSysNativeMBToUtf8(const char *str) -{ -#ifdef _WIN32 - char *ret = NULL; - wchar_t *wstr = NULL; - - wstr = ConvertSysNativeMBToWide(str); - - if (!wstr) - { - return NULL; - } - - ret = M_ConvertWideToUtf8(wstr); - - free(wstr); - - return ret; -#else - return M_StringDuplicate(str); -#endif -} - -// Convert UTF8 string to multibyte string in system encoding. The result is -// newly allocated and must be freed by the caller after use. - -char *M_ConvertUtf8ToSysNativeMB(const char *str) -{ -#ifdef _WIN32 - char *ret = NULL; - wchar_t *wstr = NULL; - - wstr = M_ConvertUtf8ToWide(str); - - if (!wstr) - { - return NULL; - } - - ret = ConvertWideToSysNativeMB(wstr); - - free(wstr); - - return ret; -#else - return M_StringDuplicate(str); -#endif -} - FILE *M_fopen(const char *filename, const char *mode) { #ifdef _WIN32 diff --git a/src/m_misc.h b/src/m_misc.h index 7b9e72cc33..6dc18ccfa3 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -30,8 +30,6 @@ wchar_t *M_ConvertUtf8ToWide(const char *str); char *M_ConvertWideToUtf8(const wchar_t *wstr); #endif -char *M_ConvertUtf8ToSysNativeMB(const char *str); -char *M_ConvertSysNativeMBToUtf8(const char *str); FILE *M_fopen(const char *filename, const char *mode); int M_remove(const char *path); diff --git a/src/net_server.c b/src/net_server.c index 42ab0d9f6c..9374b64ec7 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -383,11 +383,35 @@ static net_client_t *NET_SV_Controller(void) return best; } +typedef enum +{ + RANGE_LOCALHOST, // Same process or 127.x + RANGE_PRIVATE, // RFC 1918 + RANGE_PUBLIC, // The public Internet +} ip_range_t; + +static ip_range_t ClientAddressRange(const char *addr) +{ + if (!strcmp(addr, "local client") + || M_StringStartsWith(addr, "127.")) + { + return RANGE_LOCALHOST; + } + if (M_StringStartsWith(addr, "10.") + || M_StringStartsWith(addr, "192.168.")) + { + return RANGE_PRIVATE; + } + return RANGE_PUBLIC; +} + static void NET_SV_SendWaitingData(net_client_t *client) { net_waitdata_t wait_data; net_packet_t *packet; net_client_t *controller; + ip_range_t client_range, player_range; + const char *addr; int i; NET_SV_AssignPlayers(); @@ -416,6 +440,11 @@ static void NET_SV_SendWaitingData(net_client_t *client) sizeof(sha1_digest_t)); wait_data.is_freedoom = controller->is_freedoom; + // We only send IP addresses to locally-connected clients (including + // the 127.* loopback range): + addr = NET_AddrToString(client->connection.addr); + client_range = ClientAddressRange(addr); + // set name and address of each player: for (i = 0; i < wait_data.num_players; ++i) @@ -423,9 +452,28 @@ static void NET_SV_SendWaitingData(net_client_t *client) M_StringCopy(wait_data.player_names[i], sv_players[i]->name, MAXPLAYERNAME); - M_StringCopy(wait_data.player_addrs[i], - NET_AddrToString(sv_players[i]->addr), - MAXPLAYERNAME); + + // For privacy, only local clients or those on a LAN get to see + // addresses. Public clients only get to see their own address, + // though we do reveal localhost addresses since they're harmless, + // and we do reveal when a client is connected via LAN. + addr = NET_AddrToString(sv_players[i]->addr); + player_range = ClientAddressRange(addr); + if (client_range == RANGE_LOCALHOST || client_range == RANGE_PRIVATE + || i == wait_data.consoleplayer || player_range == RANGE_LOCALHOST) + { + M_StringCopy(wait_data.player_addrs[i], addr, MAXPLAYERNAME); + } + else if (player_range == RANGE_PRIVATE) + { + M_snprintf(wait_data.player_addrs[i], MAXPLAYERNAME, + "[LAN player]"); + } + else + { + M_snprintf(wait_data.player_addrs[i], MAXPLAYERNAME, + "[address hidden]"); + } } // Construct packet: diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c index 42480f4869..eed6167676 100644 --- a/textscreen/txt_sdl.c +++ b/textscreen/txt_sdl.c @@ -88,21 +88,21 @@ static const short code_page_to_unicode[] = CODE_PAGE_TO_UNICODE; static const SDL_Color ega_colors[] = { {0x00, 0x00, 0x00, 0xff}, // 0: Black - {0x00, 0x00, 0xa8, 0xff}, // 1: Blue - {0x00, 0xa8, 0x00, 0xff}, // 2: Green - {0x00, 0xa8, 0xa8, 0xff}, // 3: Cyan - {0xa8, 0x00, 0x00, 0xff}, // 4: Red - {0xa8, 0x00, 0xa8, 0xff}, // 5: Magenta - {0xa8, 0x54, 0x00, 0xff}, // 6: Brown - {0xa8, 0xa8, 0xa8, 0xff}, // 7: Grey - {0x54, 0x54, 0x54, 0xff}, // 8: Dark grey - {0x54, 0x54, 0xfe, 0xff}, // 9: Bright blue - {0x54, 0xfe, 0x54, 0xff}, // 10: Bright green - {0x54, 0xfe, 0xfe, 0xff}, // 11: Bright cyan - {0xfe, 0x54, 0x54, 0xff}, // 12: Bright red - {0xfe, 0x54, 0xfe, 0xff}, // 13: Bright magenta - {0xfe, 0xfe, 0x54, 0xff}, // 14: Yellow - {0xfe, 0xfe, 0xfe, 0xff}, // 15: Bright white + {0x00, 0x00, 0xaa, 0xff}, // 1: Blue + {0x00, 0xaa, 0x00, 0xff}, // 2: Green + {0x00, 0xaa, 0xaa, 0xff}, // 3: Cyan + {0xaa, 0x00, 0x00, 0xff}, // 4: Red + {0xaa, 0x00, 0xaa, 0xff}, // 5: Magenta + {0xaa, 0x55, 0x00, 0xff}, // 6: Brown + {0xaa, 0xaa, 0xaa, 0xff}, // 7: Grey + {0x55, 0x55, 0x55, 0xff}, // 8: Dark grey + {0x55, 0x55, 0xff, 0xff}, // 9: Bright blue + {0x55, 0xff, 0x55, 0xff}, // 10: Bright green + {0x55, 0xff, 0xff, 0xff}, // 11: Bright cyan + {0xff, 0x55, 0x55, 0xff}, // 12: Bright red + {0xff, 0x55, 0xff, 0xff}, // 13: Bright magenta + {0xff, 0xff, 0x55, 0xff}, // 14: Yellow + {0xff, 0xff, 0xff, 0xff}, // 15: Bright white }; #ifdef _WIN32 diff --git a/win32/win_opendir.c b/win32/win_opendir.c index b2f67805fc..a03489c9cc 100644 --- a/win32/win_opendir.c +++ b/win32/win_opendir.c @@ -1,336 +1,425 @@ -// -// 03/10/2006 James Haley -// -// For this module only: -// This code is public domain. No change sufficient enough to constitute a -// significant or original work has been made, and thus it remains as such. -// -// -// DESCRIPTION: -// -// Implementation of POSIX opendir for Visual C++. -// Derived from the MinGW C Library Extensions Source (released to the -// public domain). As with other Win32 modules, don't include most DOOM -// headers into this or conflicts will occur. -// -// Original Header: -// -// * dirent.c -// * This file has no copyright assigned and is placed in the Public Domain. -// * This file is a part of the mingw-runtime package. -// * No warranty is given; refer to the file DISCLAIMER within the package. -// * -// * Derived from DIRLIB.C by Matt J. Weinstein -// * This note appears in the DIRLIB.H -// * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 -// * -// * Updated by Jeremy Bettis -// * Significantly revised and rewinddir, seekdir and telldir added by Colin -// * Peters -// - -#ifndef _MSC_VER -#error i_opndir.c is for Microsoft Visual C++ only -#endif +/* +MIT License +Copyright (c) 2019 win32ports +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifdef _WIN32 + +#include "win_opendir.h" -#include +#include #include -#include #define WIN32_LEAN_AND_MEAN -#include /* for GetFileAttributes */ +#include +#include -#include -#define SUFFIX _T("*") -#define SLASH _T("\\") +#ifdef _MSC_VER +#pragma comment(lib, "Shlwapi.lib") +#endif -#include "win_opendir.h" +#ifndef NTFS_MAX_PATH +#define NTFS_MAX_PATH 32768 +#endif /* NTFS_MAX_PATH */ + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif /* FSCTL_GET_REPARSE_POINT */ + +#ifndef FILE_NAME_NORMALIZED +#define FILE_NAME_NORMALIZED 0 +#endif /* FILE_NAME_NORMALIZED */ -// -// opendir -// -// Returns a pointer to a DIR structure appropriately filled in to begin -// searching a directory. -// -DIR *opendir(const _TCHAR *szPath) +int closedir(DIR *dirp) { - DIR *nd; - unsigned int rc; - _TCHAR szFullPath[MAX_PATH]; - - errno = 0; - - if(!szPath) - { - errno = EFAULT; - return (DIR *)0; - } - - if(szPath[0] == _T('\0')) - { - errno = ENOTDIR; - return (DIR *)0; - } - - /* Attempt to determine if the given path really is a directory. */ - rc = GetFileAttributes(szPath); - if(rc == (unsigned int)-1) - { - /* call GetLastError for more error info */ - errno = ENOENT; - return (DIR *)0; - } - if(!(rc & FILE_ATTRIBUTE_DIRECTORY)) - { - /* Error, entry exists but not a directory. */ - errno = ENOTDIR; - return (DIR *)0; - } - - /* Make an absolute pathname. */ - _tfullpath(szFullPath, szPath, MAX_PATH); - - /* Allocate enough space to store DIR structure and the complete - * directory path given. */ - nd = (DIR *)(malloc(sizeof(DIR) + (_tcslen(szFullPath) - + _tcslen(SLASH) - + _tcslen(SUFFIX) + 1) - * sizeof(_TCHAR))); - - if(!nd) - { - /* Error, out of memory. */ - errno = ENOMEM; - return (DIR *)0; - } - - /* Create the search expression. */ - _tcscpy(nd->dd_name, szFullPath); - - /* Add on a slash if the path does not end with one. */ - if(nd->dd_name[0] != _T('\0') - && _tcsrchr(nd->dd_name, _T('/')) != nd->dd_name - + _tcslen(nd->dd_name) - 1 - && _tcsrchr(nd->dd_name, _T('\\')) != nd->dd_name - + _tcslen(nd->dd_name) - 1) - { - _tcscat(nd->dd_name, SLASH); - } - - /* Add on the search pattern */ - _tcscat(nd->dd_name, SUFFIX); - - /* Initialize handle to -1 so that a premature closedir doesn't try - * to call _findclose on it. */ - nd->dd_handle = -1; - - /* Initialize the status. */ - nd->dd_stat = 0; - - /* Initialize the dirent structure. ino and reclen are invalid under - * Win32, and name simply points at the appropriate part of the - * findfirst_t structure. */ - nd->dd_dir.d_ino = 0; - nd->dd_dir.d_reclen = 0; - nd->dd_dir.d_namlen = 0; - memset(nd->dd_dir.d_name, 0, FILENAME_MAX); - - return nd; + struct __dir *data = NULL; + if (!dirp) + { + errno = EBADF; + return -1; + } + data = (struct __dir *) dirp; + CloseHandle((HANDLE) data->fd); + free(data->entries); + free(data); + return 0; } -// -// readdir -// -// Return a pointer to a dirent structure filled with the information on the -// next entry in the directory. -// -struct dirent *readdir(DIR *dirp) +static void __seterrno(int value) { - errno = 0; - - /* Check for valid DIR struct. */ - if(!dirp) - { - errno = EFAULT; - return (struct dirent *)0; - } - - if (dirp->dd_stat < 0) - { - /* We have already returned all files in the directory - * (or the structure has an invalid dd_stat). */ - return (struct dirent *)0; - } - else if (dirp->dd_stat == 0) - { - /* We haven't started the search yet. */ - /* Start the search */ - dirp->dd_handle = _tfindfirst(dirp->dd_name, &(dirp->dd_dta)); - - if(dirp->dd_handle == -1) - { - /* Whoops! Seems there are no files in that - * directory. */ - dirp->dd_stat = -1; - } - else - { - dirp->dd_stat = 1; - } - } - else - { - /* Get the next search entry. */ - if(_tfindnext(dirp->dd_handle, &(dirp->dd_dta))) - { - /* We are off the end or otherwise error. - _findnext sets errno to ENOENT if no more file - Undo this. */ - DWORD winerr = GetLastError(); - if(winerr == ERROR_NO_MORE_FILES) - errno = 0; - _findclose(dirp->dd_handle); - dirp->dd_handle = -1; - dirp->dd_stat = -1; - } - else - { - /* Update the status to indicate the correct - * number. */ - dirp->dd_stat++; - } - } - - if (dirp->dd_stat > 0) - { - /* Successfully got an entry. Everything about the file is - * already appropriately filled in except the length of the - * file name. */ - dirp->dd_dir.d_namlen = _tcslen(dirp->dd_dta.name); - _tcscpy(dirp->dd_dir.d_name, dirp->dd_dta.name); - return &dirp->dd_dir; - } - - return (struct dirent *)0; +#ifdef _MSC_VER + _set_errno(value); +#else /* _MSC_VER */ + errno = value; +#endif /* _MSC_VER */ } +static int __islink(const wchar_t *name, char *buffer) +{ + DWORD io_result = 0; + DWORD bytes_returned = 0; + HANDLE hFile = CreateFileW( + name, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); + if (hFile == INVALID_HANDLE_VALUE) + { + return 0; + } -// -// closedir -// -// Frees up resources allocated by opendir. -// -int closedir(DIR *dirp) + io_result = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &bytes_returned, NULL); + + CloseHandle(hFile); + + if (io_result == 0) + { + return 0; + } + + return ((REPARSE_GUID_DATA_BUFFER *) buffer)->ReparseTag == + IO_REPARSE_TAG_SYMLINK; +} + +#pragma pack(push, 1) + +typedef struct dirent_FILE_ID_128 +{ + BYTE Identifier[16]; +} dirent_FILE_ID_128; + +typedef struct _dirent_FILE_ID_INFO +{ + ULONGLONG VolumeSerialNumber; + dirent_FILE_ID_128 FileId; +} dirent_FILE_ID_INFO; + +#pragma pack(pop) + +typedef enum dirent_FILE_INFO_BY_HANDLE_CLASS +{ + dirent_FileIdInfo = 18 +} dirent_FILE_INFO_BY_HANDLE_CLASS; + +static __ino_t __inode(const wchar_t *name) { - int rc; - - errno = 0; - rc = 0; - - if(!dirp) - { - errno = EFAULT; - return -1; - } - - if(dirp->dd_handle != -1) - { - rc = _findclose(dirp->dd_handle); - } - - /* Delete the dir structure. */ - free(dirp); - - return rc; + __ino_t value = {0}; + BOOL result; + dirent_FILE_ID_INFO fileid; + BY_HANDLE_FILE_INFORMATION info; + typedef BOOL(__stdcall * pfnGetFileInformationByHandleEx)( + HANDLE hFile, dirent_FILE_INFO_BY_HANDLE_CLASS FileInformationClass, + LPVOID lpFileInformation, DWORD dwBufferSize); + + HANDLE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!hKernel32) + { + return value; + } + + pfnGetFileInformationByHandleEx fnGetFileInformationByHandleEx = + (pfnGetFileInformationByHandleEx) GetProcAddress( + hKernel32, "GetFileInformationByHandleEx"); + if (!fnGetFileInformationByHandleEx) + { + return value; + } + + HANDLE hFile = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, 0); + if (hFile == INVALID_HANDLE_VALUE) + { + return value; + } + + result = fnGetFileInformationByHandleEx(hFile, dirent_FileIdInfo, &fileid, + sizeof(fileid)); + if (result) + { + value.serial = fileid.VolumeSerialNumber; + memcpy(value.fileid, fileid.FileId.Identifier, 16); + } + else + { + result = GetFileInformationByHandle(hFile, &info); + if (result) + { + value.serial = info.dwVolumeSerialNumber; + memcpy(value.fileid + 8, &info.nFileIndexHigh, 4); + memcpy(value.fileid + 12, &info.nFileIndexLow, 4); + } + } + CloseHandle(hFile); + return value; } -// -// rewinddir -// -// Return to the beginning of the directory "stream". We simply call findclose -// and then reset things like an opendir. -// -void rewinddir(DIR * dirp) +static DIR *__internal_opendir(wchar_t *wname, int size) { - errno = 0; - - if(!dirp) - { - errno = EFAULT; - return; - } - - if(dirp->dd_handle != -1) - { - _findclose(dirp->dd_handle); - } - - dirp->dd_handle = -1; - dirp->dd_stat = 0; + struct __dir *data = NULL; + struct dirent *tmp_entries = NULL; + static char default_char = '?'; + static wchar_t *prefix = L"\\\\?\\"; + static wchar_t *suffix = L"\\*.*"; + static int extra_prefix = 4; /* use prefix "\\?\" to handle long file names */ + static int extra_suffix = 4; /* use suffix "\*.*" to find everything */ + WIN32_FIND_DATAW w32fd = {0}; + HANDLE hFindFile = INVALID_HANDLE_VALUE; + static int grow_factor = 2; + char *buffer = NULL; + + BOOL relative = PathIsRelativeW(wname + extra_prefix); + + memcpy(wname + size - 1, suffix, sizeof(wchar_t) * extra_suffix); + wname[size + extra_suffix - 1] = 0; + + if (relative) + { + wname += extra_prefix; + size -= extra_prefix; + } + hFindFile = FindFirstFileW(wname, &w32fd); + if (INVALID_HANDLE_VALUE == hFindFile) + { + __seterrno(ENOENT); + return NULL; + } + + data = (struct __dir *) malloc(sizeof(struct __dir)); + if (!data) + { + goto out_of_memory; + } + wname[size - 1] = 0; + data->fd = (intptr_t) CreateFileW(wname, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, 0); + wname[size - 1] = L'\\'; + data->count = 16; + data->index = 0; + data->entries = (struct dirent *) malloc(sizeof(struct dirent) * data->count); + if (!data->entries) + { + goto out_of_memory; + } + buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (!buffer) + { + goto out_of_memory; + } + + do + { + WideCharToMultiByte(CP_UTF8, 0, w32fd.cFileName, -1, + data->entries[data->index].d_name, NAME_MAX, + &default_char, NULL); + + memcpy(wname + size, w32fd.cFileName, sizeof(wchar_t) * NAME_MAX); + + if (((w32fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == + FILE_ATTRIBUTE_REPARSE_POINT) + && __islink(wname, buffer)) + { + data->entries[data->index].d_type = DT_LNK; + } + else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) == + FILE_ATTRIBUTE_DEVICE) + { + data->entries[data->index].d_type = DT_CHR; + } + else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == + FILE_ATTRIBUTE_DIRECTORY) + { + data->entries[data->index].d_type = DT_DIR; + } + else + { + data->entries[data->index].d_type = DT_REG; + } + + data->entries[data->index].d_ino = __inode(wname); + data->entries[data->index].d_reclen = sizeof(struct dirent); + data->entries[data->index].d_namelen = + (unsigned char) wcslen(w32fd.cFileName); + data->entries[data->index].d_off = 0; + + if (++data->index == data->count) + { + tmp_entries = (struct dirent *) realloc( + data->entries, + sizeof(struct dirent) * data->count * grow_factor); + if (!tmp_entries) + { + goto out_of_memory; + } + data->entries = tmp_entries; + data->count *= grow_factor; + } + } while (FindNextFileW(hFindFile, &w32fd) != 0); + + free(buffer); + FindClose(hFindFile); + + data->count = data->index; + data->index = 0; + return (DIR *) data; + +out_of_memory: + if (data) + { + if (INVALID_HANDLE_VALUE != (HANDLE) data->fd) + { + CloseHandle((HANDLE) data->fd); + } + free(data->entries); + } + free(buffer); + free(data); + if (INVALID_HANDLE_VALUE != hFindFile) + { + FindClose(hFindFile); + } + __seterrno(ENOMEM); + return NULL; +} + +static wchar_t *__get_buffer() +{ + wchar_t *name = malloc(sizeof(wchar_t) * (NTFS_MAX_PATH + NAME_MAX + 8)); + if (name) + { + memcpy(name, L"\\\\?\\", sizeof(wchar_t) * 4); + } + return name; } -// -// telldir -// -// Returns the "position" in the "directory stream" which can be used with -// seekdir to go back to an old entry. We simply return the value in stat. -// -long telldir(DIR *dirp) +DIR *opendir(const char *name) { - errno = 0; - - if(!dirp) - { - errno = EFAULT; - return -1; - } - return dirp->dd_stat; + DIR *dirp = NULL; + wchar_t *wname = __get_buffer(); + int size = 0; + if (!wname) + { + errno = ENOMEM; + return NULL; + } + size = MultiByteToWideChar(CP_UTF8, 0, name, -1, wname + 4, NTFS_MAX_PATH); + if (0 == size) + { + free(wname); + return NULL; + } + dirp = __internal_opendir(wname, size + 4); + free(wname); + return dirp; } -// -// seekdir -// -// Seek to an entry previously returned by telldir. We rewind the directory -// and call readdir repeatedly until either dd_stat is the position number -// or -1 (off the end). This is not perfect, in that the directory may -// have changed while we weren't looking. But that is probably the case with -// any such system. -// -void seekdir(DIR *dirp, long lPos) +DIR *_wopendir(const wchar_t *name) { - errno = 0; - - if(!dirp) - { - errno = EFAULT; - return; - } - - if(lPos < -1) - { - /* Seeking to an invalid position. */ - errno = EINVAL; - return; - } - else if(lPos == -1) - { - /* Seek past end. */ - if(dirp->dd_handle != -1) - { - _findclose(dirp->dd_handle); - } - dirp->dd_handle = -1; - dirp->dd_stat = -1; - } - else - { - /* Rewind and read forward to the appropriate index. */ - rewinddir(dirp); - - while((dirp->dd_stat < lPos) && readdir(dirp)) - ; /* do-nothing loop */ - } + DIR *dirp = NULL; + wchar_t *wname = __get_buffer(); + int size = 0; + if (!wname) + { + errno = ENOMEM; + return NULL; + } + size = (int) wcslen(name); + if (size > NTFS_MAX_PATH) + { + free(wname); + return NULL; + } + memcpy(wname + 4, name, sizeof(wchar_t) * (size + 1)); + dirp = __internal_opendir(wname, size + 5); + free(wname); + return dirp; +} + +DIR *fdopendir(intptr_t fd) +{ + DIR *dirp = NULL; + wchar_t *wname = __get_buffer(); + int size = 0; + + if (!wname) + { + errno = ENOMEM; + return NULL; + } + size = GetFinalPathNameByHandleW((HANDLE) fd, wname + 4, NTFS_MAX_PATH, + FILE_NAME_NORMALIZED); + if (0 == size) + { + free(wname); + errno = ENOTDIR; + return NULL; + } + dirp = __internal_opendir(wname, size + 5); + free(wname); + return dirp; } -// EOF +struct dirent *readdir(DIR *dirp) +{ + struct __dir *data = (struct __dir *) dirp; + if (!data) + { + errno = EBADF; + return NULL; + } + if (data->index < data->count) + { + return &data->entries[data->index++]; + } + return NULL; +} + +void seekdir(DIR *dirp, long int offset) +{ + if (dirp) + { + struct __dir *data = (struct __dir *) dirp; + data->index = (offset < data->count) ? offset : data->index; + } +} + +void rewinddir(DIR *dirp) +{ + seekdir(dirp, 0); +} + +long int telldir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return -1; + } + return ((struct __dir *) dirp)->count; +} + +intptr_t dirfd(DIR *dirp) +{ + if (!dirp) + { + errno = EINVAL; + return -1; + } + return ((struct __dir *) dirp)->fd; +} +#endif /* _WIN32 */ diff --git a/win32/win_opendir.h b/win32/win_opendir.h index c1844e115e..94c9d2c848 100644 --- a/win32/win_opendir.h +++ b/win32/win_opendir.h @@ -1,73 +1,130 @@ -// -// 03/10/2006 James Haley -// -// For this module only: -// This code is public domain. No change sufficient enough to constitute a -// significant or original work has been made, and thus it remains as such. -// -// -// DESCRIPTION: -// -// Implementation of POSIX opendir for Visual C++. -// Derived from the MinGW C Library Extensions Source (released to the -// public domain). -// - -#ifndef I_OPNDIR_H__ -#define I_OPNDIR_H__ - -#include - -#ifndef FILENAME_MAX -#define FILENAME_MAX 260 -#endif +/* +MIT License +Copyright (c) 2019 win32ports +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifdef _WIN32 + +#ifndef WIN_OPENDIR_H +#define WIN_OPENDIR_H + +#include + +#ifndef NAME_MAX +#define NAME_MAX 260 +#endif /* NAME_MAX */ + +#ifndef DT_UNKNOWN +#define DT_UNKNOWN 0 +#endif /* DT_UNKNOWN */ + +#ifndef DT_FIFO +#define DT_FIFO 1 +#endif /* DT_FIFO */ + +#ifndef DT_CHR +#define DT_CHR 2 +#endif /* DT_CHR */ + +#ifndef DT_DIR +#define DT_DIR 4 +#endif /* DT_DIR */ + +#ifndef DT_BLK +#define DT_BLK 6 +#endif /* DT_BLK */ + +#ifndef DT_REG +#define DT_REG 8 +#endif /* DT_REF */ + +#ifndef DT_LNK +#define DT_LNK 10 +#endif /* DT_LNK */ + +#ifndef DT_SOCK +#define DT_SOCK 12 +#endif /* DT_SOCK */ + +#ifndef DT_WHT +#define DT_WHT 14 +#endif /* DT_WHT */ + +#ifndef _DIRENT_HAVE_D_NAMLEN +#define _DIRENT_HAVE_D_NAMLEN 1 +#endif /* _DIRENT_HAVE_D_NAMLEN */ + +#ifndef _DIRENT_HAVE_D_RECLEN +#define _DIRENT_HAVE_D_RECLEN 1 +#endif /* _DIRENT_HAVE_D_RECLEN */ + +#ifndef _DIRENT_HAVE_D_OFF +#define _DIRENT_HAVE_D_OFF 1 +#endif /* _DIRENT_HAVE_D_OFF */ + +#ifndef _DIRENT_HAVE_D_TYPE +#define _DIRENT_HAVE_D_TYPE 1 +#endif /* _DIRENT_HAVE_D_TYPE */ + +typedef void *DIR; + +typedef struct ino_t +{ + unsigned long long serial; + unsigned char fileid[16]; +} __ino_t; struct dirent { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char d_name[FILENAME_MAX]; /* File name. */ + __ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_namelen; + unsigned char d_type; + char d_name[NAME_MAX]; }; -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ -typedef struct +struct __dir { - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; + struct dirent *entries; + intptr_t fd; + long int count; + long int index; +}; + +int closedir(DIR *dirp); + +DIR *opendir(const char *name); + +DIR *_wopendir(const wchar_t *name); - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; +DIR *fdopendir(intptr_t fd); - /* _findnext handle */ - intptr_t dd_handle; +struct dirent *readdir(DIR *dirp); - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; +void seekdir(DIR *dirp, long int offset); - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; -} DIR; +void rewinddir(DIR *dirp); -DIR *opendir(const char *); -struct dirent *readdir(DIR *); -int closedir(DIR *); -void rewinddir(DIR *); -long telldir(DIR *); -void seekdir(DIR *, long); +long int telldir(DIR *dirp); -#endif +intptr_t dirfd(DIR *dirp); -// EOF +#endif /* WIN_OPENDIR_H */ +#endif /* _WIN32 */