├── .github └── workflows │ └── libdirtrav.yml ├── CMakeLists.txt ├── Changelog.txt ├── LICENSE ├── Makefile ├── README.md ├── build ├── folderstats.cbp ├── folderstats.depend ├── libdirtrav.workspace ├── libdirtrav_nowin_shared.cbp ├── libdirtrav_nowin_shared.depend ├── libdirtrav_nowin_static.cbp ├── libdirtrav_nowin_static.depend ├── libdirtrav_shared.cbp ├── libdirtrav_shared.depend ├── libdirtrav_static.cbp ├── libdirtrav_static.depend ├── libdirtravw_nowin_shared.cbp ├── libdirtravw_nowin_shared.depend ├── libdirtravw_nowin_static.cbp ├── libdirtravw_nowin_static.depend ├── libdirtravw_shared.cbp ├── libdirtravw_shared.depend ├── libdirtravw_static.cbp ├── libdirtravw_static.depend ├── rdir.cbp ├── rdir.depend ├── rdirw.cbp ├── rdirw.depend ├── test1.cbp ├── test1.depend ├── test2.cbp ├── test2.depend ├── test3.cbp ├── test3.depend ├── test3w.cbp ├── test3w.depend ├── tree.cbp ├── tree.depend ├── treew.cbp └── treew.depend ├── doc └── Doxyfile ├── include ├── dirtrav.h ├── dirtrav_version.h └── dirtravw.h ├── src ├── dirtrav.c ├── folderstats.c ├── rdir.c ├── test1.c ├── test2.c ├── test3.c └── tree.c └── test ├── test1.c ├── test2.c └── tree.c /.github/workflows/libdirtrav.yml: -------------------------------------------------------------------------------- 1 | name: GitHub-CI for libdirtrav 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | name: ${{ matrix.config.name }} 12 | runs-on: ${{ matrix.config.os }} 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | config: 17 | # - { 18 | # name: "Windows MSVC", artifact: "Windows-MSVC.tar.xz", 19 | # os: windows-latest, 20 | # cc: "cl", cxx: "cl", 21 | # environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat" 22 | # } 23 | - { 24 | name: "Windows MinGW", artifact: "Windows-MinGW.tar.bz2", 25 | os: windows-latest, 26 | cc: "gcc", cxx: "g++", 27 | makeflags: "BUILD_WIDE=1" 28 | } 29 | - { 30 | name: "Ubuntu GCC", artifact: "Linux.tar.bz2", 31 | os: ubuntu-latest, 32 | cc: "gcc", cxx: "g++" 33 | } 34 | - { 35 | name: "macOS Clang", artifact: "macOS.tar.bz2", 36 | os: macos-latest, 37 | cc: "clang", cxx: "clang++" 38 | } 39 | steps: 40 | - uses: actions/checkout@v1 41 | - name: Compile, install, package 42 | run: | 43 | make install PREFIX=build_result DOXYGEN= CC=${{ matrix.config.cc }} ${{ matrix.config.makeflags }} 44 | tar cfj ./${{ matrix.config.artifact }} --strip-components=1 build_result 45 | - name: Pack 46 | run: | 47 | tar cfj ./${{ matrix.config.artifact }} --strip-components=1 build_result 48 | - name: Upload 49 | uses: actions/upload-artifact@v1 50 | with: 51 | path: ./${{ matrix.config.artifact }} 52 | name: ${{ matrix.config.artifact }} 53 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | PROJECT(libdirtrav) 3 | 4 | # parameters 5 | OPTION(BUILD_STATIC "Build static libraries" ON) 6 | OPTION(BUILD_SHARED "Build shared libraries" ON) 7 | OPTION(BUILD_TOOLS "Build tools" ON) 8 | IF(WIN32) 9 | OPTION(WITH_WIDE "Also build UTF-16 library (libdirtravw)" OFF) 10 | OPTION(FORCE_OPENDIR "Force using opendir() instead of Windows API" OFF) 11 | ELSE() 12 | SET(WITH_WIDE OFF) 13 | ENDIF() 14 | 15 | # conditions 16 | IF(NOT BUILD_STATIC AND NOT BUILD_SHARED) 17 | MESSAGE(FATAL_ERROR "Cannot build with both BUILD_STATIC and BUILD_SHARED disabled") 18 | ENDIF() 19 | 20 | # Doxygen 21 | FIND_PACKAGE(Doxygen) 22 | OPTION(BUILD_DOCUMENTATION "Create and install API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) 23 | 24 | # build parameters 25 | #SET(CMAKE_C_FLAGS "-Wall") 26 | IF(FORCE_OPENDIR) 27 | SET(FORCE_OPENDIR_DEF ${CMAKE_C_FLAGS} "FORCE_OPENDIR") 28 | ELSE() 29 | SET(FORCE_OPENDIR_DEF ${CMAKE_C_FLAGS} "") 30 | ENDIF() 31 | 32 | INCLUDE_DIRECTORIES(include) 33 | 34 | # build definitions 35 | SET(ALLTARGETS) 36 | SET(LINKTYPES) 37 | IF(BUILD_STATIC) 38 | LIST(APPEND LINKTYPES "STATIC") 39 | ENDIF() 40 | IF(BUILD_SHARED) 41 | LIST(APPEND LINKTYPES "SHARED") 42 | ENDIF() 43 | 44 | FOREACH(LINKTYPE ${LINKTYPES}) 45 | ADD_LIBRARY(dirtrav_${LINKTYPE} ${LINKTYPE} src/dirtrav.c) 46 | SET_TARGET_PROPERTIES(dirtrav_${LINKTYPE} PROPERTIES DEFINE_SYMBOL "BUILD_DIRTRAV_DLL") 47 | SET_TARGET_PROPERTIES(dirtrav_${LINKTYPE} PROPERTIES COMPILE_DEFINITIONS "DIRTRAV_GENERATE;${LINKTYPE};${FORCE_OPENDIR_DEF}") 48 | SET_TARGET_PROPERTIES(dirtrav_${LINKTYPE} PROPERTIES OUTPUT_NAME dirtrav) 49 | TARGET_INCLUDE_DIRECTORIES(dirtrav_${LINKTYPE} PRIVATE lib) 50 | #TARGET_LINK_LIBRARIES(dirtrav_${LINKTYPE} ${ANYZIP_LIBRARIES} ${EXPAT_LIBRARIES}) 51 | SET(ALLTARGETS ${ALLTARGETS} dirtrav_${LINKTYPE}) 52 | 53 | IF(WITH_WIDE) 54 | ADD_LIBRARY(dirtravw_${LINKTYPE} ${LINKTYPE} src/dirtrav.c) 55 | SET_TARGET_PROPERTIES(dirtravw_${LINKTYPE} PROPERTIES DEFINE_SYMBOL "BUILD_DIRTRAV_DLL") 56 | SET_TARGET_PROPERTIES(dirtravw_${LINKTYPE} PROPERTIES COMPILE_DEFINITIONS "DIRTRAV_GENERATE_WIDE;${LINKTYPE};${FORCE_OPENDIR_DEF}") 57 | SET_TARGET_PROPERTIES(dirtravw_${LINKTYPE} PROPERTIES OUTPUT_NAME dirtravw) 58 | TARGET_INCLUDE_DIRECTORIES(dirtravw_${LINKTYPE} PRIVATE lib) 59 | #TARGET_LINK_LIBRARIES(dirtravw_${LINKTYPE} ${ANYZIP_LIBRARIES} ${EXPATW_LIBRARIES}) 60 | SET(ALLTARGETS ${ALLTARGETS} dirtravw_${LINKTYPE}) 61 | ENDIF() 62 | 63 | SET(EXELINKTYPE ${LINKTYPE}) 64 | ENDFOREACH() 65 | 66 | IF(BUILD_TOOLS) 67 | ADD_EXECUTABLE(tree src/tree.c) 68 | TARGET_LINK_LIBRARIES(tree dirtrav_${EXELINKTYPE}) 69 | LIST(APPEND ALLTARGETS tree) 70 | 71 | ADD_EXECUTABLE(rdir src/rdir.c) 72 | TARGET_LINK_LIBRARIES(rdir dirtrav_${EXELINKTYPE}) 73 | LIST(APPEND ALLTARGETS rdir) 74 | 75 | ADD_EXECUTABLE(folderstats src/folderstats.c) 76 | TARGET_LINK_LIBRARIES(folderstats dirtrav_${EXELINKTYPE}) 77 | LIST(APPEND ALLTARGETS folderstats) 78 | ENDIF() 79 | 80 | IF(BUILD_DOCUMENTATION) 81 | IF(NOT DOXYGEN_FOUND) 82 | MESSAGE(FATAL_ERROR "Doxygen is needed to build the documentation.") 83 | ENDIF() 84 | ADD_CUSTOM_TARGET(doc ALL 85 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile 86 | #WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 87 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 88 | COMMENT "Generating API documentation with Doxygen" 89 | VERBATIM 90 | ) 91 | INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc/man 92 | DESTINATION . 93 | ) 94 | INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc/html 95 | DESTINATION share/libdirtrav 96 | ) 97 | ENDIF() 98 | 99 | # installation specifications 100 | INSTALL(TARGETS ${ALLTARGETS} 101 | ARCHIVE DESTINATION lib 102 | LIBRARY DESTINATION lib 103 | RUNTIME DESTINATION bin 104 | ) 105 | INSTALL(DIRECTORY include/ 106 | DESTINATION include 107 | FILES_MATCHING PATTERN "dirtrav*.h" 108 | ) 109 | -------------------------------------------------------------------------------- /Changelog.txt: -------------------------------------------------------------------------------- 1 | 0.2.16 2 | 3 | 2021-12-21 Brecht Sanders https://github.com/brechtsanders/ 4 | 5 | * fix FindFirstFileEx() issues on Windows XP by falling back to FindFirstFileEx() 6 | * on Windows don't include removable drives in dirtrav_iterate_roots() 7 | 8 | 0.2.15 9 | 10 | 2021-12-15 Brecht Sanders https://github.com/brechtsanders/ 11 | 12 | * don't abort traversal when errors occur on non-Windows operating systems 13 | * Makefile: support building wide library (libdirtravw) on Windows 14 | 15 | 0.2.14 16 | 17 | 2021-12-15 Brecht Sanders https://github.com/brechtsanders/ 18 | 19 | * added dirtrav_iterate_roots() and dirtravw_iterate_roots() 20 | 21 | 0.2.13 22 | 23 | 2021-12-14 Brecht Sanders https://github.com/brechtsanders/ 24 | 25 | * don't abort traversal when errors occur on Windows 26 | 27 | 0.2.12 28 | 29 | 2021-08-19 Brecht Sanders https://github.com/brechtsanders/ 30 | 31 | * fix dirtrav_recursive_delete() and dirtravw_recursive_delete() to delete as much as possible on failure 32 | 33 | 0.2.11 34 | 35 | 2021-08-18 Brecht Sanders https://github.com/brechtsanders/ 36 | 37 | * fix build for non-Windows operating systems 38 | 39 | 0.2.10 40 | 41 | 2021-08-18 Brecht Sanders https://github.com/brechtsanders/ 42 | 43 | * added dirtrav_recursive_delete() and dirtravw_recursive_delete() 44 | 45 | 0.2.9 46 | 47 | 2020-09-11 Brecht Sanders https://github.com/brechtsanders/ 48 | 49 | * added dirtrav_free() and dirtravw_free() to release memory allocated by dirtrav_prop_get_owner() 50 | * added owner column to rdir example 51 | 52 | 0.2.8 53 | 54 | 2020-03-22 Brecht Sanders https://github.com/brechtsanders/ 55 | 56 | * fixed dirtrav_prop_get_owner() in Windows to return SID if user name wasn't found locally (instead of NULL) 57 | * added folderstats tool 58 | * added Doxygen HTML manual generation 59 | * added Doxygen and tools to Makefile 60 | 61 | 0.2.7 62 | 63 | 2020-03-21 Brecht Sanders https://github.com/brechtsanders/ 64 | 65 | * added dirtrav_supports_elevate_access() 66 | * ran valgrind tests on Debian Linux 67 | * fixed memory leak (missing free(fullpath)) in dirtrav_traverse_path_parts() 68 | * added initial Makefile for building without CMake 69 | * configured GitHub CI build (in file: .github/workflows/libdirtrav.yml) 70 | 71 | 0.2.6 72 | 73 | 2018-09-24 Brecht Sanders https://github.com/brechtsanders/ 74 | 75 | * added dirtrav_prop_get_extension() 76 | 77 | 0.2.5 78 | 79 | 2018-09-24 Brecht Sanders https://github.com/brechtsanders/ 80 | 81 | * added dirtrav_prop_get_owner() 82 | 83 | 0.2.4 84 | 85 | 2018-08-22 Brecht Sanders https://github.com/brechtsanders/ 86 | 87 | * added dirtrav_prop_get_top_path() 88 | * added dirtrav_prop_get_relative_path() 89 | 90 | 0.2.3 91 | 92 | 2018-08-08 Brecht Sanders https://github.com/brechtsanders/ 93 | 94 | * fixes to documentation (including Doxygen) 95 | * added -e option to folderstats (to run with elevated privileges) 96 | 97 | 0.2.2 98 | 99 | 2018-08-05 Brecht Sanders https://github.com/brechtsanders/ 100 | 101 | * fixed issue with dirtrav_prop_get_size() for sizes > 4GB on Windows 102 | 103 | 0.2.1 104 | 105 | 2018-08-05 Brecht Sanders https://github.com/brechtsanders/ 106 | 107 | * dirtrav_traverse_directory() now returns -1 instead of 0 when path is not found 108 | 109 | 0.2.0 110 | 111 | 2018-08-04 Brecht Sanders https://github.com/brechtsanders/ 112 | 113 | * fixed issue not calling foldercallbackafter when foldercallbackbefore returns negative value 114 | * added tool: folderstats 115 | 116 | 0.1.0 117 | 118 | 2018-08-02 Brecht Sanders https://github.com/brechtsanders/ 119 | 120 | * initial release 121 | 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Brecht Sanders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),) 2 | OS = $(shell uname -s) 3 | endif 4 | PREFIX = /usr/local 5 | CC = gcc 6 | CPP = g++ 7 | AR = ar 8 | LIBPREFIX = lib 9 | LIBEXT = .a 10 | ifeq ($(OS),Windows_NT) 11 | BINEXT = .exe 12 | SOEXT = .dll 13 | else ifeq ($(OS),Darwin) 14 | BINEXT = 15 | SOEXT = .dylib 16 | else 17 | BINEXT = 18 | SOEXT = .so 19 | endif 20 | INCS = -Iinclude 21 | CFLAGS = $(INCS) -Os 22 | CPPFLAGS = $(INCS) -Os 23 | STATIC_CFLAGS = -DDIRTRAV_GENERATE -DBUILD_DIRTRAV_STATIC 24 | SHARED_CFLAGS = -DDIRTRAV_GENERATE -DBUILD_DIRTRAV_DLL 25 | WIDE_STATIC_CFLAGS = -DDIRTRAV_GENERATE_WIDE -DBUILD_DIRTRAV_STATIC 26 | WIDE_SHARED_CFLAGS = -DDIRTRAV_GENERATE_WIDE -DBUILD_DIRTRAV_DLL 27 | LIBS = 28 | LDFLAGS = 29 | ifeq ($(OS),Darwin) 30 | STRIPFLAG = 31 | else 32 | STRIPFLAG = -s 33 | endif 34 | MKDIR = mkdir -p 35 | RM = rm -f 36 | RMDIR = rm -rf 37 | CP = cp -f 38 | CPDIR = cp -rf 39 | DOXYGEN = $(shell which doxygen) 40 | 41 | OSALIAS := $(OS) 42 | ifeq ($(OS),Windows_NT) 43 | ifneq (,$(findstring x86_64,$(shell gcc --version))) 44 | OSALIAS := win64 45 | else 46 | OSALIAS := win32 47 | endif 48 | endif 49 | 50 | libdirtrav_OBJ = src/dirtrav.o 51 | libdirtrav_LDFLAGS = 52 | libdirtrav_SHARED_LDFLAGS = 53 | ifneq ($(OS),Windows_NT) 54 | SHARED_CFLAGS += -fPIC 55 | endif 56 | ifeq ($(OS),Windows_NT) 57 | libdirtrav_SHARED_LDFLAGS += -Wl,--out-implib,$@$(LIBEXT) 58 | endif 59 | ifeq ($(OS),Darwin) 60 | OS_LINK_FLAGS = -dynamiclib -o $@ 61 | else 62 | OS_LINK_FLAGS = -shared -Wl,-soname,$@ $(STRIPFLAG) 63 | endif 64 | 65 | ifneq ($(OS),Windows_NT) 66 | BUILD_WIDE := 67 | endif 68 | ifeq ($(BUILD_WIDE),) 69 | STATIC_LIB_WIDE := 70 | SHARED_LIB_WIDE := 71 | else 72 | STATIC_LIB_WIDE := $(LIBPREFIX)dirtravw$(LIBEXT) 73 | SHARED_LIB_WIDE := $(LIBPREFIX)dirtravw$(SOEXT) 74 | endif 75 | 76 | TOOLS_BIN = tree$(BINEXT) rdir$(BINEXT) folderstats$(BINEXT) 77 | EXAMPLES_BIN = test1$(BINEXT) 78 | 79 | COMMON_PACKAGE_FILES = README.md LICENSE Changelog.txt 80 | SOURCE_PACKAGE_FILES = $(COMMON_PACKAGE_FILES) Makefile CMakeLists.txt doc/Doxyfile include/*.h src/*.c build/*.workspace build/*.cbp build/*.depend 81 | 82 | default: all 83 | 84 | all: static-lib shared-lib $(TOOLS_BIN) 85 | 86 | %.o: %.c 87 | $(CC) -c -o $@ $< $(CFLAGS) 88 | 89 | %.static.o: %.c 90 | $(CC) -c -o $@ $< $(STATIC_CFLAGS) $(CFLAGS) 91 | 92 | %.shared.o: %.c 93 | $(CC) -c -o $@ $< $(SHARED_CFLAGS) $(CFLAGS) 94 | 95 | $(LIBPREFIX)dirtrav$(LIBEXT): $(libdirtrav_OBJ:%.o=%.static.o) 96 | $(AR) cr $@ $^ 97 | 98 | $(LIBPREFIX)dirtrav$(SOEXT): $(libdirtrav_OBJ:%.o=%.shared.o) 99 | $(CC) -o $@ $(OS_LINK_FLAGS) $^ $(libdirtrav_SHARED_LDFLAGS) $(libdirtrav_LDFLAGS) $(LDFLAGS) $(LIBS) 100 | 101 | 102 | ifneq ($(BUILD_WIDE),) 103 | 104 | %.wide-static.o: %.c 105 | $(CC) -c -o $@ $< $(WIDE_STATIC_CFLAGS) $(CFLAGS) 106 | 107 | %.wide-shared.o: %.c 108 | $(CC) -c -o $@ $< $(WIDE_SHARED_CFLAGS) $(CFLAGS) 109 | 110 | $(LIBPREFIX)dirtravw$(LIBEXT): $(libdirtrav_OBJ:%.o=%.wide-static.o) 111 | $(AR) cr $@ $^ 112 | 113 | $(LIBPREFIX)dirtravw$(SOEXT): $(libdirtrav_OBJ:%.o=%.wide-shared.o) 114 | $(CC) -o $@ $(OS_LINK_FLAGS) $^ $(libdirtrav_SHARED_LDFLAGS) $(libdirtrav_LDFLAGS) $(LDFLAGS) $(LIBS) 115 | 116 | endif 117 | 118 | 119 | static-lib: $(LIBPREFIX)dirtrav$(LIBEXT) $(STATIC_LIB_WIDE) 120 | 121 | shared-lib: $(LIBPREFIX)dirtrav$(SOEXT) $(SHARED_LIB_WIDE) 122 | 123 | #tree.o: src/tree.c 124 | # $(CC) -c -o $@ $< $(CFLAGS) 125 | 126 | #tree$(BINEXT).o: tree.o $(LIBPREFIX)dirtrav$(LIBEXT) 127 | # $(CC) -o $@ $< $(CFLAGS) 128 | 129 | tools: $(TOOLS_BIN) 130 | 131 | examples: $(EXAMPLES_BIN) 132 | 133 | 134 | tree$(BINEXT): src/tree.static.o $(LIBPREFIX)dirtrav$(LIBEXT) 135 | $(CC) -o $@ $^ $(libdirtrav_LDFLAGS) $(LDFLAGS) 136 | 137 | rdir$(BINEXT): src/rdir.static.o $(LIBPREFIX)dirtrav$(LIBEXT) 138 | $(CC) -o $@ $^ $(libdirtrav_LDFLAGS) $(LDFLAGS) 139 | 140 | folderstats$(BINEXT): src/folderstats.static.o $(LIBPREFIX)dirtrav$(LIBEXT) 141 | $(CC) -o $@ $^ $(libdirtrav_LDFLAGS) $(LDFLAGS) 142 | 143 | test1$(BINEXT): src/test1.static.o $(LIBPREFIX)dirtrav$(LIBEXT) 144 | $(CC) -o $^ $(libdirtrav_LDFLAGS) $(LDFLAGS) 145 | 146 | .PHONY: doc 147 | doc: 148 | ifdef DOXYGEN 149 | $(DOXYGEN) doc/Doxyfile 150 | endif 151 | 152 | install: all doc 153 | $(MKDIR) $(PREFIX)/include $(PREFIX)/lib $(PREFIX)/bin 154 | $(CP) include/*.h $(PREFIX)/include/ 155 | $(CP) *$(LIBEXT) $(PREFIX)/lib/ 156 | ifeq ($(OS),Windows_NT) 157 | $(CP) *$(SOEXT) $(PREFIX)/bin/ 158 | else 159 | $(CP) *$(SOEXT) $(PREFIX)/lib/ 160 | endif 161 | $(CP) $(TOOLS_BIN) $(PREFIX)/bin/ 162 | ifdef DOXYGEN 163 | $(CPDIR) doc/man $(PREFIX)/ 164 | $(MKDIR) $(PREFIX)/share/libdirtrav 165 | $(CPDIR) doc/html $(PREFIX)/share/libdirtrav/ 166 | endif 167 | 168 | .PHONY: version 169 | version: 170 | sed -ne "s/^#define\s*DIRTRAV_VERSION_[A-Z]*\s*\([0-9]*\)\s*$$/\1./p" include/dirtrav_version.h | tr -d "\n" | sed -e "s/\.$$//" > version 171 | 172 | #.PHONY: package 173 | #package: version 174 | # tar cfJ libdirtrav-$(shell cat version).tar.xz --transform="s?^?libdirtrav-$(shell cat version)/?" $(SOURCE_PACKAGE_FILES) 175 | 176 | .PHONY: package 177 | package: version 178 | tar cfJ libdirtrav-$(shell cat version).tar.xz --transform="s?^?libdirtrav-$(shell cat version)/?" $(SOURCE_PACKAGE_FILES) 179 | 180 | .PHONY: package 181 | binarypackage: version 182 | $(MAKE) PREFIX=binpkg_$(OSALIAS)_temp install BUILD_WIDE=1 183 | ifneq ($(OS),Windows_NT) 184 | tar cfJ "libdirtrav-$(shell cat version)-$(OSALIAS).tar.xz" --transform="s?^binpkg_$(OSALIAS)_temp/??" $(COMMON_PACKAGE_FILES) binpkg_$(OSALIAS)_temp/* 185 | else 186 | rm -f libdirtrav-$(shell cat version)-$(OSALIAS).zip 187 | cp -f $(COMMON_PACKAGE_FILES) binpkg_$(OSALIAS)_temp/ 188 | cd binpkg_$(OSALIAS)_temp && zip -r -9 "../libdirtrav-$(shell cat version)-binary-$(OSALIAS).zip" $(COMMON_PACKAGE_FILES) * && cd .. 189 | endif 190 | rm -rf binpkg_$(OSALIAS)_temp 191 | 192 | .PHONY: clean 193 | clean: 194 | $(RM) src/*.o *$(LIBEXT) *$(SOEXT) $(TOOLS_BIN) $(EXAMPLES_BIN) version libdirtrav-*.tar.xz doc/doxygen_sqlite3.db 195 | ifeq ($(OS),Windows_NT) 196 | $(RM) *.def 197 | endif 198 | $(RMDIR) doc/html doc/man 199 | 200 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libdirtrav 2 | ========== 3 | Cross-platform C library for recursively traversing directory contents. 4 | 5 | Description 6 | ----------- 7 | The libdirtrav library provides a way to recursively read folder contents using callback functions. 8 | This is done using opendir() and readdir() functions, except for Windows where native FindFirstFile()/FindFirstFileEx() and FindNextFile() functions are used. 9 | On Windows a wide version is available which uses wchar_t* as string type for Unicode UTF-16 support. 10 | 11 | Goal 12 | ---- 13 | The library was written with the following goals in mind: 14 | - written in standard C, but allows being used by C++ 15 | - speed 16 | - small footprint 17 | - portable across different platforms (Windows, *nix) 18 | - no dependancies 19 | 20 | Libraries 21 | --------- 22 | 23 | The following libraries are provided: 24 | - `-ldirtrav` - requires `#include ` 25 | - `-ldirtravw` - only supported on Windows, requires `#include ` 26 | 27 | Command line utilities 28 | ---------------------- 29 | Some command line utilities are included: 30 | - `tree` - lists folder tree structure 31 | - `rdir` - recursively lists folder contents 32 | - `folderstats` - get folder statistics 33 | 34 | Dependancies 35 | ------------ 36 | This project has no depencancies. 37 | 38 | Building from source 39 | -------------------- 40 | Requirements: 41 | - a C compiler like gcc or clang, on Windows MinGW and MinGW-w64 are supported 42 | - a shell environment, on Windows MSYS is supported 43 | - the make command 44 | - CMake version 2.6 or higher (optional, but preferred) 45 | 46 | Building with CMake 47 | - configure by running `cmake -G"Unix Makefiles"` (or `cmake -G"MSYS Makefiles"` on Windows) optionally followed by: 48 | + `-DCMAKE_INSTALL_PREFIX:PATH=` Base path were files will be installed 49 | + `-DBUILD_STATIC:BOOL=OFF` - Don't build static libraries 50 | + `-DBUILD_SHARED:BOOL=OFF` - Don't build shared libraries 51 | + `-DBUILD_TOOLS:BOOL=OFF` - Don't build tools (only libraries) 52 | + `-DWITH_WIDE:BOOL=ON` - Only on Windows: also build UTF-16 library (libdirtravw) 53 | + `-DFORCE_OPENDIR:BOOL=ON` - Only on Windows: use opendir() and readdir() instead of native Windows functions 54 | - build and install by running `make install` (or `make install/strip` to strip symbols) 55 | 56 | For Windows prebuilt binaries are also available for download (both 32-bit and 64-bit) 57 | 58 | License 59 | ------- 60 | libdirtrav is released under the terms of the MIT License (MIT), see LICENSE.txt. 61 | 62 | This means you are free to use libdirtrav in any of your projects, from open source to commercial. 63 | -------------------------------------------------------------------------------- /build/folderstats.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 106 | 107 | -------------------------------------------------------------------------------- /build/folderstats.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1584806664 source:\\server\users\brecht\sources\cpp\libdirtrav\src\folderstats.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | "dirtravw.h" 13 | 14 | 15 | "dirtrav.h" 16 | 17 | 1584806708 \\server\users\brecht\sources\cpp\libdirtrav\include\dirtravw.h 18 | 19 | 20 | 21 | 22 | 23 | 1584806608 \\server\users\brecht\sources\cpp\libdirtrav\include\dirtrav.h 24 | 25 | 26 | 27 | 28 | 1584810264 source:z:\libdirtrav\src\folderstats.c 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | "dirtravw.h" 39 | 40 | 41 | "dirtrav.h" 42 | 43 | 1629308544 z:\libdirtrav\include\dirtravw.h 44 | 45 | 46 | 47 | 48 | 49 | 1629308094 z:\libdirtrav\include\dirtrav.h 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /build/libdirtrav.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /build/libdirtrav_nowin_shared.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 104 | 105 | -------------------------------------------------------------------------------- /build/libdirtrav_nowin_shared.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/libdirtrav_nowin_static.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 119 | 120 | -------------------------------------------------------------------------------- /build/libdirtrav_nowin_static.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | -------------------------------------------------------------------------------- /build/libdirtrav_shared.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 102 | 103 | -------------------------------------------------------------------------------- /build/libdirtrav_shared.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/libdirtrav_static.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 113 | 114 | -------------------------------------------------------------------------------- /build/libdirtrav_static.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/libdirtravw_nowin_shared.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 104 | 105 | -------------------------------------------------------------------------------- /build/libdirtravw_nowin_shared.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/libdirtravw_nowin_static.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 119 | 120 | -------------------------------------------------------------------------------- /build/libdirtravw_nowin_static.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/libdirtravw_shared.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 102 | 103 | -------------------------------------------------------------------------------- /build/libdirtravw_shared.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/libdirtravw_static.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 113 | 114 | -------------------------------------------------------------------------------- /build/libdirtravw_static.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639557525 source:z:\libdirtrav\src\dirtrav.c 3 | "dirtrav_version.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | "dirtrav.h" 14 | "dirtravw.h" 15 | 16 | 17 | 1639552957 z:\libdirtrav\include\dirtrav_version.h 18 | 19 | 1639554823 z:\libdirtrav\include\dirtrav.h 20 | 21 | 22 | 23 | 24 | 1639557419 z:\libdirtrav\include\dirtravw.h 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/rdir.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 109 | 110 | -------------------------------------------------------------------------------- /build/rdir.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | -------------------------------------------------------------------------------- /build/rdirw.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 110 | 111 | -------------------------------------------------------------------------------- /build/rdirw.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1599831131 source:z:\libdirtrav\src\rdir.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | "dirtravw.h" 11 | 12 | 13 | "dirtrav.h" 14 | 15 | 1639553467 z:\libdirtrav\include\dirtravw.h 16 | 17 | 18 | 19 | 20 | 21 | 1639553467 z:\libdirtrav\include\dirtrav.h 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /build/test1.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 110 | 111 | -------------------------------------------------------------------------------- /build/test1.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | -------------------------------------------------------------------------------- /build/test2.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 110 | 111 | -------------------------------------------------------------------------------- /build/test2.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | -------------------------------------------------------------------------------- /build/test3.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 | 101 | -------------------------------------------------------------------------------- /build/test3.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639558021 source:z:\libdirtrav\build\test3.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | "dirtravw.h" 10 | 11 | 12 | "dirtrav.h" 13 | 14 | 1639554823 z:\libdirtrav\include\dirtrav.h 15 | 16 | 17 | 18 | 19 | 1639557419 z:\libdirtrav\include\dirtravw.h 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /build/test3w.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 | 101 | -------------------------------------------------------------------------------- /build/test3w.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1639560536 source:z:\libdirtrav\build\test3.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | "dirtravw.h" 10 | "dirtrav.h" 11 | 12 | 1639557419 z:\libdirtrav\include\dirtravw.h 13 | 14 | 15 | 16 | 17 | 18 | 1639554823 z:\libdirtrav\include\dirtrav.h 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /build/tree.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 109 | 110 | -------------------------------------------------------------------------------- /build/tree.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1532972706 source:z:\libdirtrav\src\tree.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 1629308544 z:\libdirtrav\include\dirtravw.h 16 | 17 | 18 | 19 | 20 | 21 | 1629308094 z:\libdirtrav\include\dirtrav.h 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /build/treew.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 110 | 111 | -------------------------------------------------------------------------------- /build/treew.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1532969106 source:z:\libdirtrav\src\tree.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 1639553467 z:\libdirtrav\include\dirtravw.h 16 | 17 | 18 | 19 | 20 | 21 | 1639553467 z:\libdirtrav\include\dirtrav.h 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /doc/Doxyfile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = "libdirtrav" 2 | OUTPUT_DIRECTORY = doc 3 | INPUT = 4 | EXTRACT_ALL = NO 5 | EXTRACT_PRIVATE = NO 6 | EXTRACT_STATIC = NO 7 | FILE_PATTERNS = README.md *.h 8 | USE_MDFILE_AS_MAINPAGE = README.md 9 | RECURSIVE = YES 10 | GENERATE_MAN = YES 11 | GENERATE_HTML = YES 12 | GENERATE_LATEX = NO 13 | #GENERATE_LATEX = YES 14 | #USE_PDFLATEX = YES 15 | #PDF_HYPERLINKS = YES 16 | SORT_MEMBER_DOCS = NO 17 | EXCLUDE_SYMBOLS = DLL_EXPORT_DIRTRAV 18 | -------------------------------------------------------------------------------- /include/dirtrav.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2018 Brecht Sanders All Rights Reserved 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | *****************************************************************************/ 22 | 23 | /** 24 | * @file dirtrav.h 25 | * @brief libdirtrav header file with main functions 26 | * @author Brecht Sanders 27 | * 28 | * This header file defines the functions needed to traverse directories. 29 | * \sa dirtrav_traverse_directory() 30 | */ 31 | 32 | #ifndef INCLUDED_TRAVERSEDIRECTORY_H 33 | #define INCLUDED_TRAVERSEDIRECTORY_H 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | /*! \cond PRIVATE */ 40 | #if !defined(DLL_EXPORT_DIRTRAV) 41 | # if defined(_WIN32) && defined(BUILD_DIRTRAV_DLL) 42 | # define DLL_EXPORT_DIRTRAV __declspec(dllexport) 43 | # elif defined(_WIN32) && !defined(STATIC) && !defined(BUILD_DIRTRAV_STATIC) && !defined(BUILD_DIRTRAV) 44 | # define DLL_EXPORT_DIRTRAV __declspec(dllimport) 45 | # else 46 | # define DLL_EXPORT_DIRTRAV 47 | # endif 48 | #endif 49 | /*! \endcond */ 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | /*! \brief get dirtrav version string 56 | * \param pmajor pointer to integer that will receive major version number 57 | * \param pminor pointer to integer that will receive minor version number 58 | * \param pmicro pointer to integer that will receive micro version number 59 | * \sa dirtrav_get_version_string() 60 | */ 61 | DLL_EXPORT_DIRTRAV void dirtrav_get_version (int* pmajor, int* pminor, int* pmicro); 62 | 63 | /*! \brief get dirtrav version string 64 | * \return version string 65 | * \sa dirtrav_get_version() 66 | */ 67 | DLL_EXPORT_DIRTRAV const char* dirtrav_get_version_string (); 68 | 69 | /*! \brief check if enabling privileged access is supported (currently only implemented on Windows) 70 | * \return non-zero if elevating to privileged access is supported or zero if not 71 | */ 72 | DLL_EXPORT_DIRTRAV int dirtrav_supports_elevate_access (); 73 | 74 | /*! \brief enable privileged access to allow reading all files and directories (only implemented on Windows) 75 | * \return NULL on success or error message 76 | */ 77 | DLL_EXPORT_DIRTRAV const char* dirtrav_elevate_access (); 78 | 79 | /*! \brief structure used to pass directory entry data to callback functions 80 | */ 81 | struct dirtrav_entry_struct { 82 | const char* filename; /**< name of the current file or folder */ 83 | const char* fullpath; /**< full path of the current file or folder */ 84 | const char* parentpath; /**< full path of the parent folder */ 85 | const struct dirtrav_entry_struct* parentinfo; /**< directory entry data of parent folder */ 86 | void* callbackdata; /**< callback data to be used freely by callback functions */ 87 | void* folderlocaldata; /**< custom folder data, defaults to NULL, allocate/free in foldercallbackbefore/foldercallbackafter */ 88 | }; 89 | /*! \brief pointer to struct dirtravw_entry_struct used to pass data to callback functions 90 | * \sa struct dirtrav_entry_struct 91 | * \sa dirtrav_file_callback_fn 92 | * \sa dirtrav_folder_callback_fn 93 | * \sa dirtrav_traverse_directory() 94 | */ 95 | typedef struct dirtrav_entry_struct* dirtrav_entry; 96 | 97 | /*! \brief callback function called by dirtrav_traverse_directory for each file 98 | * \param info file information 99 | * \return 0 to continue processing or non-zero to abort 100 | * \sa dirtrav_entry 101 | * \sa dirtrav_traverse_directory() 102 | */ 103 | typedef int (*dirtrav_file_callback_fn) (dirtrav_entry info); 104 | 105 | /*! \brief callback function called by dirtrav_traverse_directory for each folder 106 | * \param info folder information 107 | * \return 0 to continue processing or non-zero to abort, < 0 in foldercallbackbefore to not process subfolder 108 | * \sa dirtrav_entry 109 | * \sa dirtrav_traverse_directory() 110 | */ 111 | typedef int (*dirtrav_folder_callback_fn) (dirtrav_entry info); 112 | 113 | /*! \brief recursively traverse \p directory calling calbacks for each file and folder 114 | * \param directory full path of directory to be traversed 115 | * \param filecallback optional callback function to be called before processing each file 116 | * \param foldercallbackbefore optional callback function to be called before processing each folder 117 | * \param foldercallbackafter optional callback function to be called after processing each folder (except when foldercallbackbefore returned non-zero) 118 | * \param callbackdata optional callback data to be passed to callback functions 119 | * \return 0 if the entire tree was traversed or the result of the callback function that caused traversal to stop 120 | * \sa dirtrav_entry 121 | * \sa dirtrav_iterate_roots() 122 | */ 123 | DLL_EXPORT_DIRTRAV int dirtrav_traverse_directory (const char* directory, dirtrav_file_callback_fn filecallback, dirtrav_folder_callback_fn foldercallbackbefore, dirtrav_folder_callback_fn foldercallbackafter, void* callbackdata); 124 | 125 | /*! \brief iterate root paths (root paths of drives on Windows, / on other platforms) calling calback for each entry 126 | * \param rootcallback callback function to be called for each root path 127 | * \param callbackdata optional callback data to be passed to callback functions 128 | * \return 0 if all root paths were processed or the result of the callback function that caused traversal to stop 129 | * \sa dirtrav_entry 130 | * \sa dirtrav_traverse_directory() 131 | */ 132 | DLL_EXPORT_DIRTRAV int dirtrav_iterate_roots (dirtrav_folder_callback_fn rootcallback, void* callbackdata); 133 | 134 | /*! \brief split \p path into folders calling calbacks for each folder part 135 | * \param startpath optional base path to which \p path is relative 136 | * \param path path to analyse (relative to \p startpath if specified) 137 | * \param foldercallbackbefore optional callback function to be called before processing each folder 138 | * \param foldercallbackafter optional callback function to be called after processing each folder (except when foldercallbackbefore returned non-zero) 139 | * \param callbackdata optional callback data to be passed to callback functions 140 | * \return 0 if the entire tree was traversed or the result of the callback function that caused traversal to stop 141 | * \sa dirtrav_file_callback_fn 142 | * \sa dirtrav_folder_callback_fn 143 | */ 144 | DLL_EXPORT_DIRTRAV int dirtrav_traverse_path_parts (const char* startpath, const char* path, dirtrav_folder_callback_fn foldercallbackbefore, dirtrav_folder_callback_fn foldercallbackafter, void* callbackdata); 145 | 146 | /*! \brief create folder structure \p path under \p startpath 147 | * \param startpath optional base path to which \p path is relative 148 | * \param path path of folder structure to create (relative to \p startpath if specified) 149 | * \param mode file permission bits to use when creating folders (not used on Windows) 150 | * \return 0 151 | * \sa dirtrav_folder_callback_fn 152 | */ 153 | DLL_EXPORT_DIRTRAV int dirtrav_make_full_path (const char* startpath, const char* path, mode_t mode); 154 | 155 | /*! \brief recursively delete \p path and all files and folders it contains 156 | * \param path path of folder structure to delete 157 | * \return zero on success, non-zero on error 158 | * \sa dirtrav_folder_callback_fn 159 | */ 160 | DLL_EXPORT_DIRTRAV int dirtrav_recursive_delete (const char* path); 161 | 162 | /*! \brief get full path of current file or folder 163 | * \param entry system properties of directory entry 164 | * \return full path of current file or folder 165 | */ 166 | #define dirtrav_prop_get_path(entry) (entry->fullpath) 167 | 168 | /*! \brief get parent path 169 | * \param entry system properties of directory entry 170 | * \return parent path 171 | * \sa dirtrav_entry 172 | * \sa dirtrav_traverse_directory() 173 | */ 174 | #define dirtrav_prop_get_parentpath(entry) (entry->parentpath) 175 | 176 | /*! \brief get name of current file or folder 177 | * \param entry system properties of directory entry 178 | * \return name of current file or folder 179 | * \sa dirtrav_entry 180 | * \sa dirtrav_traverse_directory() 181 | */ 182 | #define dirtrav_prop_get_name(entry) (entry->filename) 183 | 184 | /*! \brief get extension of current file 185 | * \param entry system properties of directory entry 186 | * \return file extension (including the leading dot) or NULL if none 187 | * \sa dirtrav_entry 188 | * \sa dirtrav_traverse_directory() 189 | * \sa dirtrav_prop_get_name() 190 | */ 191 | DLL_EXPORT_DIRTRAV const char* dirtrav_prop_get_extension (dirtrav_entry entry); 192 | 193 | /*! \brief determine if current file or folder is a folder 194 | * \param entry system properties of directory entry 195 | * \return non-zero if current file or folder is a folder 196 | * \sa dirtrav_entry 197 | * \sa dirtrav_traverse_directory() 198 | */ 199 | DLL_EXPORT_DIRTRAV int dirtrav_prop_is_directory (dirtrav_entry entry); 200 | 201 | /*! \brief determine if current file or folder is a link 202 | * \param entry system properties of directory entry 203 | * \return non-zero if current file or folder is a link 204 | * \sa dirtrav_entry 205 | * \sa dirtrav_traverse_directory() 206 | */ 207 | DLL_EXPORT_DIRTRAV int dirtrav_prop_is_link (dirtrav_entry entry); 208 | 209 | /*! \brief get size of current file (not valid for folders) 210 | * \param entry system properties of directory entry 211 | * \return file size in bytes 212 | * \sa dirtrav_entry 213 | * \sa dirtrav_traverse_directory() 214 | */ 215 | DLL_EXPORT_DIRTRAV uint64_t dirtrav_prop_get_size (dirtrav_entry entry); 216 | 217 | /*! \brief get creation date and time of current file or folder 218 | * \param entry system properties of directory entry 219 | * \return creation date and time of current file or folder 220 | * \sa dirtrav_entry 221 | * \sa dirtrav_traverse_directory() 222 | */ 223 | DLL_EXPORT_DIRTRAV time_t dirtrav_prop_get_create_time (dirtrav_entry entry); 224 | 225 | /*! \brief get modification date and time of current file or folder 226 | * \param entry system properties of directory entry 227 | * \return modification date and time of current file or folder 228 | * \sa dirtrav_entry 229 | * \sa dirtrav_traverse_directory() 230 | */ 231 | DLL_EXPORT_DIRTRAV time_t dirtrav_prop_get_modify_time (dirtrav_entry entry); 232 | 233 | /*! \brief get last access date and time of current file or folder 234 | * \param entry system properties of directory entry 235 | * \return last access date and time of current file or folder 236 | * \sa dirtrav_entry 237 | * \sa dirtrav_traverse_directory() 238 | */ 239 | DLL_EXPORT_DIRTRAV time_t dirtrav_prop_get_access_time (dirtrav_entry entry); 240 | 241 | /*! \brief get top path from where directory traversal was started 242 | * \param entry system properties of directory entry 243 | * \return top path 244 | * \sa dirtrav_entry 245 | * \sa dirtrav_traverse_directory() 246 | */ 247 | DLL_EXPORT_DIRTRAV const char* dirtrav_prop_get_top_path (dirtrav_entry entry); 248 | 249 | /*! \brief get relative path (relative to top path from where directory traversal was started) 250 | * \param entry system properties of directory entry 251 | * \return relative path 252 | * \sa dirtrav_entry 253 | * \sa dirtrav_traverse_directory() 254 | */ 255 | DLL_EXPORT_DIRTRAV const char* dirtrav_prop_get_relative_path (dirtrav_entry entry); 256 | 257 | /*! \brief get owner name 258 | * \param entry system properties of directory entry 259 | * \return name of owner (the caller must call dirtrav_free()) or NULL on error 260 | * \sa dirtrav_entry 261 | * \sa dirtrav_traverse_directory() 262 | * \sa dirtrav_free() 263 | */ 264 | DLL_EXPORT_DIRTRAV char* dirtrav_prop_get_owner (dirtrav_entry entry); 265 | 266 | /*! \brief release memory allocated by this library 267 | * \param data pointer to memory allocated by other functions in this library 268 | * \sa dirtrav_prop_get_owner() 269 | */ 270 | DLL_EXPORT_DIRTRAV void dirtrav_free (void* data); 271 | 272 | #ifdef __cplusplus 273 | } 274 | #endif 275 | 276 | #endif //INCLUDED_TRAVERSEDIRECTORY_H 277 | -------------------------------------------------------------------------------- /include/dirtrav_version.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2013-2018 Brecht Sanders All Rights Reserved 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | *****************************************************************************/ 22 | 23 | /** 24 | * @file dirtrav_version.h 25 | * @brief libdirtrav header file with version information. 26 | * @author Brecht Sanders 27 | * 28 | * Only use this header file when version information is needed at compile 29 | * time. Otherwise the version functions in the libraries should be used. 30 | * \sa DIRTRAV_VERSION_* 31 | * \sa DIRTRAV_VERSION_STRING 32 | * \sa dirtrav_get_version() 33 | * \sa dirtrav_get_version_string() 34 | */ 35 | 36 | #ifndef INCLUDED_DIRTRAV_VERSION_H 37 | #define INCLUDED_DIRTRAV_VERSION_H 38 | 39 | /*! \brief version number constants 40 | * \sa dirtrav_get_version() 41 | * \sa dirtrav_get_version_string() 42 | * \name DIRTRAV_VERSION_* 43 | * \{ 44 | */ 45 | /*! \brief major version number */ 46 | #define DIRTRAV_VERSION_MAJOR 0 47 | /*! \brief minor version number */ 48 | #define DIRTRAV_VERSION_MINOR 2 49 | /*! \brief micro version number */ 50 | #define DIRTRAV_VERSION_MICRO 16 51 | /*! @} */ 52 | 53 | /*! \cond PRIVATE */ 54 | #define DIRTRAV_VERSION_STRINGIZE_(major, minor, micro) #major"."#minor"."#micro 55 | #define DIRTRAV_VERSION_STRINGIZE(major, minor, micro) DIRTRAV_VERSION_STRINGIZE_(major, minor, micro) 56 | /*! \endcond */ 57 | 58 | /*! \brief string with dotted version number \hideinitializer */ 59 | #define DIRTRAV_VERSION_STRING DIRTRAV_VERSION_STRINGIZE(DIRTRAV_VERSION_MAJOR, DIRTRAV_VERSION_MINOR, DIRTRAV_VERSION_MICRO) 60 | 61 | /*! \brief string with name of dirtrav library */ 62 | #define DIRTRAV_NAME "libdirtrav_read" 63 | 64 | /*! \brief string with name and version of dirtrav library \hideinitializer */ 65 | #define DIRTRAV_FULLNAME DIRTRAV_NAME " " DIRTRAV_VERSION_STRING 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /include/dirtravw.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2013-2018 Brecht Sanders All Rights Reserved 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | *****************************************************************************/ 22 | 23 | /** 24 | * @file dirtravw.h 25 | * @brief libdirtrav header file with main functions 26 | * @author Brecht Sanders 27 | * 28 | * This header file defines the functions needed to traverse directories 29 | * using Unicode UTF-16 wide strings (wchar_t*). 30 | * \sa dirtravw_traverse_directory() 31 | */ 32 | 33 | #ifndef INCLUDED_TRAVERSEDIRECTORY_H 34 | #define INCLUDED_TRAVERSEDIRECTORY_H 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | /*! \cond PRIVATE */ 42 | #if !defined(DLL_EXPORT_DIRTRAV) 43 | # if defined(_WIN32) && defined(BUILD_DIRTRAV_DLL) 44 | # define DLL_EXPORT_DIRTRAV __declspec(dllexport) 45 | # elif defined(_WIN32) && !defined(STATIC) && !defined(BUILD_DIRTRAV_STATIC) && !defined(BUILD_DIRTRAV) 46 | # define DLL_EXPORT_DIRTRAV __declspec(dllimport) 47 | # else 48 | # define DLL_EXPORT_DIRTRAV 49 | # endif 50 | #endif 51 | /*! \endcond */ 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /*! \brief get dirtrav version string 58 | * \param pmajor pointer to integer that will receive major version number 59 | * \param pminor pointer to integer that will receive minor version number 60 | * \param pmicro pointer to integer that will receive micro version number 61 | * \sa dirtravw_get_version_string() 62 | */ 63 | DLL_EXPORT_DIRTRAV void dirtravw_get_version (int* pmajor, int* pminor, int* pmicro); 64 | 65 | /*! \brief get dirtrav version string 66 | * \return version string 67 | * \sa dirtravw_get_version() 68 | */ 69 | DLL_EXPORT_DIRTRAV const wchar_t* dirtravw_get_version_string (); 70 | 71 | /*! \brief check if enabling privileged access is supported (currently only implemented on Windows) 72 | * \return non-zero if elevating to privileged access is supported or zero if not 73 | */ 74 | DLL_EXPORT_DIRTRAV int dirtravw_supports_elevate_access (); 75 | 76 | /*! \brief enable privileged access to allow reading all files and directories (only implemented on Windows) 77 | * \return NULL on success or error message 78 | */ 79 | DLL_EXPORT_DIRTRAV const wchar_t* dirtravw_elevate_access (); 80 | 81 | /*! \brief structure used to pass directory entry data to callback functions 82 | */ 83 | struct dirtravw_entry_struct { 84 | const wchar_t* filename; /**< name of the current file or folder */ 85 | const wchar_t* fullpath; /**< full path of the current file or folder */ 86 | const wchar_t* parentpath; /**< full path of the parent folder */ 87 | const struct dirtravw_entry_struct* parentinfo; /**< directory entry data of parent folder */ 88 | void* callbackdata; /**< callback data to be used freely by callback functions */ 89 | void* folderlocaldata; /**< custom folder data, defaults to NULL, allocate/free in foldercallbackbefore/foldercallbackafter */ 90 | }; 91 | /*! \brief pointer to struct dirtravw_entry_struct used to pass data to callback functions 92 | * \sa struct dirtravw_entry_struct 93 | * \sa dirtravw_file_callback_fn 94 | * \sa dirtravw_folder_callback_fn 95 | * \sa dirtravw_traverse_directory() 96 | */ 97 | typedef struct dirtravw_entry_struct* dirtravw_entry; 98 | 99 | /*! \brief callback function called by dirtravw_traverse_directory for each file 100 | * \param info file information 101 | * \return 0 to continue processing or non-zero to abort 102 | * \sa dirtravw_entry 103 | * \sa dirtravw_traverse_directory() 104 | */ 105 | typedef int (*dirtravw_file_callback_fn) (dirtravw_entry info); 106 | 107 | /*! \brief callback function called by dirtravw_traverse_directory for each folder 108 | * \param info folder information 109 | * \return 0 to continue processing or non-zero to abort, < 0 in foldercallbackbefore to not process subfolder 110 | * \sa dirtravw_entry 111 | * \sa dirtravw_traverse_directory() 112 | */ 113 | typedef int (*dirtravw_folder_callback_fn) (dirtravw_entry info); 114 | 115 | /*! \brief recursively traverse \p directory calling calbacks for each file and folder 116 | * \param directory full path of directory to be traversed 117 | * \param filecallback optional callback function to be called before processing each file 118 | * \param foldercallbackbefore optional callback function to be called before processing each folder 119 | * \param foldercallbackafter optional callback function to be called after processing each folder (except when foldercallbackbefore returned non-zero) 120 | * \param callbackdata optional callback data to be passed to callback functions 121 | * \return 0 if the entire tree was traversed or the result of the callback function that caused traversal to stop 122 | * \sa dirtravw_entry 123 | * \sa dirtravw_iterate_roots() 124 | */ 125 | DLL_EXPORT_DIRTRAV int dirtravw_traverse_directory (const wchar_t* directory, dirtravw_file_callback_fn filecallback, dirtravw_folder_callback_fn foldercallbackbefore, dirtravw_folder_callback_fn foldercallbackafter, void* callbackdata); 126 | 127 | /*! \brief iterate root paths (root paths of drives on Windows, / on other platforms) calling calback for each entry 128 | * \param rootcallback callback function to be called for each root path 129 | * \param callbackdata optional callback data to be passed to callback functions 130 | * \return 0 if all root paths were processed or the result of the callback function that caused traversal to stop 131 | * \sa dirtravw_entry 132 | * \sa dirtravw_traverse_directory() 133 | */ 134 | DLL_EXPORT_DIRTRAV int dirtravw_iterate_roots (dirtravw_folder_callback_fn rootcallback, void* callbackdata); 135 | 136 | /*! \brief split \p path into folders calling calbacks for each folder part 137 | * \param startpath optional base path to which \p path is relative 138 | * \param path path to analyse (relative to \p startpath if specified) 139 | * \param foldercallbackbefore optional callback function to be called before processing each folder 140 | * \param foldercallbackafter optional callback function to be called after processing each folder (except when foldercallbackbefore returned non-zero) 141 | * \param callbackdata optional callback data to be passed to callback functions 142 | * \return 0 if the entire tree was traversed or the result of the callback function that caused traversal to stop 143 | * \sa dirtravw_file_callback_fn 144 | * \sa dirtravw_folder_callback_fn 145 | */ 146 | DLL_EXPORT_DIRTRAV int dirtravw_traverse_path_parts (const wchar_t* startpath, const wchar_t* path, dirtravw_folder_callback_fn foldercallbackbefore, dirtravw_folder_callback_fn foldercallbackafter, void* callbackdata); 147 | 148 | /*! \brief create folder structure \p path under \p startpath 149 | * \param startpath optional base path to which \p path is relative 150 | * \param path path of folder structure to create (relative to \p startpath if specified) 151 | * \param mode file permission bits to use when creating folders (not used on Windows) 152 | * \return 0 153 | * \sa dirtravw_folder_callback_fn 154 | */ 155 | DLL_EXPORT_DIRTRAV int dirtravw_make_full_path (const wchar_t* startpath, const wchar_t* path, mode_t mode); 156 | 157 | /*! \brief recursively delete \p path and all files and folders it contains 158 | * \param path path of folder structure to delete 159 | * \return zero on success, non-zero on error 160 | * \sa dirtrav_folder_callback_fn 161 | */ 162 | DLL_EXPORT_DIRTRAV int dirtravw_recursive_delete (const wchar_t* path); 163 | 164 | /*! \brief get full path of current file or folder 165 | * \param entry system properties of directory entry 166 | * \return full path of current file or folder 167 | */ 168 | #define dirtravw_prop_get_path(entry) (entry->fullpath) 169 | 170 | /*! \brief get parent path 171 | * \param entry system properties of directory entry 172 | * \return parent path 173 | * \sa dirtravw_entry 174 | * \sa dirtravw_traverse_directory() 175 | */ 176 | #define dirtravw_prop_get_parentpath(entry) (entry->parentpath) 177 | 178 | /*! \brief get name of current file or folder 179 | * \param entry system properties of directory entry 180 | * \return name of current file or folder 181 | * \sa dirtravw_entry 182 | * \sa dirtravw_traverse_directory() 183 | */ 184 | #define dirtravw_prop_get_name(entry) (entry->filename) 185 | 186 | /*! \brief get extension of current file 187 | * \param entry system properties of directory entry 188 | * \return file extension (including the leading dot) or NULL if none 189 | * \sa dirtravw_entry 190 | * \sa dirtravw_traverse_directory() 191 | * \sa dirtravw_prop_get_name() 192 | */ 193 | DLL_EXPORT_DIRTRAV const wchar_t* dirtravw_prop_get_extension (dirtravw_entry entry); 194 | 195 | /*! \brief determine if current file or folder is a folder 196 | * \param entry system properties of directory entry 197 | * \return non-zero if current file or folder is a folder 198 | * \sa dirtravw_entry 199 | * \sa dirtravw_traverse_directory() 200 | */ 201 | DLL_EXPORT_DIRTRAV int dirtravw_prop_is_directory (dirtravw_entry entry); 202 | 203 | /*! \brief determine if current file or folder is a link 204 | * \param entry system properties of directory entry 205 | * \return non-zero if current file or folder is a link 206 | * \sa dirtravw_entry 207 | * \sa dirtravw_traverse_directory() 208 | */ 209 | DLL_EXPORT_DIRTRAV int dirtravw_prop_is_link (dirtravw_entry entry); 210 | 211 | /*! \brief get size of current file (not valid for folders) 212 | * \param entry system properties of directory entry 213 | * \return file size in bytes 214 | * \sa dirtravw_entry 215 | * \sa dirtravw_traverse_directory() 216 | */ 217 | DLL_EXPORT_DIRTRAV uint64_t dirtravw_prop_get_size (dirtravw_entry entry); 218 | 219 | /*! \brief get creation date and time of current file or folder 220 | * \param entry system properties of directory entry 221 | * \return creation date and time of current file or folder 222 | * \sa dirtravw_entry 223 | * \sa dirtravw_traverse_directory() 224 | */ 225 | DLL_EXPORT_DIRTRAV time_t dirtravw_prop_get_create_time (dirtravw_entry entry); 226 | 227 | /*! \brief get modification date and time of current file or folder 228 | * \param entry system properties of directory entry 229 | * \return modification date and time of current file or folder 230 | * \sa dirtravw_entry 231 | * \sa dirtravw_traverse_directory() 232 | */ 233 | DLL_EXPORT_DIRTRAV time_t dirtravw_prop_get_modify_time (dirtravw_entry entry); 234 | 235 | /*! \brief get last access date and time of current file or folder 236 | * \param entry system properties of directory entry 237 | * \return last access date and time of current file or folder 238 | * \sa dirtravw_entry 239 | * \sa dirtravw_traverse_directory() 240 | */ 241 | DLL_EXPORT_DIRTRAV time_t dirtravw_prop_get_access_time (dirtravw_entry entry); 242 | 243 | /*! \brief get top path from where directory traversal was started 244 | * \param entry system properties of directory entry 245 | * \return top path 246 | * \sa dirtravw_entry 247 | * \sa dirtravw_traverse_directory() 248 | */ 249 | DLL_EXPORT_DIRTRAV const wchar_t* dirtravw_prop_get_top_path (dirtravw_entry entry); 250 | 251 | /*! \brief get relative path (relative to top path from where directory traversal was started) 252 | * \param entry system properties of directory entry 253 | * \return relative path 254 | * \sa dirtravw_entry 255 | * \sa dirtravw_traverse_directory() 256 | */ 257 | DLL_EXPORT_DIRTRAV const wchar_t* dirtravw_prop_get_relative_path (dirtravw_entry entry); 258 | 259 | /*! \brief get owner name 260 | * \param entry system properties of directory entry 261 | * \return name of owner (the caller must call dirtravw_free()) or NULL on error 262 | * \sa dirtravw_entry 263 | * \sa dirtravw_traverse_directory() 264 | * \sa dirtravw_free() 265 | */ 266 | DLL_EXPORT_DIRTRAV wchar_t* dirtravw_prop_get_owner (dirtravw_entry entry); 267 | 268 | /*! \brief release memory allocated by this library 269 | * \param data pointer to memory allocated by other functions in this library 270 | * \sa dirtravw_prop_get_owner() 271 | */ 272 | DLL_EXPORT_DIRTRAV void dirtravw_free (void* data); 273 | 274 | #ifdef __cplusplus 275 | } 276 | #endif 277 | 278 | #endif //INCLUDED_TRAVERSEDIRECTORY_H 279 | -------------------------------------------------------------------------------- /src/dirtrav.c: -------------------------------------------------------------------------------- 1 | #include "dirtrav_version.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | //#include 7 | #define LOOKUP_SID 8 | #ifdef _WIN32 9 | #ifdef LOOKUP_SID 10 | #if !defined(WINVER) || WINVER < 0x0500 11 | #undef WINVER 12 | #define WINVER 0x0500 13 | #endif 14 | #include 15 | #include 16 | #endif 17 | #else 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | #if defined(DIRTRAV_GENERATE) 24 | 25 | # include "dirtrav.h" 26 | # define DIRCHAR char 27 | # define DIRSTRLEN strlen 28 | # define DIRSTRCPY strcpy 29 | # define DIRSTRDUP strdup 30 | # define DIRPRINTF printf 31 | # define DIRTEXT(s) s 32 | //# define DIRFN(fn) fn 33 | # define DIRTRAVFN(fn) dirtrav_##fn 34 | # define DIRWFN(fn) fn 35 | # define DIR_WFN(fn) fn 36 | # define DIR_WUFN(fn) fn 37 | # define DIRWINFN(fn) fn##A 38 | # if !defined(_WIN32) || defined(FORCE_OPENDIR) 39 | # if defined(_WIN32) 40 | //# define STAT_FN(path,data) _stat64(path, data) 41 | //# define STAT_STRUCT struct __stat64 42 | //# define STAT_TIME_TYPE __time64_t 43 | # define STAT_FN(path,data) _stat(path, data) 44 | # define STAT_STRUCT struct _stat 45 | # define STAT_TIME_TYPE time_t 46 | # else 47 | //# define STAT_FN(path,data) stat64(path, data) 48 | //# define STAT_STRUCT struct stat64 49 | //# define STAT_TIME_TYPE time64_t 50 | # define STAT_FN(path,data) stat(path, data) 51 | # define STAT_STRUCT struct stat 52 | # define STAT_TIME_TYPE time_t 53 | # endif 54 | # define FILETIME2time_t(t) ((time_t)(t)) 55 | # else 56 | //# define STAT_FN(path,data) _stat64(path, data) 57 | //# define STAT_STRUCT struct __stat64 58 | //# define STAT_TIME_TYPE FILETIME 59 | # define STAT_STRUCT WIN32_FIND_DATAA 60 | # define STAT_TIME_TYPE time_t 61 | //# define FILETIME2time_t(t) (STAT_TIME_TYPE)((*(__int64*)&(t) - 116444736000000000) / 10000000) 62 | # define FILETIME2time_t(t) (STAT_TIME_TYPE)(((__int64)(t).dwLowDateTime + ((__int64)(t).dwHighDateTime * 0x100000000) - 116444736000000000) / 10000000) 63 | # endif 64 | 65 | #elif defined(DIRTRAV_GENERATE_WIDE) 66 | 67 | # include "dirtravw.h" 68 | # define DIRCHAR wchar_t 69 | # define DIRSTRLEN wcslen 70 | # define DIRSTRCPY wcscpy 71 | # define DIRSTRDUP wcsdup 72 | # define DIRPRINTF wprintf 73 | # define DIRTEXT_(s) L##s 74 | # define DIRTEXT(s) DIRTEXT_(s) 75 | //# define DIRFN(fn) wide_##fn 76 | # define DIRTRAVFN(fn) dirtravw_##fn 77 | # define DIRWFN(fn) w##fn 78 | # define DIR_WFN(fn) _w##fn 79 | # define DIR_WUFN(fn) _W##fn 80 | # define DIRWINFN(fn) fn##W 81 | # define STAT_FN(path,data) _wstat64(path, data) 82 | # if !defined(_WIN32) || defined(FORCE_OPENDIR) 83 | # define STAT_STRUCT struct __stat64 84 | # define FILETIME2time_t(t) ((time_t)(t)) 85 | # else 86 | # define STAT_STRUCT WIN32_FIND_DATAW 87 | //# define FILETIME2time_t(t) (STAT_TIME_TYPE)((*(__int64*)&(t) - 116444736000000000) / 10000000) 88 | # define FILETIME2time_t(t) (STAT_TIME_TYPE)(((__int64)(t).dwLowDateTime + ((__int64)(t).dwHighDateTime * 0x100000000) - 116444736000000000) / 10000000) 89 | # endif 90 | # define STAT_TIME_TYPE time_t 91 | 92 | #else 93 | 94 | # error Must define DIRTRAV_GENERATE or DIRTRAV_GENERATE_WIDE when compiling this file 95 | 96 | #endif 97 | 98 | #ifdef _WIN32 99 | # include 100 | # define PATH_SEPARATOR '\\' 101 | #else 102 | # define PATH_SEPARATOR '/' 103 | #endif 104 | 105 | struct DIRTRAVFN(entry_internal_struct) { 106 | struct DIRTRAVFN(entry_struct) external; 107 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 108 | DIRWINFN(WIN32_FIND_DATA) direntry; 109 | #else 110 | STAT_STRUCT statbuf; 111 | #endif 112 | const DIRCHAR* toppath; /////TO DO: consider making this public 113 | }; 114 | 115 | DLL_EXPORT_DIRTRAV void DIRTRAVFN(get_version) (int* pmajor, int* pminor, int* pmicro) 116 | { 117 | if (pmajor) 118 | *pmajor = DIRTRAV_VERSION_MAJOR; 119 | if (pminor) 120 | *pminor = DIRTRAV_VERSION_MINOR; 121 | if (pmicro) 122 | *pmicro = DIRTRAV_VERSION_MICRO; 123 | } 124 | 125 | DLL_EXPORT_DIRTRAV const DIRCHAR* DIRTRAVFN(get_version_string) () 126 | { 127 | return DIRTEXT(DIRTRAV_VERSION_STRING); 128 | } 129 | 130 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(supports_elevate_access) () 131 | { 132 | #ifdef _WIN32 133 | return 1; 134 | #else 135 | return 0; 136 | #endif 137 | } 138 | 139 | DLL_EXPORT_DIRTRAV const DIRCHAR* DIRTRAVFN(elevate_access) () 140 | { 141 | #ifdef _WIN32 142 | //enable SE_BACKUP_NAME privilege 143 | TOKEN_PRIVILEGES NewState; 144 | LUID luid; 145 | HANDLE hToken = NULL; 146 | const DIRCHAR* result = NULL; 147 | //open process token for this process 148 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { 149 | result = DIRTEXT("Failed OpenProcessToken"); 150 | } else { 151 | //get local unique ID for privilege. 152 | if (!LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &luid)) { 153 | result = DIRTEXT("Failed LookupPrivilegeValue"); 154 | } else { 155 | //adjust token privilege 156 | NewState.PrivilegeCount = 1; 157 | NewState.Privileges[0].Luid = luid; 158 | NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 159 | if (!AdjustTokenPrivileges(hToken, FALSE, &NewState, 0, NULL, NULL)) { 160 | result = DIRTEXT("Failed AdjustTokenPrivileges"); 161 | } 162 | } 163 | CloseHandle(hToken); 164 | } 165 | return result; 166 | #else 167 | return DIRTEXT("Privilege elevation not implemented on this platform"); 168 | #endif 169 | } 170 | 171 | int DIRTRAVFN(iteration) (struct DIRTRAVFN(entry_internal_struct)* parentfolderinfo, DIRTRAVFN(file_callback_fn) filecallback, DIRTRAVFN(folder_callback_fn) foldercallbackbefore, DIRTRAVFN(folder_callback_fn) foldercallbackafter, void* callbackdata) 172 | { 173 | int statusbefore; 174 | int status = 0; 175 | DIRCHAR* fullpath; 176 | struct DIRTRAVFN(entry_internal_struct) info; 177 | size_t filenamelen; 178 | const DIRCHAR* directory = parentfolderinfo->external.fullpath; 179 | size_t directorylen = DIRSTRLEN(directory); 180 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 181 | size_t fullpathlen; 182 | HANDLE dir; 183 | DIRCHAR* searchpath; 184 | size_t searchpathlen; 185 | //determine search path 186 | searchpath = (DIRCHAR*)malloc((directorylen + 4 + 7) * sizeof(DIRCHAR)); 187 | if (directorylen > 2 && directory[1] == ':') { 188 | memcpy(searchpath, DIRTEXT("\\\\?\\"), 4 * sizeof(DIRCHAR)); 189 | searchpathlen = 4; 190 | } else { 191 | searchpathlen = 0; 192 | } 193 | memcpy(searchpath + searchpathlen, directory, directorylen * sizeof(DIRCHAR)); 194 | searchpathlen += directorylen; 195 | if (searchpathlen > 0 && searchpath[searchpathlen - 1] != PATH_SEPARATOR) 196 | searchpath[searchpathlen++] = PATH_SEPARATOR; 197 | searchpath[searchpathlen] = '*'; 198 | searchpath[searchpathlen + 1] = 0; 199 | //get directory contents 200 | info.external.parentpath = directory; 201 | info.external.parentinfo = (struct DIRTRAVFN(entry_struct)*)parentfolderinfo; 202 | info.external.callbackdata = callbackdata; 203 | info.toppath = parentfolderinfo->toppath; 204 | #ifdef FIND_FIRST_EX_LARGE_FETCH 205 | dir = DIRWINFN(FindFirstFileEx)(searchpath, FindExInfoBasic, &info.direntry, FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); 206 | if (dir == INVALID_HANDLE_VALUE /*&& GetLastError() == ERROR_NOT_SUPPORTED*/) 207 | dir = DIRWINFN(FindFirstFile)(searchpath, &info.direntry); 208 | #else 209 | dir = DIRWINFN(FindFirstFile)(searchpath, &info.direntry); 210 | #endif 211 | if (dir != INVALID_HANDLE_VALUE) { 212 | //process files and directories 213 | fullpathlen = directorylen + 1; 214 | fullpath = (DIRCHAR*)malloc(fullpathlen * sizeof(DIRCHAR)); 215 | memcpy(fullpath, directory, directorylen * sizeof(DIRCHAR)); 216 | do { 217 | filenamelen = DIRSTRLEN(info.direntry.cFileName); 218 | if (directorylen + filenamelen + 2 > fullpathlen) { 219 | fullpathlen = directorylen + filenamelen + 2; 220 | fullpath = (DIRCHAR*)realloc(fullpath, fullpathlen * sizeof(DIRCHAR)); 221 | } 222 | memcpy(fullpath + directorylen, info.direntry.cFileName, filenamelen * sizeof(DIRCHAR)); 223 | fullpath[directorylen + filenamelen] = 0; 224 | info.external.filename = info.direntry.cFileName; 225 | info.external.fullpath = fullpath; /////TO DO: use info.fullpath instead of fullpath 226 | if (info.direntry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 227 | //process subdirectory 228 | if (!(info.direntry.cFileName[0] == '.' && (info.direntry.cFileName[1] == 0 || (info.direntry.cFileName[1] == '.' && info.direntry.cFileName[2] == 0)))) { 229 | info.external.folderlocaldata = NULL; 230 | //add trailing separator 231 | fullpath[directorylen + filenamelen] = PATH_SEPARATOR; 232 | fullpath[directorylen + filenamelen + 1] = 0; 233 | //call callback before processing folder 234 | if (foldercallbackbefore) 235 | statusbefore = (*foldercallbackbefore)((DIRTRAVFN(entry))&info); 236 | else 237 | statusbefore = 0; 238 | //recurse for subdirectory 239 | if (statusbefore == 0) 240 | status = DIRTRAVFN(iteration)(&info, filecallback, foldercallbackbefore, foldercallbackafter, callbackdata); 241 | else if (statusbefore > 0) 242 | status = statusbefore; 243 | //call callback after processing folder 244 | if (foldercallbackafter && statusbefore <= 0) 245 | status = (*foldercallbackafter)((DIRTRAVFN(entry))&info); 246 | } 247 | } else { 248 | //process file 249 | if (filecallback) { 250 | status = (*filecallback)((DIRTRAVFN(entry))&info); 251 | } 252 | } 253 | } while (status == 0 && DIRWINFN(FindNextFile)(dir, &info.direntry)); 254 | FindClose(dir); 255 | free(fullpath); 256 | } else { 257 | //unable to get directory contents 258 | //status = -1; 259 | } 260 | free(searchpath); 261 | #else 262 | DIR_WUFN(DIR)* dir; 263 | struct DIR_WFN(dirent)* direntry; 264 | //get directory contents 265 | info.external.parentpath = directory; 266 | info.external.parentinfo = (struct DIRTRAVFN(entry_struct)*)parentfolderinfo; 267 | info.external.callbackdata = callbackdata; 268 | info.toppath = parentfolderinfo->toppath; 269 | if ((dir = DIR_WFN(opendir)(directory)) != NULL) { 270 | //process files and directories 271 | while (status == 0 && (direntry = DIR_WFN(readdir)(dir)) != NULL) { 272 | filenamelen = DIRSTRLEN(direntry->d_name); 273 | fullpath = (DIRCHAR*)malloc((directorylen + filenamelen + 2) * sizeof(DIRCHAR)); 274 | memcpy(fullpath, directory, directorylen * sizeof(DIRCHAR)); 275 | memcpy(fullpath + directorylen, direntry->d_name, filenamelen * sizeof(DIRCHAR)); 276 | fullpath[directorylen + filenamelen] = 0; 277 | info.external.filename = direntry->d_name; 278 | info.external.fullpath = fullpath; 279 | if (STAT_FN(fullpath, &(info.statbuf)) == 0) { 280 | if (S_ISDIR(info.statbuf.st_mode)) { 281 | //process subdirectory 282 | if (!(direntry->d_name[0] == '.' && (direntry->d_name[1] == 0 || (direntry->d_name[1] == '.' && direntry->d_name[2] == 0)))) { 283 | info.external.folderlocaldata = NULL; 284 | //add trailing separator 285 | fullpath[directorylen + filenamelen] = PATH_SEPARATOR; 286 | fullpath[directorylen + filenamelen + 1] = 0; 287 | //call callback before processing folder 288 | if (foldercallbackbefore) 289 | statusbefore = (*foldercallbackbefore)((DIRTRAVFN(entry))&info); 290 | else 291 | statusbefore = 0; 292 | //recurse for subdirectory if requested 293 | if (statusbefore == 0) 294 | status = DIRTRAVFN(iteration)(&info, filecallback, foldercallbackbefore, foldercallbackafter, callbackdata); 295 | else if (statusbefore > 0) 296 | status = statusbefore; 297 | //call callback after processing folder 298 | if (foldercallbackafter && statusbefore <= 0) 299 | status = (*foldercallbackafter)((DIRTRAVFN(entry))&info); 300 | } 301 | } else { 302 | //process file 303 | if (filecallback) { 304 | info.external.filename = direntry->d_name; 305 | info.external.fullpath = fullpath; 306 | status = (*filecallback)((DIRTRAVFN(entry))&info); 307 | } 308 | } 309 | } 310 | free(fullpath); 311 | } 312 | DIR_WFN(closedir)(dir); 313 | } else { 314 | //unable to get directory contents 315 | //status = -1; 316 | } 317 | #endif 318 | return status; 319 | } 320 | 321 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(traverse_directory) (const DIRCHAR* directory, DIRTRAVFN(file_callback_fn) filecallback, DIRTRAVFN(folder_callback_fn) foldercallbackbefore, DIRTRAVFN(folder_callback_fn) foldercallbackafter, void* callbackdata) 322 | { 323 | int status; 324 | struct DIRTRAVFN(entry_internal_struct) info; 325 | size_t directorylen = DIRSTRLEN(directory); 326 | DIRCHAR* fullpath = NULL; 327 | if (directorylen > 0 && directory[directorylen - 1] != PATH_SEPARATOR) { 328 | //add trailing separator if missing 329 | fullpath = (DIRCHAR*)malloc((directorylen + 2) * sizeof(DIRCHAR)); 330 | memcpy(fullpath, directory, directorylen * sizeof(DIRCHAR)); 331 | fullpath[directorylen] = PATH_SEPARATOR; 332 | fullpath[directorylen + 1] = 0; 333 | } 334 | memset(&info, 0, sizeof(info)); 335 | //info.external.fullname = NULL;/////TO DO 336 | info.external.fullpath = (fullpath ? fullpath : directory); 337 | //info.external.parentpath = NULL; 338 | info.external.callbackdata = callbackdata; 339 | info.toppath = info.external.fullpath; 340 | status = DIRTRAVFN(iteration)(&info, filecallback, foldercallbackbefore, foldercallbackafter, callbackdata); 341 | if (fullpath) 342 | free(fullpath); 343 | return status; 344 | } 345 | 346 | int DIRTRAVFN(traverse_fullpath_parts_from_position) (const DIRCHAR* fullpath, size_t pos, DIRTRAVFN(folder_callback_fn) foldercallbackbefore, DIRTRAVFN(folder_callback_fn) foldercallbackafter, struct DIRTRAVFN(entry_internal_struct)* parentfolderinfo) 347 | { 348 | size_t nextpos; 349 | struct DIRTRAVFN(entry_internal_struct) info; 350 | int status = 0; 351 | //skip initial path separator if any 352 | while (fullpath[pos] == PATH_SEPARATOR) 353 | pos++; 354 | //abort if no next part is found 355 | if (!fullpath[pos]) 356 | return 0; 357 | //determine end of current part 358 | nextpos = pos; 359 | while (fullpath[nextpos] && fullpath[nextpos] != PATH_SEPARATOR) 360 | nextpos++; 361 | //recurse through parts 362 | DIRCHAR* currentpath; 363 | //determine current full path 364 | currentpath = (DIRCHAR*)malloc((nextpos + 1) * sizeof(DIRCHAR)); 365 | memcpy(currentpath, fullpath, nextpos * sizeof(DIRCHAR)); 366 | currentpath[nextpos] = 0; 367 | //initialize directory information structure 368 | info.external.filename = currentpath + pos; 369 | info.external.fullpath = currentpath; 370 | info.external.parentpath = parentfolderinfo->external.fullpath; 371 | info.external.parentinfo = (struct DIRTRAVFN(entry_struct)*)parentfolderinfo; 372 | info.external.callbackdata = parentfolderinfo->external.callbackdata; 373 | info.external.folderlocaldata = NULL; 374 | info.toppath = parentfolderinfo->toppath; 375 | //call callback before processing folder 376 | if (foldercallbackbefore && status == 0) { 377 | (status = (*foldercallbackbefore)((DIRTRAVFN(entry))&info)); 378 | } 379 | //recurse through next parts 380 | if (status == 0 && fullpath[nextpos]) 381 | status = DIRTRAVFN(traverse_fullpath_parts_from_position)(fullpath, nextpos, foldercallbackbefore, foldercallbackafter, &info); 382 | //call callback after processing folder 383 | if (foldercallbackafter) { 384 | if (status == 0) 385 | status = (*foldercallbackafter)((DIRTRAVFN(entry))&info); 386 | else 387 | (*foldercallbackafter)((DIRTRAVFN(entry))&info); 388 | } 389 | free(currentpath); 390 | return 0; 391 | } 392 | 393 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(iterate_roots) (DIRTRAVFN(folder_callback_fn) rootcallback, void* callbackdata) 394 | { 395 | struct DIRTRAVFN(entry_struct) info; 396 | //initialize directory information structure 397 | info.fullpath = NULL; 398 | info.filename = NULL; 399 | info.parentpath = NULL; 400 | info.parentinfo = NULL; 401 | info.callbackdata = callbackdata; 402 | info.folderlocaldata = NULL; 403 | #ifdef _WIN32 404 | const DIRCHAR* p; 405 | DIRCHAR* drivelist; 406 | DWORD drivelistlen; 407 | UINT drivetype; 408 | int status = 0; 409 | if ((drivelistlen = DIRWINFN(GetLogicalDriveStrings)(0, NULL)) == 0) 410 | return 1; 411 | if ((drivelist = (DIRCHAR*)malloc(drivelistlen * sizeof(DIRCHAR))) == NULL) 412 | return 2; 413 | if ((drivelistlen = DIRWINFN(GetLogicalDriveStrings)(drivelistlen, drivelist)) == 0) 414 | return 3; 415 | p = drivelist; 416 | while (status == 0 && *p) { 417 | drivetype = DIRWINFN(GetDriveType)(p); 418 | if (drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_REMOTE && drivetype != DRIVE_REMOVABLE && drivetype != DRIVE_CDROM) { 419 | info.fullpath = p; 420 | status = (*rootcallback)(&info); 421 | } 422 | while (*p) 423 | p++; 424 | p++; 425 | } 426 | free(drivelist); 427 | return status; 428 | #else 429 | info.fullpath = "/"; 430 | return (*rootcallback)(&info); 431 | #endif 432 | } 433 | 434 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(traverse_path_parts) (const DIRCHAR* startpath, const DIRCHAR* path, DIRTRAVFN(folder_callback_fn) foldercallbackbefore, DIRTRAVFN(folder_callback_fn) foldercallbackafter, void* callbackdata) 435 | { 436 | size_t i; 437 | size_t pos; 438 | int status; 439 | DIRCHAR* fullpath; 440 | struct DIRTRAVFN(entry_internal_struct) info; 441 | DIRCHAR* startpathfixed; 442 | if (!path || !*path) 443 | return 0; 444 | //construct full path 445 | if (!startpath || !*startpath) { 446 | pos = 0; 447 | fullpath = DIRSTRDUP(path); 448 | startpathfixed = DIRSTRDUP(DIRTEXT("")); 449 | } else { 450 | //add trailing to start path separator if missing 451 | size_t startpathlen = DIRSTRLEN(startpath); 452 | if (startpathlen > 0 && startpath[startpathlen - 1] != PATH_SEPARATOR) { 453 | startpathfixed = (DIRCHAR*)malloc((startpathlen + 2) * sizeof(DIRCHAR)); 454 | memcpy(startpathfixed, startpath, startpathlen * sizeof(DIRCHAR)); 455 | startpathfixed[startpathlen] = PATH_SEPARATOR; 456 | startpathfixed[startpathlen + 1] = 0; 457 | } else { 458 | startpathfixed = DIRSTRDUP(startpath); 459 | } 460 | //determine full path 461 | pos = DIRSTRLEN(startpathfixed); 462 | fullpath = (DIRCHAR*)malloc((pos + DIRSTRLEN(path) + 2) * sizeof(DIRCHAR)); 463 | DIRSTRCPY(fullpath, startpathfixed); 464 | if (pos > 0 && fullpath[pos] != PATH_SEPARATOR && path[0] != PATH_SEPARATOR) 465 | fullpath[pos++] = PATH_SEPARATOR; 466 | /////TO DO: what if startpath ends and path begins with PATH_SEPARATOR? 467 | DIRSTRCPY(fullpath + pos, path); 468 | i = DIRSTRLEN(fullpath); 469 | if (i > 0 && fullpath[i - 1] == PATH_SEPARATOR) 470 | fullpath[i - 1] = 0; 471 | } 472 | //strip double separators (except at the beginning on Windows) 473 | i = 0; 474 | #ifdef _WIN32 475 | if (fullpath[0] == PATH_SEPARATOR && fullpath[1] == PATH_SEPARATOR) { 476 | i = 2; 477 | while (fullpath[i] == PATH_SEPARATOR) 478 | i++; 479 | } 480 | #endif 481 | while (fullpath[i]) { 482 | if (fullpath[i] == PATH_SEPARATOR && fullpath[i + 1] == PATH_SEPARATOR) { 483 | memmove(fullpath + i, fullpath + i + 1, (DIRSTRLEN(fullpath + i + 1) + 1) * sizeof(DIRCHAR)); 484 | if (pos >= i + 1) 485 | pos--; 486 | } else { 487 | i++; 488 | } 489 | } 490 | //strip . and .. entries from path 491 | if (fullpath[0] == '.' && fullpath[1] == PATH_SEPARATOR) { 492 | memmove(fullpath, fullpath + 2, (DIRSTRLEN(fullpath + 2) + 1) * sizeof(DIRCHAR)); 493 | if (pos >= 2) 494 | pos -= 2; 495 | } 496 | i = 0; 497 | while (fullpath[i]) { 498 | if (fullpath[i] == PATH_SEPARATOR && fullpath[i + 1] == '.' && fullpath[i + 2] == PATH_SEPARATOR) { 499 | memmove(fullpath + i, fullpath + i + 2, (DIRSTRLEN(fullpath + i + 2) + 1) * sizeof(DIRCHAR)); 500 | if (pos >= i + 2) 501 | pos -= 2; 502 | } else if (i > 0 && fullpath[i] == PATH_SEPARATOR && fullpath[i + 1] == '.' && fullpath[i + 2] == '.' && (fullpath[i + 3] == PATH_SEPARATOR || fullpath[i + 3] == 0)) { 503 | int startpos = i - 1; 504 | while (startpos > 0 && fullpath[startpos] != PATH_SEPARATOR) 505 | startpos--; 506 | memmove(fullpath + startpos, fullpath + i + 3, (DIRSTRLEN(fullpath + i + 3) + 1) * sizeof(DIRCHAR)); 507 | if (pos >= i + 3) 508 | pos -= 3 + (i - startpos); 509 | i = startpos; 510 | } else { 511 | i++; 512 | } 513 | } 514 | //initialize directory information structure 515 | info.external.filename = NULL; 516 | info.external.fullpath = fullpath; 517 | info.external.parentpath = NULL; 518 | info.external.parentinfo = NULL; 519 | info.external.callbackdata = callbackdata; 520 | info.external.folderlocaldata = NULL; 521 | info.toppath = startpathfixed; 522 | status = DIRTRAVFN(traverse_fullpath_parts_from_position)(fullpath, pos, foldercallbackbefore, foldercallbackafter, &info); 523 | //clean up 524 | free(fullpath); 525 | free(startpathfixed); 526 | return status; 527 | } 528 | 529 | int DIRTRAVFN(recursive_delete_file_callback) (DIRTRAVFN(entry) info) 530 | { 531 | #ifdef _WIN32 532 | if (!DIRWINFN(DeleteFile)(info->fullpath)) 533 | #else 534 | if (unlink(info->fullpath) != 0) 535 | #endif 536 | *((int*)info->callbackdata) |= 1; 537 | return 0; 538 | } 539 | 540 | int DIRTRAVFN(recursive_delete_folder_callback) (DIRTRAVFN(entry) info) 541 | { 542 | #ifdef _WIN32 543 | if (!DIRWINFN(RemoveDirectory)(info->fullpath)) 544 | #else 545 | if (rmdir(info->fullpath) != 0) 546 | #endif 547 | *((int*)info->callbackdata) |= 2; 548 | return 0; 549 | } 550 | 551 | int DIRTRAVFN(recursive_delete) (const DIRCHAR* path) 552 | { 553 | int status = 0; 554 | if (!path || !*path) 555 | return -2; 556 | DIRTRAVFN(traverse_directory)(path, DIRTRAVFN(recursive_delete_file_callback), NULL, DIRTRAVFN(recursive_delete_folder_callback), (void*)&status); 557 | if (status != 0) 558 | return status; 559 | #ifdef _WIN32 560 | if (!DIRWINFN(RemoveDirectory)(path)) 561 | #else 562 | if (rmdir(path) != 0) 563 | #endif 564 | return (2 | 4); 565 | return 0; 566 | } 567 | 568 | int DIRTRAVFN(make_full_path_callback) (DIRTRAVFN(entry) info) 569 | { 570 | #ifdef _WIN32 571 | DIRWINFN(CreateDirectory)(((struct DIRTRAVFN(entry_internal_struct)*)info)->external.fullpath, NULL); 572 | #else 573 | DIRWFN(mkdir)(info->fullpath, *(mode_t*)info->callbackdata); 574 | #endif 575 | return 0; 576 | } 577 | 578 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(make_full_path) (const DIRCHAR* startpath, const DIRCHAR* path, mode_t mode) 579 | { 580 | #ifndef _WIN32 581 | if (mode == 0) 582 | mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; 583 | #endif 584 | return DIRTRAVFN(traverse_path_parts)(startpath, path, DIRTRAVFN(make_full_path_callback), NULL, &mode); 585 | /////TO DO: proper result code indicating if tree was not successfully created 586 | } 587 | 588 | #ifndef MAX_EXTENSION_LENGTH 589 | #define MAX_EXTENSION_LENGTH 12 590 | #endif 591 | 592 | DLL_EXPORT_DIRTRAV const DIRCHAR* DIRTRAVFN(prop_get_extension) (DIRTRAVFN(entry) entry) 593 | { 594 | const DIRCHAR* p; 595 | size_t extlen; 596 | const DIRCHAR* filename = entry->filename; 597 | if (!filename || !*filename) 598 | return NULL; 599 | p = filename + DIRSTRLEN(filename); 600 | extlen = 0; 601 | while (p-- != filename && extlen++ < MAX_EXTENSION_LENGTH) { 602 | if (*p == DIRTEXT('.')) 603 | return p; 604 | } 605 | return NULL; 606 | } 607 | 608 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(prop_is_directory) (DIRTRAVFN(entry) entry) 609 | { 610 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 611 | return (((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0); 612 | #else 613 | return (S_ISDIR(((struct DIRTRAVFN(entry_internal_struct)*)entry)->statbuf.st_mode) ? 1 : 0); 614 | #endif 615 | } 616 | 617 | DLL_EXPORT_DIRTRAV int DIRTRAVFN(prop_is_link) (DIRTRAVFN(entry) entry) 618 | { 619 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 620 | return (((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? 1 : 0); 621 | #elif defined(_WIN32) 622 | return 0; /////TO DO: check if link on Windows 623 | #else 624 | return (S_ISLNK(((struct DIRTRAVFN(entry_internal_struct)*)entry)->statbuf.st_mode) ? 1 : 0); 625 | #endif 626 | } 627 | 628 | DLL_EXPORT_DIRTRAV uint64_t DIRTRAVFN(prop_get_size) (DIRTRAVFN(entry) entry) 629 | { 630 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 631 | return (uint64_t)0x100000000 * ((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.nFileSizeHigh + ((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.nFileSizeLow; 632 | #else 633 | return ((struct DIRTRAVFN(entry_internal_struct)*)entry)->statbuf.st_size; 634 | #endif 635 | } 636 | 637 | DLL_EXPORT_DIRTRAV time_t DIRTRAVFN(prop_get_create_time) (DIRTRAVFN(entry) entry) 638 | { 639 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 640 | return FILETIME2time_t(((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.ftCreationTime); 641 | #else 642 | return FILETIME2time_t(((struct DIRTRAVFN(entry_internal_struct)*)entry)->statbuf.st_ctime); 643 | #endif 644 | } 645 | 646 | DLL_EXPORT_DIRTRAV time_t DIRTRAVFN(prop_get_modify_time) (DIRTRAVFN(entry) entry) 647 | { 648 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 649 | return FILETIME2time_t(((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.ftLastWriteTime); 650 | #else 651 | return FILETIME2time_t(((struct DIRTRAVFN(entry_internal_struct)*)entry)->statbuf.st_mtime); 652 | #endif 653 | } 654 | 655 | DLL_EXPORT_DIRTRAV time_t DIRTRAVFN(prop_get_access_time) (DIRTRAVFN(entry) entry) 656 | { 657 | #if defined(_WIN32) && !defined(FORCE_OPENDIR) 658 | return FILETIME2time_t(((struct DIRTRAVFN(entry_internal_struct)*)entry)->direntry.ftLastAccessTime); 659 | #else 660 | return FILETIME2time_t(((struct DIRTRAVFN(entry_internal_struct)*)entry)->statbuf.st_atime); 661 | #endif 662 | } 663 | 664 | DLL_EXPORT_DIRTRAV const DIRCHAR* DIRTRAVFN(prop_get_top_path) (DIRTRAVFN(entry) entry) 665 | { 666 | return ((struct DIRTRAVFN(entry_internal_struct)*)entry)->toppath; 667 | } 668 | 669 | DLL_EXPORT_DIRTRAV const DIRCHAR* DIRTRAVFN(prop_get_relative_path) (DIRTRAVFN(entry) entry) 670 | { 671 | size_t toppathlen; 672 | toppathlen = DIRSTRLEN(((struct DIRTRAVFN(entry_internal_struct)*)entry)->toppath); 673 | return entry->fullpath + toppathlen; 674 | } 675 | 676 | DLL_EXPORT_DIRTRAV DIRCHAR* DIRTRAVFN(prop_get_owner) (DIRTRAVFN(entry) entry) 677 | { 678 | DIRCHAR* result = NULL; 679 | #ifdef _WIN32 680 | SECURITY_DESCRIPTOR* secdes; 681 | PSID ownersid; 682 | BOOL ownderdefaulted; 683 | DWORD len = 0; 684 | DIRWINFN(GetFileSecurity)(entry->fullpath, OWNER_SECURITY_INFORMATION, NULL, 0, &len); 685 | if (len > 0) { 686 | secdes = (SECURITY_DESCRIPTOR*)malloc(len); 687 | if (DIRWINFN(GetFileSecurity)(entry->fullpath, OWNER_SECURITY_INFORMATION, secdes, len, &len)) { 688 | if (GetSecurityDescriptorOwner(secdes, &ownersid, &ownderdefaulted)) { 689 | SID_NAME_USE accounttype; 690 | DIRCHAR* name; 691 | DIRCHAR* domain; 692 | DWORD domainlen; 693 | len = 0; 694 | domainlen = 0; 695 | if (DIRWINFN(LookupAccountSid)(NULL, ownersid, NULL, &len, NULL, &domainlen, &accounttype) && len > 0 && domainlen > 0) { 696 | name = (DIRCHAR*)malloc(len * sizeof(DIRCHAR)); 697 | domain = (DIRCHAR*)malloc(domainlen * sizeof(DIRCHAR)); 698 | if (DIRWINFN(LookupAccountSid)(NULL, ownersid, name, &len, domain, &domainlen, &accounttype)) { 699 | result = (DIRCHAR*)malloc((domainlen + len + 2) * sizeof(DIRCHAR)); 700 | memcpy(result, domain, domainlen * sizeof(DIRCHAR)); 701 | result[domainlen] = '\\'; 702 | DIRSTRCPY(result + domainlen + 1, name); 703 | } 704 | free(name); 705 | free(domain); 706 | } 707 | #ifdef LOOKUP_SID 708 | if (!result) { 709 | DIRCHAR* sidstring; 710 | if (DIRWINFN(ConvertSidToStringSid)(ownersid, &sidstring)) { 711 | result = DIRSTRDUP(sidstring); 712 | LocalFree(sidstring); 713 | } 714 | } 715 | #endif 716 | } 717 | } 718 | free(secdes); 719 | } 720 | /////TO DO: GROUP_SECURITY_INFORMATION 721 | /////TO DO: query remote server to look up users on network drive - to get volume information about path, see GetVolumeNameForVolumeMountPoint() 722 | #else 723 | struct stat fileinfo; 724 | if (stat(entry->fullpath, &fileinfo) == 0) { 725 | struct passwd* pw = getpwuid(fileinfo.st_uid); 726 | if (pw) { 727 | result = strdup(pw->pw_name); 728 | } 729 | //struct group* gr = getgrgid(fileinfo.st_gid); 730 | } 731 | #endif 732 | return result; 733 | } 734 | 735 | DLL_EXPORT_DIRTRAV void DIRTRAVFN(free) (void* data) 736 | { 737 | free(data); 738 | } 739 | 740 | #undef DIRTRAV_GENERATE 741 | #undef DIRTRAV_GENERATE_WIDE 742 | #undef DIRCHAR 743 | #undef DIRSTRLEN 744 | #undef DIRSTRCPY 745 | #undef DIRSTRDUP 746 | #undef DIRPRINTF 747 | #undef DIRTEXT_ 748 | #undef DIRTEXT 749 | #undef DIRFN 750 | #undef DIRWFN 751 | #undef DIR_WFN 752 | #undef DIR_WUFN 753 | #undef DIRWINFN 754 | #undef STAT_FN 755 | #undef STAT_STRUCT 756 | #undef STAT_TIME_TYPE 757 | #undef FILETIME2time_t 758 | -------------------------------------------------------------------------------- /src/folderstats.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef _WIN32 11 | # undef __MSVCRT_VERSION__ 12 | # define __MSVCRT_VERSION__ 0x0800 13 | # include 14 | #endif 15 | 16 | //#define WIDE_DIRTRAV 1 17 | //#undef WIDE_DIRTRAV 18 | 19 | #ifdef WIDE_DIRTRAV 20 | # include "dirtravw.h" 21 | # include 22 | # include 23 | # define DIRCHAR wchar_t 24 | # define DIRPRINTF wprintf 25 | # define DIRFPRINTF fwprintf 26 | # define DIRTEXT_(s) L##s 27 | # define DIRTEXT(s) DIRTEXT_(s) 28 | # define DIRTRAVFN(fn) dirtravw_##fn 29 | # define DIRCMP strcmp 30 | # ifdef _WIN32 31 | # define DIRCASECMP wcsicmp 32 | # else 33 | # define DIRCASECMP wcscasecmp 34 | # endif 35 | # define DIRTOUPPER towupper 36 | # define DIRTOLOWER towlower 37 | #else 38 | # include "dirtrav.h" 39 | # define DIRCHAR char 40 | # define DIRPRINTF printf 41 | # define DIRFPRINTF fprintf 42 | # define DIRTEXT(s) s 43 | # define DIRTRAVFN(fn) dirtrav_##fn 44 | # define DIRCMP strcmp 45 | # ifdef _WIN32 46 | # define DIRCASECMP stricmp 47 | # else 48 | # define DIRCASECMP strcasecmp 49 | # endif 50 | # define DIRTOUPPER toupper 51 | # define DIRTOLOWER tolower 52 | #endif 53 | 54 | struct folder_data_struct { 55 | int opt_elevated; 56 | int opt_recurse; 57 | unsigned int level; 58 | uint64_t count_folders; 59 | uint64_t count_files; 60 | uint64_t total_size; 61 | unsigned int deepest_level; 62 | time_t oldest_timestamp; 63 | time_t newest_timestamp; 64 | }; 65 | 66 | int file_callback (DIRTRAVFN(entry) info) 67 | { 68 | time_t t; 69 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 70 | data->count_files++; 71 | data->total_size += DIRTRAVFN(prop_get_size)(info); 72 | t = DIRTRAVFN(prop_get_modify_time)(info); 73 | if (t != 0) { 74 | if (t < data->oldest_timestamp || data->oldest_timestamp == 0) 75 | data->oldest_timestamp = t; 76 | if (t > data->newest_timestamp) 77 | data->newest_timestamp = t; 78 | } 79 | //DIRPRINTF(DIRTEXT("%16" PRIu64 " bytes\n"), DIRTRAVFN(prop_get_size)(info));///// 80 | //DIRPRINTF(DIRTEXT("%s\n"), DIRTRAVFN(prop_get_relative_path)(info));///// 81 | return 0; 82 | } 83 | 84 | int folder_callback_before (DIRTRAVFN(entry) info) 85 | { 86 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 87 | data->count_folders++; 88 | data->level++; 89 | if (data->level > data->deepest_level) 90 | data->deepest_level = data->level; 91 | return (data->opt_recurse ? 0 : -1); 92 | } 93 | 94 | int folder_callback_after (DIRTRAVFN(entry) info) 95 | { 96 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 97 | data->level--; 98 | //if (data->level == 0) 99 | // DIRPRINTF(DIRTEXT("\t%" PRIu64 " bytes in %" PRIu64 " files and %" PRIu64 " folders\n"), data->total_size, data->count_files, info->count_folders); 100 | //DIRPRINTF(DIRTEXT("%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\r"), data->count_files, data->count_folders, data->total_size);///// 101 | return 0; 102 | } 103 | 104 | void show_help () 105 | { 106 | DIRPRINTF(DIRTEXT( 107 | "Usage: folderstats [-h] [-r] path ...\n" 108 | "Parameters:\n" 109 | " -h \tdisplay command line help\n" 110 | " -r \trecurse into subdirectories\n" 111 | " -e \tuse elevated privileges (only on Windows)\n" 112 | " path \tpath folder to be analyzed\n" 113 | "Description:\n" 114 | "Gets folder statistics.\n" 115 | "Version: %s\n" 116 | "\n"), DIRTRAVFN(get_version_string)() 117 | ); 118 | } 119 | 120 | int parse_command_line (int argc, DIRCHAR** argv, struct folder_data_struct* data) 121 | { 122 | int i; 123 | //process command line parameters 124 | if (argc <= 1) { 125 | show_help(); 126 | return 0; 127 | } 128 | for (i = 1; i < argc; i++) { 129 | //check for command line parameters 130 | if (argv[i][0] && argv[i][0] == '-') { 131 | switch (DIRTOLOWER(argv[i][1])) { 132 | case 'h' : 133 | case '?' : 134 | show_help(); 135 | _exit(0); 136 | case 'r' : 137 | data->opt_recurse = 1; 138 | break; 139 | case 'e' : 140 | data->opt_elevated = 1; 141 | break; 142 | default : 143 | DIRFPRINTF(stderr, DIRTEXT("Invalid command line parameter: %s\n"), argv[i]); 144 | return 0; 145 | } 146 | } else { 147 | return i; 148 | } 149 | } 150 | return i; 151 | } 152 | 153 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 154 | int main () 155 | { 156 | //get command line arguments 157 | int argc = 0; 158 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 159 | //set correct output (UTF-16 for Windows) 160 | _setmode(_fileno(stdout), _O_U16TEXT); 161 | #else 162 | int main(int argc, char *argv[]) 163 | { 164 | #endif 165 | int i; 166 | int status; 167 | clock_t starttime; 168 | struct folder_data_struct folderdata = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 169 | 170 | //process command line options 171 | folderdata.opt_recurse = 0; 172 | if ((i = parse_command_line(argc, argv, &folderdata)) <= 0) { 173 | return 1; 174 | } 175 | 176 | //elevate access (needed on Windows to see all folders) 177 | if (folderdata.opt_elevated) { 178 | const DIRCHAR* errmsg; 179 | if ((errmsg = DIRTRAVFN(elevate_access)()) != NULL) { 180 | DIRFPRINTF(stderr, DIRTEXT("Error, elevating privileges: %s\n"), errmsg); 181 | } 182 | } 183 | 184 | //process all folders 185 | while (i < argc) { 186 | DIRPRINTF(DIRTEXT("Reading directory from: %s\n"), argv[i]); 187 | //reset counters 188 | folderdata.level = 0; 189 | folderdata.count_folders = 0; 190 | folderdata.count_files = 0; 191 | folderdata.total_size = 0; 192 | folderdata.deepest_level = 0; 193 | folderdata.oldest_timestamp = 0; 194 | folderdata.newest_timestamp = 0; 195 | starttime = clock(); 196 | //process folder 197 | status = DIRTRAVFN(traverse_directory)(argv[i], file_callback, folder_callback_before, folder_callback_after, &folderdata); 198 | //DIRPRINTF(DIRTEXT("\r\t\t\t\t\t\t\t\r"), status);///// 199 | if (status != 0) { 200 | DIRPRINTF(DIRTEXT("Error, status code %i\n"), status); 201 | } else { 202 | DIRPRINTF(DIRTEXT("Folders: %" PRIu64 "\nLevels: %u\nFiles: %" PRIu64 "\nSize: %" PRIu64 " bytes\n"), folderdata.count_folders, folderdata.deepest_level, folderdata.count_files, folderdata.total_size); 203 | DIRPRINTF(DIRTEXT("Elapsed time: %.3f s\n"), (float)(clock() - starttime) / CLOCKS_PER_SEC); 204 | } 205 | i++; 206 | } 207 | 208 | //clean up 209 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 210 | LocalFree(argv); 211 | #endif 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /src/rdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifdef _WIN32 8 | // required for _setmode 9 | # undef __MSVCRT_VERSION__ 10 | # define __MSVCRT_VERSION__ 0x0800 11 | # include 12 | #endif 13 | 14 | #ifdef WIDE_DIRTRAV 15 | #include "dirtravw.h" 16 | # include 17 | # include 18 | # define DIRCHAR wchar_t 19 | # define DIRSTRLEN wcslen 20 | # define DIRPRINTF wprintf 21 | # define DIRSTRFTIME wcsftime 22 | # define DIRTEXT_(s) L##s 23 | # define DIRTEXT(s) DIRTEXT_(s) 24 | # define DIRTRAVFN(fn) dirtravw_##fn 25 | #else 26 | #include "dirtrav.h" 27 | # define DIRCHAR char 28 | # define DIRSTRLEN strlen 29 | # define DIRPRINTF printf 30 | # define DIRSTRFTIME strftime 31 | # define DIRTEXT(s) s 32 | # define DIRTRAVFN(fn) dirtrav_##fn 33 | #endif 34 | 35 | struct dirtrav_struct { 36 | size_t level; 37 | }; 38 | 39 | const DIRCHAR* time2str (time_t datetime) 40 | { 41 | static DIRCHAR buf[20]; 42 | const struct tm* brokendowntime = localtime(&datetime); 43 | DIRSTRFTIME(buf, sizeof(buf) / sizeof(DIRCHAR), DIRTEXT("%Y-%m-%d %H:%M:%S"), brokendowntime); 44 | return buf; 45 | } 46 | 47 | int file_callback (DIRTRAVFN(entry) info) 48 | { 49 | struct dirtrav_struct* folderdata = (info->parentinfo)->callbackdata; 50 | DIRCHAR* owner; 51 | //DIRPRINTF(DIRTEXT("%*s%s\n"), (int)(folderdata->level * 2), DIRTEXT(""), DIRTRAVFN(prop_get_path)(info)); 52 | DIRPRINTF(DIRTEXT("%*s%s"), (int)(folderdata->level * 2), DIRTEXT(""), DIRTRAVFN(prop_get_name)(info)); 53 | DIRPRINTF(DIRTEXT("\t%s"), time2str(DIRTRAVFN(prop_get_create_time)(info))); 54 | DIRPRINTF(DIRTEXT("\t%s"), time2str(DIRTRAVFN(prop_get_modify_time)(info))); 55 | DIRPRINTF(DIRTEXT("%16" PRIu64 " bytes\t"), DIRTRAVFN(prop_get_size)(info)); 56 | owner = DIRTRAVFN(prop_get_owner)(info); 57 | DIRPRINTF(DIRTEXT("%s\n"), (owner ? owner : DIRTEXT("-"))); 58 | DIRTRAVFN(free)(owner); 59 | return 0; 60 | } 61 | 62 | int folder_callback_before (DIRTRAVFN(entry) info) 63 | { 64 | struct dirtrav_struct* data = (struct dirtrav_struct*)info->callbackdata; 65 | //DIRPRINTF(DIRTEXT("%*s[%s]\n"), (int)(data->level * 2), DIRTEXT(""), DIRTRAVFN(prop_get_path)(info)); 66 | DIRPRINTF(DIRTEXT("%*s[%s]\n"), (int)(data->level * 2), DIRTEXT(""), DIRTRAVFN(prop_get_name)(info)); 67 | data->level++; 68 | return 0; 69 | } 70 | 71 | int folder_callback_after (DIRTRAVFN(entry) info) 72 | { 73 | struct dirtrav_struct* data = (struct dirtrav_struct*)info->callbackdata; 74 | data->level--; 75 | return 0; 76 | } 77 | 78 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 79 | int main () 80 | { 81 | //get command line arguments 82 | int argc = 0; 83 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 84 | //set correct output (UTF-16 for Windows) 85 | _setmode(_fileno(stdout), _O_U16TEXT); 86 | #else 87 | int main(int argc, char *argv[]) 88 | { 89 | //set correct output (UTF-8 for Windows) 90 | //_setmode(_fileno(stdout), _O_U8TEXT); 91 | #endif 92 | int status; 93 | struct dirtrav_struct folderdata = {1}; 94 | 95 | if (argc < 2) { 96 | fprintf(stderr, "Missing argument\n"); 97 | return 1; 98 | } 99 | 100 | DIRTRAVFN(elevate_access)(); 101 | 102 | DIRPRINTF(DIRTEXT("[%s]\n"), argv[1]); 103 | 104 | status = DIRTRAVFN(traverse_directory)(argv[1], file_callback, folder_callback_before, folder_callback_after, &folderdata); 105 | if (status != 0) { 106 | fprintf(stderr, "Aborted\n"); 107 | } 108 | 109 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 110 | LocalFree(argv); 111 | #endif 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/test1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef _WIN32 4 | # undef __MSVCRT_VERSION__ 5 | # define __MSVCRT_VERSION__ 0x0800 6 | # include 7 | #endif 8 | 9 | #undef WIDE_DIRTRAV 10 | //#define WIDE_DIRTRAV 1 11 | 12 | #ifdef WIDE_DIRTRAV 13 | # include "dirtravw.h" 14 | # include 15 | # include 16 | # define DIRCHAR wchar_t 17 | # define DIRPRINTF wprintf 18 | # define DIRTEXT_(s) L##s 19 | # define DIRTEXT(s) DIRTEXT_(s) 20 | # define DIRTRAVFN(fn) dirtravw_##fn 21 | #else 22 | # include "dirtrav.h" 23 | # define DIRCHAR char 24 | # define DIRPRINTF printf 25 | # define DIRTEXT(s) s 26 | # define DIRTRAVFN(fn) dirtrav_##fn 27 | #endif 28 | 29 | struct folder_data_struct { 30 | unsigned int level; 31 | }; 32 | 33 | int file_callback (DIRTRAVFN(entry) info) 34 | { 35 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 36 | DIRPRINTF(DIRTEXT("%*c%s\n"), data->level * 2 + 2, DIRTEXT(' '), DIRTRAVFN(prop_get_name)(info)); 37 | DIRPRINTF(DIRTEXT("%*c [%s]\n"), data->level * 2 + 2, DIRTEXT(' '), DIRTRAVFN(prop_get_parentpath)(info)); 38 | DIRPRINTF(DIRTEXT("%*c [%s]\n"), data->level * 2 + 2, DIRTEXT(' '), DIRTRAVFN(prop_get_top_path)(info)); 39 | return 0; 40 | } 41 | 42 | int folder_callback_before (DIRTRAVFN(entry) info) 43 | { 44 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 45 | DIRPRINTF(DIRTEXT("%*c<%s> %s\n"), data->level * 2 + 2, DIRTEXT(' '), DIRTRAVFN(prop_get_path)(info), DIRTRAVFN(prop_get_name)(info)); 46 | DIRPRINTF(DIRTEXT("%*c [%s]\n"), data->level * 2 + 2, DIRTEXT(' '), DIRTRAVFN(prop_get_top_path)(info)); 47 | DIRPRINTF(DIRTEXT("%*c [%s]\n"), data->level * 2 + 2, DIRTEXT(' '), DIRTRAVFN(prop_get_relative_path)(info)); 48 | data->level++; 49 | return 0; 50 | } 51 | 52 | int folder_callback_after (DIRTRAVFN(entry) info) 53 | { 54 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 55 | data->level--; 56 | return 0; 57 | } 58 | 59 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 60 | int main () 61 | { 62 | //get command line arguments 63 | int argc = 0; 64 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 65 | //set correct output (UTF-16 for Windows) 66 | _setmode(_fileno(stdout), _O_U16TEXT); 67 | #else 68 | int main(int argc, char *argv[]) 69 | { 70 | #endif 71 | int i; 72 | int status; 73 | const DIRCHAR* errmsg; 74 | struct folder_data_struct folderdata = {0}; 75 | 76 | DIRPRINTF(DIRTEXT("Version %s\n"), DIRTRAVFN(get_version_string)()); 77 | 78 | if (DIRTRAVFN(supports_elevate_access())) { 79 | if ((errmsg = DIRTRAVFN(elevate_access)()) != NULL) { 80 | DIRPRINTF(DIRTEXT("Error elevating directory access: %s\n"), errmsg); 81 | } 82 | } 83 | 84 | for (i = 1; i < argc; i++) { 85 | status = DIRTRAVFN(traverse_directory)(argv[i], file_callback, folder_callback_before, folder_callback_after, &folderdata); 86 | if (status == 0) 87 | DIRPRINTF(DIRTEXT("Folder traversed successfully\n")); 88 | else 89 | DIRPRINTF(DIRTEXT("Folder not completely traversed\n")); 90 | } 91 | 92 | folderdata.level = 0; 93 | DIRTRAVFN(traverse_path_parts)(DIRTEXT("C:\\TEMP\\Test\\1\\2\\3"), DIRTEXT("4\\5\\6"), folder_callback_before, folder_callback_after, &folderdata); 94 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 95 | LocalFree(argv); 96 | #endif 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /src/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifdef _WIN32 8 | # undef __MSVCRT_VERSION__ 9 | # define __MSVCRT_VERSION__ 0x0800 10 | # include 11 | #endif 12 | 13 | //#define WIDE_DIRTRAV 1 14 | #undef WIDE_DIRTRAV 15 | 16 | #ifdef WIDE_DIRTRAV 17 | # include "dirtravw.h" 18 | # include 19 | # include 20 | # define DIRCHAR wchar_t 21 | # define DIRPRINTF wprintf 22 | # define DIRTEXT_(s) L##s 23 | # define DIRTEXT(s) DIRTEXT_(s) 24 | # define DIRTRAVFN(fn) dirtraw_##fn 25 | # define DIRCMP strcmp 26 | # ifdef _WIN32 27 | # define DIRCASECMP wcsicmp 28 | # else 29 | # define DIRCASECMP wcscasecmp 30 | # endif 31 | #else 32 | # include "dirtrav.h" 33 | # define DIRCHAR char 34 | # define DIRPRINTF printf 35 | # define DIRTEXT(s) s 36 | # define DIRTRAVFN(fn) dirtrav_##fn 37 | # define DIRCMP strcmp 38 | # ifdef _WIN32 39 | # define DIRCASECMP stricmp 40 | # else 41 | # define DIRCASECMP strcasecmp 42 | # endif 43 | #endif 44 | 45 | struct folder_data_struct { 46 | unsigned int level; 47 | uint64_t count_folders; 48 | uint64_t count_files; 49 | uint64_t totalsize; 50 | }; 51 | 52 | int file_callback (DIRTRAVFN(entry) info) 53 | { 54 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 55 | data->count_files++; 56 | data->totalsize += DIRTRAVFN(prop_get_size)(info); 57 | if (data->level == 0) { 58 | char buf[20]; 59 | const DIRCHAR* ext; 60 | DIRCHAR* s; 61 | time_t t; 62 | //show filename and length 63 | DIRPRINTF(DIRTEXT("%s\t%lu"), DIRTRAVFN(prop_get_name)(info), (unsigned long)DIRTRAVFN(prop_get_size)(info)); 64 | //show extension 65 | ext = DIRTRAVFN(prop_get_extension)(info); 66 | DIRPRINTF(DIRTEXT("\t%s"), (ext ? ext : "-")); 67 | //show timestamp 68 | t = DIRTRAVFN(prop_get_modify_time)(info); 69 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&t)); 70 | printf("\t%s", buf); 71 | //show owner 72 | s = DIRTRAVFN(prop_get_owner)(info); 73 | DIRPRINTF(DIRTEXT("\t%s"), (s ? s : "-")); 74 | free(s); 75 | printf("\n"); 76 | } 77 | return 0; 78 | } 79 | 80 | int folder_callback_before (DIRTRAVFN(entry) info) 81 | { 82 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 83 | if (DIRCASECMP(info->fullpath, DIRTEXT("C:\\Windows\\")) == 0) { 84 | DIRPRINTF(DIRTEXT("Skipping: %s\n"), DIRTRAVFN(prop_get_path)(info)); 85 | return -1; 86 | } 87 | data->count_folders++; 88 | if (data->level == 0) 89 | DIRPRINTF(DIRTEXT("%s\n"), DIRTRAVFN(prop_get_path)(info)); 90 | data->level++; 91 | return 0; 92 | } 93 | 94 | int folder_callback_after (DIRTRAVFN(entry) info) 95 | { 96 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 97 | data->level--; 98 | //if (data->level == 0) 99 | // DIRPRINTF(DIRTEXT("\t%" PRIu64 " bytes in %" PRIu64 " files and %" PRIu64 " folders\n"), data->totalsize, data->count_files, info->count_folders); 100 | return 0; 101 | } 102 | 103 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 104 | int main () 105 | { 106 | //get command line arguments 107 | int argc = 0; 108 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 109 | //set correct output (UTF-16 for Windows) 110 | _setmode(_fileno(stdout), _O_U16TEXT); 111 | #else 112 | int main(int argc, char *argv[]) 113 | { 114 | #endif 115 | int status; 116 | clock_t starttime; 117 | struct folder_data_struct folderdata = {0, 0, 0, 0}; 118 | DIRTRAVFN(elevate_access)(); 119 | DIRPRINTF(DIRTEXT("Reading directory from: %s\n"), argv[1]); 120 | starttime = clock(); 121 | status = DIRTRAVFN(traverse_directory)(argv[1], file_callback, folder_callback_before, folder_callback_after, &folderdata); 122 | DIRPRINTF(DIRTEXT("Elapsed time: %.3f s\n"), (float)(clock() - starttime) / CLOCKS_PER_SEC); 123 | DIRPRINTF(DIRTEXT("Status: %i\nFolders: %" PRIu64 "\nFiles: %" PRIu64 "\nSize: %" PRIu64 " bytes\n"), status, folderdata.count_folders, folderdata.count_files, folderdata.totalsize); 124 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 125 | LocalFree(argv); 126 | #endif 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /src/test3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #ifdef _WIN32 7 | #include 8 | #endif 9 | 10 | #ifdef WIDE_DIRTRAV 11 | # include "dirtravw.h" 12 | # define DIRCHAR wchar_t 13 | # define DIRPRINTF wprintf 14 | # define DIRPRINTF_S "ls" 15 | # define DIRTEXT_(s) L##s 16 | # define DIRTEXT(s) DIRTEXT_(s) 17 | # define DIRTRAVFN(fn) dirtravw_##fn 18 | #else 19 | # include "dirtrav.h" 20 | # define DIRCHAR char 21 | # define DIRPRINTF printf 22 | # define DIRPRINTF_S "s" 23 | # define DIRTEXT(s) s 24 | # define DIRTRAVFN(fn) dirtrav_##fn 25 | #endif 26 | 27 | int file_found (DIRTRAVFN(entry) info) 28 | { 29 | //DIRPRINTF(DIRTEXT("%s\n"), info->fullpath);///// 30 | (*(uint64_t*)info->callbackdata)++; 31 | return 0; 32 | } 33 | 34 | int drive_found (DIRTRAVFN(entry) info) 35 | { 36 | //DIRPRINTF(DIRTEXT("%" DIRPRINTF_S "\n"), info->fullpath);///// 37 | return DIRTRAVFN(traverse_directory)(info->fullpath, file_found, NULL, NULL, info->callbackdata); 38 | } 39 | 40 | int main() 41 | { 42 | uint64_t count = 0; 43 | DIRTRAVFN(elevate_access)(); 44 | DIRTRAVFN(iterate_roots)(drive_found, &count); 45 | DIRPRINTF(DIRTEXT("Files found: %" PRIu64 "\n"), count); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /src/tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifdef _WIN32 8 | # undef __MSVCRT_VERSION__ 9 | # define __MSVCRT_VERSION__ 0x0800 10 | # include 11 | #endif 12 | 13 | #ifdef WIDE_DIRTRAV 14 | # include 15 | # include 16 | # include 17 | # define DIRCHAR wchar_t 18 | # define DIRSTRLEN wcslen 19 | # define DIRPRINTF wprintf 20 | # define DIRTEXT_(s) L##s 21 | # define DIRTEXT(s) DIRTEXT_(s) 22 | # define DIRTRAVFN(fn) dirtravw_##fn 23 | #else 24 | # include 25 | # define DIRCHAR char 26 | # define DIRSTRLEN strlen 27 | # define DIRPRINTF printf 28 | # define DIRTEXT(s) s 29 | # define DIRTRAVFN(fn) dirtrav_##fn 30 | #endif 31 | 32 | struct dirtrav_struct { 33 | size_t level; 34 | }; 35 | 36 | struct folderdata_struct { 37 | size_t fullpathlen; 38 | }; 39 | 40 | int folder_callback_before (DIRTRAVFN(entry) info) 41 | { 42 | struct dirtrav_struct* data = info->callbackdata; 43 | /* 44 | const DIRCHAR* fullpath = DIRTRAVFN(prop_get_path)(info); 45 | info->folderlocaldata = malloc(sizeof(struct folderdata_struct)); 46 | ((struct folderdata_struct*)info->folderlocaldata)->fullpathlen = DIRSTRLEN(fullpath); 47 | //DIRPRINTF(DIRTEXT("%*s"), (int)(data->level * 2), DIRTEXT("")); 48 | //DIRPRINTF(DIRTEXT("%s\n"), fullpath + (parentfolderdata ? ((struct folderdata_struct*)parentfolderdata)->fullpathlen : 0)); 49 | //DIRPRINTF(DIRTEXT("%s\n"), fullpath); 50 | //DIRPRINTF(DIRTEXT("%*s%s\n"), (int)(data->level * 2), DIRTEXT(""), filename); 51 | DIRPRINTF(DIRTEXT("%*s%s\n"), (int)(data->level * 2), DIRTEXT(""), fullpath); 52 | */ 53 | data->level++; 54 | DIRPRINTF(DIRTEXT("%*s%s\n"), (int)(data->level * 2), DIRTEXT(""), info->filename); 55 | return 0; 56 | } 57 | 58 | int folder_callback_after (DIRTRAVFN(entry) info) 59 | { 60 | struct dirtrav_struct* data = info->callbackdata; 61 | data->level--; 62 | /* 63 | if (info->folderlocaldata) { 64 | DIRPRINTF(DIRTEXT("%*s%i\n"), (int)(data->level * 2), DIRTEXT(""), (int)((struct folderdata_struct*)info->folderlocaldata)->fullpathlen); 65 | free(info->folderlocaldata); 66 | } 67 | */ 68 | return 0; 69 | } 70 | 71 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 72 | int main () 73 | { 74 | //get command line arguments 75 | int argc = 0; 76 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 77 | //set correct output (UTF-16 for Windows) 78 | _setmode(_fileno(stdout), _O_U16TEXT); 79 | #else 80 | int main(int argc, char *argv[]) 81 | { 82 | #endif 83 | int status; 84 | struct dirtrav_struct folderdata = {0}; 85 | 86 | if (argc < 2) { 87 | fprintf(stderr, "Missing argument\n"); 88 | return 1; 89 | } 90 | 91 | DIRTRAVFN(elevate_access)(); 92 | 93 | DIRPRINTF(DIRTEXT("%s\n"), argv[1]); 94 | 95 | status = DIRTRAVFN(traverse_directory)(argv[1], NULL, folder_callback_before, folder_callback_after, &folderdata); 96 | if (status != 0) { 97 | fprintf(stderr, "Aborted\n"); 98 | } 99 | 100 | #if defined(_WIN32) && defined(WIDE_DIRTRAV) 101 | LocalFree(argv); 102 | #endif 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /test/test1.c: -------------------------------------------------------------------------------- 1 | #include "traverse_directory.h" 2 | #include 3 | #include 4 | #ifdef _WIN32 5 | # undef __MSVCRT_VERSION__ 6 | # define __MSVCRT_VERSION__ 0x0800 7 | # include 8 | #endif 9 | 10 | //#undef WIDE_TRAVERSE_DIRECTORY 11 | 12 | #ifdef WIDE_TRAVERSE_DIRECTORY 13 | # include 14 | # include 15 | # define DIRCHAR wchar_t 16 | # define DIRPRINTF wprintf 17 | # define DIRTEXT_(s) L##s 18 | # define DIRTEXT(s) DIRTEXT_(s) 19 | # define DIRFN(fn) wide_##fn 20 | #else 21 | # define DIRCHAR char 22 | # define DIRPRINTF printf 23 | # define DIRTEXT(s) s 24 | # define DIRFN(fn) fn 25 | #endif 26 | 27 | struct folder_data_struct { 28 | unsigned int level; 29 | }; 30 | 31 | int file_callback (DIRFN(traverse_directory_entry) info, void* parentfolderdata) 32 | { 33 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 34 | DIRPRINTF(DIRTEXT("%*c%s\n"), data->level * 2 + 2, DIRTEXT(' '), DIRFN(get_direntprop_name)(info)); 35 | DIRPRINTF(DIRTEXT("%*c [%s]\n"), data->level * 2 + 2, DIRTEXT(' '), DIRFN(get_direntprop_parentpath)(info)); 36 | return 0; 37 | } 38 | 39 | int folder_callback_before (DIRFN(traverse_directory_entry) info, void** folderdata, void* parentfolderdata) 40 | { 41 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 42 | DIRPRINTF(DIRTEXT("%*c<%s> %s\n"), data->level * 2 + 2, DIRTEXT(' '), DIRFN(get_direntprop_path)(info), DIRFN(get_direntprop_name)(info)); 43 | data->level++; 44 | return 0; 45 | } 46 | 47 | int folder_callback_after (DIRFN(traverse_directory_entry) info, void** folderdata, void* parentfolderdata) 48 | { 49 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 50 | data->level--; 51 | return 0; 52 | } 53 | 54 | #if defined(_WIN32) && defined(WIDE_TRAVERSE_DIRECTORY) 55 | int main () 56 | { 57 | //get command line arguments 58 | int argc = 0; 59 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 60 | //set correct output (UTF-16 for Windows) 61 | _setmode(_fileno(stdout), _O_U16TEXT); 62 | #else 63 | int main(int argc, char *argv[]) 64 | { 65 | #endif 66 | int status; 67 | const DIRCHAR* errmsg; 68 | struct folder_data_struct folderdata = {0}; 69 | 70 | DIRPRINTF(DIRTEXT("Version %s\n"), DIRFN(traverse_directory_get_version_string)()); 71 | 72 | if ((errmsg = DIRFN(traverse_directory_elevate_access)()) != NULL) { 73 | DIRPRINTF(DIRTEXT("Error elevating directory access: %s\n"), errmsg); 74 | } 75 | 76 | status = DIRFN(traverse_directory)(argv[1], file_callback, &folderdata, folder_callback_before, folder_callback_after, &folderdata, NULL); 77 | if (status == 0) 78 | DIRPRINTF(DIRTEXT("Folder traversed successfully\n")); 79 | else 80 | DIRPRINTF(DIRTEXT("Folder not completely traversed\n")); 81 | 82 | folderdata.level = 0; 83 | DIRFN(traverse_path_parts)(DIRTEXT("C:\\TEMP\\Test\\1\\2\\3"), DIRTEXT("4\\5\\6"), folder_callback_before, folder_callback_after, &folderdata, NULL); 84 | #if defined(_WIN32) && defined(WIDE_TRAVERSE_DIRECTORY) 85 | LocalFree(argv); 86 | #endif 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /test/test2.c: -------------------------------------------------------------------------------- 1 | #include "traverse_directory.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #ifdef _WIN32 9 | # undef __MSVCRT_VERSION__ 10 | # define __MSVCRT_VERSION__ 0x0800 11 | # include 12 | #endif 13 | 14 | //#undef WIDE_TRAVERSE_DIRECTORY 15 | 16 | #ifdef WIDE_TRAVERSE_DIRECTORY 17 | # include 18 | # include 19 | # define DIRCHAR wchar_t 20 | # define DIRPRINTF wprintf 21 | # define DIRTEXT_(s) L##s 22 | # define DIRTEXT(s) DIRTEXT_(s) 23 | # define DIRFN(fn) wide_##fn 24 | # define DIRCMP strcmp 25 | # ifdef _WIN32 26 | # define DIRCASECMP wcsicmp 27 | # else 28 | # define DIRCASECMP wcscasecmp 29 | # endif 30 | #else 31 | # define DIRCHAR char 32 | # define DIRPRINTF printf 33 | # define DIRTEXT(s) s 34 | # define DIRFN(fn) fn 35 | # define DIRCMP strcmp 36 | # ifdef _WIN32 37 | # define DIRCASECMP stricmp 38 | # else 39 | # define DIRCASECMP strcasecmp 40 | # endif 41 | #endif 42 | 43 | struct folder_data_struct { 44 | unsigned int level; 45 | uint64_t count_folders; 46 | uint64_t count_files; 47 | uint64_t totalsize; 48 | }; 49 | 50 | int file_callback (DIRFN(traverse_directory_entry) info, void* parentfolderdata) 51 | { 52 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 53 | data->count_files++; 54 | data->totalsize += DIRFN(get_direntprop_size)(info); 55 | if (data->level == 0) 56 | DIRPRINTF(DIRTEXT("%s\n"), DIRFN(get_direntprop_name)(info)); 57 | return 0; 58 | } 59 | 60 | int folder_callback_before (DIRFN(traverse_directory_entry) info, void** folderdata, void* parentfolderdata) 61 | { 62 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 63 | if (DIRCASECMP(info->fullpath, DIRTEXT("C:\\Windows\\")) == 0) { 64 | DIRPRINTF(DIRTEXT("Skipping: %s\n"), DIRFN(get_direntprop_path)(info)); 65 | return -1; 66 | } 67 | data->count_folders++; 68 | if (data->level == 0) 69 | DIRPRINTF(DIRTEXT("%s\n"), DIRFN(get_direntprop_path)(info)); 70 | data->level++; 71 | return 0; 72 | } 73 | 74 | int folder_callback_after (DIRFN(traverse_directory_entry) info, void** folderdata, void* parentfolderdata) 75 | { 76 | struct folder_data_struct* data = (struct folder_data_struct*)info->callbackdata; 77 | data->level--; 78 | //if (data->level == 0) 79 | // DIRPRINTF(DIRTEXT("\t%" PRIu64 " bytes in %" PRIu64 " files and %" PRIu64 " folders\n"), data->totalsize, data->count_files, info->count_folders); 80 | return 0; 81 | } 82 | 83 | #if defined(_WIN32) && defined(WIDE_TRAVERSE_DIRECTORY) 84 | int main () 85 | { 86 | //get command line arguments 87 | int argc = 0; 88 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 89 | //set correct output (UTF-16 for Windows) 90 | _setmode(_fileno(stdout), _O_U16TEXT); 91 | #else 92 | int main(int argc, char *argv[]) 93 | { 94 | #endif 95 | int status; 96 | clock_t starttime; 97 | struct folder_data_struct folderdata = {0, 0, 0, 0}; 98 | DIRFN(traverse_directory_elevate_access)(); 99 | DIRPRINTF(DIRTEXT("Reading directory from: %s\n"), argv[1]); 100 | starttime = clock(); 101 | status = DIRFN(traverse_directory)(argv[1], file_callback, &folderdata, folder_callback_before, folder_callback_after, &folderdata, NULL); 102 | DIRPRINTF(DIRTEXT("Elapsed time: %.3f s\n"), (float)(clock() - starttime) / CLOCKS_PER_SEC); 103 | DIRPRINTF(DIRTEXT("Status: %i\nFolders: %" PRIu64 "\nFiles: %" PRIu64 "\nSize: %" PRIu64 " bytes\n"), status, folderdata.count_folders, folderdata.count_files, folderdata.totalsize); 104 | #if defined(_WIN32) && defined(WIDE_TRAVERSE_DIRECTORY) 105 | LocalFree(argv); 106 | #endif 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /test/tree.c: -------------------------------------------------------------------------------- 1 | #include "traverse_directory.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #ifdef _WIN32 9 | # undef __MSVCRT_VERSION__ 10 | # define __MSVCRT_VERSION__ 0x0800 11 | # include 12 | #endif 13 | 14 | #undef WIDE_TRAVERSE_DIRECTORY 15 | 16 | #ifdef WIDE_TRAVERSE_DIRECTORY 17 | # include 18 | # include 19 | # define DIRCHAR wchar_t 20 | # define DIRSTRLEN wcslen 21 | # define DIRPRINTF wprintf 22 | # define DIRTEXT_(s) L##s 23 | # define DIRTEXT(s) DIRTEXT_(s) 24 | # define DIRFN(fn) wide_##fn 25 | #else 26 | # define DIRCHAR char 27 | # define DIRSTRLEN strlen 28 | # define DIRPRINTF printf 29 | # define DIRTEXT(s) s 30 | # define DIRFN(fn) fn 31 | #endif 32 | 33 | struct traverse_directory_struct { 34 | size_t level; 35 | }; 36 | 37 | struct folderdata_struct { 38 | size_t fullpathlen; 39 | }; 40 | 41 | int folder_callback_before (DIRFN(traverse_directory_entry) info, void** folderdata, void* parentfolderdata) 42 | { 43 | struct traverse_directory_struct* data = (struct traverse_directory_struct*)info->callbackdata; 44 | const DIRCHAR* fullpath = DIRFN(get_direntprop_path)(info); 45 | *folderdata = malloc(sizeof(struct folderdata_struct)); 46 | ((struct folderdata_struct*)*folderdata)->fullpathlen = DIRSTRLEN(fullpath); 47 | //DIRPRINTF(DIRTEXT("%*s"), (int)(data->level * 2), DIRTEXT("")); 48 | //DIRPRINTF(DIRTEXT("%s\n"), fullpath + (parentfolderdata ? ((struct folderdata_struct*)parentfolderdata)->fullpathlen : 0)); 49 | //DIRPRINTF(DIRTEXT("%s\n"), fullpath); 50 | //DIRPRINTF(DIRTEXT("%*s%s\n"), (int)(data->level * 2), DIRTEXT(""), filename); 51 | DIRPRINTF(DIRTEXT("%*s%s\n"), (int)(data->level * 2), DIRTEXT(""), fullpath); 52 | data->level++; 53 | return 0; 54 | } 55 | 56 | int folder_callback_after (DIRFN(traverse_directory_entry) info, void** folderdata, void* parentfolderdata) 57 | { 58 | struct traverse_directory_struct* data = (struct traverse_directory_struct*)info->callbackdata; 59 | data->level--; 60 | if (*folderdata) 61 | free(*folderdata); 62 | return 0; 63 | } 64 | 65 | #if defined(_WIN32) && defined(WIDE_TRAVERSE_DIRECTORY) 66 | int main () 67 | { 68 | //get command line arguments 69 | int argc = 0; 70 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 71 | //set correct output (UTF-16 for Windows) 72 | _setmode(_fileno(stdout), _O_U16TEXT); 73 | #else 74 | int main(int argc, char *argv[]) 75 | { 76 | #endif 77 | int status; 78 | struct traverse_directory_struct folderdata = {0}; 79 | 80 | if (argc < 2) { 81 | fprintf(stderr, "Missing argument\n"); 82 | return 1; 83 | } 84 | 85 | DIRFN(traverse_directory_elevate_access)(); 86 | 87 | status = DIRFN(traverse_directory)(argv[1], NULL/*file_callback*/, &folderdata, folder_callback_before, folder_callback_after, &folderdata, NULL); 88 | if (status != 0) { 89 | fprintf(stderr, "Aborted\n"); 90 | } 91 | 92 | #if defined(_WIN32) && defined(WIDE_TRAVERSE_DIRECTORY) 93 | LocalFree(argv); 94 | #endif 95 | return 0; 96 | } 97 | --------------------------------------------------------------------------------