├── .clang-format ├── .github └── workflows │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── MODULES.md ├── README.md ├── cmake ├── FindWLIBC.cmake ├── WLIBCModules.cmake └── WLIBCTests.cmake ├── include ├── alloca.h ├── byteswap.h ├── dirent.h ├── dlfcn.h ├── err.h ├── errno.h ├── error.h ├── fcntl.h ├── getopt.h ├── grp.h ├── internal │ ├── acl.h │ ├── convert.h │ ├── dirent.h │ ├── error.h │ ├── fcntl.h │ ├── misc.h │ ├── nt.h │ ├── path.h │ ├── registry.h │ ├── sched.h │ ├── security.h │ ├── signal.h │ ├── spawn.h │ ├── stdio.h │ ├── thread.h │ ├── timer.h │ └── validate.h ├── io.h ├── langinfo.h ├── limits.h ├── poll.h ├── posix │ └── limits.h ├── process.h ├── pthread.h ├── pwd.h ├── sched.h ├── signal.h ├── spawn.h ├── stdint.h ├── stdio-ext.h ├── stdio-hooks.h ├── stdio.h ├── stdio_ext.h ├── stdlib.h ├── string.h ├── strings.h ├── sys │ ├── acl.h │ ├── file.h │ ├── fstypes.h │ ├── ioctl.h │ ├── mman.h │ ├── mount.h │ ├── param.h │ ├── random.h │ ├── resource.h │ ├── select.h │ ├── stat.h │ ├── statfs.h │ ├── statvfs.h │ ├── time.h │ ├── times.h │ ├── types.h │ ├── utsname.h │ ├── wait.h │ └── xattr.h ├── sysexits.h ├── termios.h ├── tests │ └── test.h ├── thread.h ├── threads.h ├── unistd.h ├── wchar.h └── wlibc.h ├── src ├── CMakeLists.txt ├── dirent │ ├── CMakeLists.txt │ ├── alphasort.c │ ├── closedir.c │ ├── dirfd.c │ ├── opendir.c │ ├── readdir.c │ ├── rewinddir.c │ ├── scandir.c │ ├── seekdir.c │ └── telldir.c ├── dlfcn │ ├── CMakeLists.txt │ ├── dlclose.c │ ├── dlerror.c │ ├── dlopen.c │ └── dlsym.c ├── errno │ ├── CMakeLists.txt │ └── program.c ├── error │ ├── CMakeLists.txt │ └── error.c ├── fcntl │ ├── CMakeLists.txt │ ├── fcntl.c │ ├── internal.c │ ├── open.c │ └── osfhandle.c ├── getopt │ ├── CMakeLists.txt │ └── getopt.c ├── grp │ ├── CMakeLists.txt │ ├── grent.c │ ├── grgid.c │ └── grnam.c ├── internal │ ├── CMakeLists.txt │ ├── convert.c │ ├── error.c │ ├── misc.c │ ├── path.c │ ├── registry.c │ ├── security.c │ └── wmain.c ├── langinfo │ ├── CMakeLists.txt │ └── langinfo.c ├── poll │ ├── CMakeLists.txt │ ├── fdset.c │ ├── poll.c │ └── select.c ├── pwd │ ├── CMakeLists.txt │ ├── pwent.c │ ├── pwnam.c │ └── pwuid.c ├── sched │ ├── CMakeLists.txt │ ├── affinity.c │ ├── cpuset.c │ ├── open.c │ ├── param.c │ ├── scheduler.c │ └── yield.c ├── signal │ ├── CMakeLists.txt │ ├── internal.c │ ├── raise.c │ ├── sigaction.c │ ├── signal.c │ └── sigprocmask.c ├── spawn │ ├── CMakeLists.txt │ ├── actions.c │ ├── attributes.c │ ├── internal.c │ └── spawn.c ├── stdio │ ├── CMakeLists.txt │ ├── clearerr.c │ ├── fclose.c │ ├── fdopen.c │ ├── feof.c │ ├── ferror.c │ ├── fflush.c │ ├── fgetc.c │ ├── fgets.c │ ├── fileno.c │ ├── fileops.c │ ├── flock.c │ ├── fopen.c │ ├── fputc.c │ ├── fputs.c │ ├── fread.c │ ├── freopen.c │ ├── fseek.c │ ├── ftell.c │ ├── fwrite.c │ ├── getdelim.c │ ├── internal.c │ ├── mode.c │ ├── pclose.c │ ├── perror.c │ ├── pipe-hooks.c │ ├── popen.c │ ├── printf.c │ ├── rename.c │ ├── scanf.c │ ├── setvbuf.c │ ├── stdio-hooks.c │ ├── temp.c │ └── ungetc.c ├── stdlib │ ├── CMakeLists.txt │ ├── mkstemp.c │ ├── setenv.c │ └── unsetenv.c ├── string │ ├── CMakeLists.txt │ ├── ffs.c │ ├── memrchr.c │ ├── strerror.c │ ├── strndup.c │ └── strsignal.c ├── sys │ ├── acl │ │ ├── CMakeLists.txt │ │ ├── acl.c │ │ ├── entry.c │ │ ├── flags.c │ │ ├── object.c │ │ ├── perm.c │ │ ├── qualifier.c │ │ └── tag.c │ ├── file │ │ ├── CMakeLists.txt │ │ └── flock.c │ ├── ioctl │ │ ├── CMakeLists.txt │ │ └── ioctl.c │ ├── mman │ │ ├── CMakeLists.txt │ │ ├── mlock.c │ │ ├── mmap.c │ │ ├── mprotect.c │ │ ├── msync.c │ │ ├── munlock.c │ │ └── munmap.c │ ├── mount │ │ ├── CMakeLists.txt │ │ └── getmntinfo.c │ ├── random │ │ ├── CMakeLists.txt │ │ └── random.c │ ├── resource │ │ ├── CMakeLists.txt │ │ ├── priority.c │ │ ├── rlimit.c │ │ └── rusage.c │ ├── stat │ │ ├── CMakeLists.txt │ │ ├── chflags.c │ │ ├── chmod.c │ │ ├── mkdir.c │ │ ├── stat.c │ │ ├── statx.c │ │ └── utimens.c │ ├── statfs │ │ ├── CMakeLists.txt │ │ └── statfs.c │ ├── statvfs │ │ ├── CMakeLists.txt │ │ └── statvfs.c │ ├── time │ │ ├── CMakeLists.txt │ │ ├── clock.c │ │ ├── gettimeofday.c │ │ ├── internal.c │ │ ├── itimer.c │ │ ├── timer.c │ │ └── utimes.c │ ├── times │ │ ├── CMakeLists.txt │ │ └── times.c │ ├── utsname │ │ ├── CMakeLists.txt │ │ └── uname.c │ ├── wait │ │ ├── CMakeLists.txt │ │ └── waitpid.c │ └── xattr │ │ ├── CMakeLists.txt │ │ ├── getxattr.c │ │ ├── listxattr.c │ │ └── setxattr.c ├── termios │ ├── CMakeLists.txt │ ├── tcattr.c │ └── tcmisc.c ├── thread │ ├── CMakeLists.txt │ ├── barrier.c │ ├── cond.c │ ├── internal.c │ ├── key.c │ ├── mutex.c │ ├── once.c │ ├── rwlock.c │ └── thread.c ├── unistd │ ├── CMakeLists.txt │ ├── access.c │ ├── alarm.c │ ├── chdir.c │ ├── chown.c │ ├── close.c │ ├── conf.c │ ├── domainname.c │ ├── dup.c │ ├── exec.c │ ├── fsync.c │ ├── getcwd.c │ ├── getdtablesize.c │ ├── getpagesize.c │ ├── gid.c │ ├── hostname.c │ ├── isatty.c │ ├── kill.c │ ├── link.c │ ├── lseek.c │ ├── nice.c │ ├── pid.c │ ├── pipe.c │ ├── pread.c │ ├── pwrite.c │ ├── read.c │ ├── readlink.c │ ├── remove.c │ ├── sleep.c │ ├── symlink.c │ ├── truncate.c │ ├── ttyname.c │ ├── uid.c │ └── write.c └── wchar │ ├── CMakeLists.txt │ └── width.c └── tests ├── CMakeLists.txt ├── dirent ├── CMakeLists.txt ├── test-dirent.c ├── test-fdopendir.c ├── test-opendir.c └── test-scandir.c ├── dlfcn ├── CMakeLists.txt └── test-dlfcn.c ├── errno ├── CMakeLists.txt └── test-program.c ├── error ├── CMakeLists.txt ├── test-err.c └── test-error.c ├── fcntl ├── CMakeLists.txt ├── test-at.c ├── test-fcntl.c ├── test-open.c ├── test-path.c └── test-sanity.c ├── getopt ├── CMakeLists.txt └── test-getopt.c ├── grp ├── CMakeLists.txt └── test-grp.c ├── langinfo ├── CMakeLists.txt └── test-langinfo.c ├── poll ├── CMakeLists.txt ├── test-poll.c └── test-select.c ├── pthread ├── CMakeLists.txt ├── test-barrier.c ├── test-cond.c ├── test-key.c ├── test-mutex.c ├── test-once.c ├── test-rwlock.c └── test-thread.c ├── pwd ├── CMakeLists.txt └── test-pwd.c ├── sched ├── CMakeLists.txt ├── test-cpuset.c └── test-sched.c ├── signal ├── CMakeLists.txt ├── test-segmentation-fault.c ├── test-sigaction.c ├── test-signal.c └── test-sigprocmask.c ├── spawn ├── CMakeLists.txt ├── arg.c ├── basic.c ├── cwd.c ├── env.c ├── inherit.c ├── simple.c └── test-spawn.c ├── stdio ├── CMakeLists.txt ├── pipe-helper.c ├── test-fdopen.c ├── test-fflush.c ├── test-fileio.c ├── test-fileno.c ├── test-fopen.c ├── test-freopen.c ├── test-getdelim.c ├── test-internal.c ├── test-pipe.c ├── test-rename.c ├── test-stream.c ├── test-temp.c └── test-ungetc.c ├── stdlib ├── CMakeLists.txt ├── test-env.c └── test-mkstemp.c ├── sys ├── acl │ ├── CMakeLists.txt │ └── test-acl.c ├── file │ ├── CMakeLists.txt │ └── test-flock.c ├── ioctl │ ├── CMakeLists.txt │ └── test-ioctl.c ├── mman │ ├── CMakeLists.txt │ └── test-mmap.c ├── mount │ ├── CMakeLists.txt │ └── test-getmntinfo.c ├── random │ ├── CMakeLists.txt │ └── test-random.c ├── resource │ ├── CMakeLists.txt │ ├── test-priority.c │ └── test-rusage.c ├── stat │ ├── CMakeLists.txt │ ├── test-chflags.c │ ├── test-chmod.c │ ├── test-mkdir.c │ ├── test-stat.c │ └── test-utimens.c ├── statfs │ ├── CMakeLists.txt │ └── test-statfs.c ├── statvfs │ ├── CMakeLists.txt │ └── test-statvfs.c ├── time │ ├── CMakeLists.txt │ ├── test-itimers.c │ └── test-timer.c ├── times │ ├── CMakeLists.txt │ └── test-times.c ├── utsname │ ├── CMakeLists.txt │ └── test-uname.c ├── wait │ ├── CMakeLists.txt │ ├── child-helper.c │ └── test-waitpid.c └── xattr │ ├── CMakeLists.txt │ └── test-xattr.c ├── threads ├── CMakeLists.txt ├── test-cnd.c ├── test-init.c ├── test-mtx.c ├── test-thrd.c └── test-tss.c └── unistd ├── CMakeLists.txt ├── kill-helper.c ├── test-access.c ├── test-alarm.c ├── test-chdir.c ├── test-chown.c ├── test-close.c ├── test-dup.c ├── test-getcwd.c ├── test-io.c ├── test-isatty.c ├── test-kill.c ├── test-link.c ├── test-nice.c ├── test-pio.c ├── test-pipes.c ├── test-remove.c ├── test-symlinks.c ├── test-truncate.c └── test-ttyname.c /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: WLIBC CI/CD 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | msvc-asan: 7 | runs-on: windows-2022 8 | steps: 9 | - uses: actions/checkout@v3 10 | - name: Install ninja 11 | shell: cmd 12 | run: choco install ninja 13 | - name: Build & Test 14 | shell: cmd 15 | run: | 16 | CALL "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" AMD64 17 | SET CC=cl 18 | cmake . -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON 19 | ninja 20 | ctest -VV --repeat until-pass:5 21 | msvc-release: 22 | runs-on: windows-2022 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Install ninja 26 | shell: cmd 27 | run: choco install ninja 28 | - name: Build & Test 29 | shell: cmd 30 | run: | 31 | CALL "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" AMD64 32 | SET CC=cl 33 | cmake . -GNinja -DCMAKE_BUILD_TYPE=Release 34 | ninja 35 | ctest -VV --repeat until-pass:5 36 | clang-release: 37 | runs-on: windows-2022 38 | steps: 39 | - uses: actions/checkout@v3 40 | - name: Install ninja 41 | shell: cmd 42 | run: choco install ninja 43 | - name: Build & Test 44 | shell: cmd 45 | run: | 46 | SET CC=clang 47 | cmake . -GNinja -DCMAKE_BUILD_TYPE=Release 48 | ninja 49 | ctest -VV --repeat until-pass:5 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | 3 | *.obj 4 | *.lib 5 | *.pdb 6 | *.dll 7 | *.exe 8 | 9 | *.sln 10 | *.ninja 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Sibi Siddharthan 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # windows-libc 2 | `windows-libc` is a modular and (mostly)POSIX compliant C library for Windows (10, 11) designed to work alongside `msvcrt`. 3 | 4 | ## Build Instructions 5 | ``` 6 | cmake -DENABLE_=ON .. 7 | ``` 8 | 9 | ## Usage Instructions 10 | ``` 11 | find_package(WLIBC) 12 | ... 13 | target_link_libraries(your-target WLIBC::WLIBC) 14 | ``` 15 | 16 | See MODULES.md for more information regarding the available modules. 17 | 18 | ## Requirements 19 | * CMake 20 | * Enable Developer mode on Windows 10 (for symlinks to work) 21 | * MSVC or Clang compiler (MinGW is not supported) 22 | * (Optional) Add privilege for increase scheduling priority (SE_INC_BASE_PRIORITY_NAME) 23 | 24 | ## Bugs 25 | If you find a bug please raise an issue here -> https://github.com/SibiSiddharthan/windows-libc/issues. 26 | -------------------------------------------------------------------------------- /cmake/FindWLIBC.cmake: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | include(SelectLibraryConfigurations) 9 | include(FindPackageHandleStandardArgs) 10 | 11 | find_path(WLIBC_INCLUDE_DIR NAMES wlibc.h) 12 | find_library(WLIBC_LIBRARY_RELEASE NAMES wlibc wlibcs NAMES_PER_DIR) 13 | find_library(WLIBC_LIBRARY_DEBUG NAMES wlibcd wlibcds NAMES_PER_DIR) 14 | 15 | select_library_configurations(WLIBC) 16 | find_package_handle_standard_args(WLIBC REQUIRED_VARS WLIBC_INCLUDE_DIR WLIBC_LIBRARY) 17 | 18 | if(WLIBC_FOUND) 19 | include_directories(BEFORE ${WLIBC_INCLUDE_DIR}) 20 | set(WLIBC_LIBRARIES ${WLIBC_LIBRARY}) 21 | if(NOT TARGET WLIBC::WLIBC) 22 | add_library(WLIBC::WLIBC UNKNOWN IMPORTED) 23 | set_target_properties(WLIBC::WLIBC PROPERTIES INTERFACE_LINK_OPTIONS "LINKER:/entry:wmainCRTStartup") 24 | endif() 25 | if(WLIBC_LIBRARY_RELEASE) 26 | set_target_properties(WLIBC::WLIBC PROPERTIES IMPORTED_CONFIGURATIONS RELEASE) 27 | set_target_properties(WLIBC::WLIBC PROPERTIES IMPORTED_LOCATION_RELEASE ${WLIBC_LIBRARY_RELEASE}) 28 | endif() 29 | if(WLIBC_LIBRARY_DEBUG) 30 | set_target_properties(WLIBC::WLIBC PROPERTIES IMPORTED_CONFIGURATIONS DEBUG) 31 | set_target_properties(WLIBC::WLIBC PROPERTIES IMPORTED_LOCATION_DEBUG ${WLIBC_LIBRARY_DEBUG}) 32 | endif() 33 | endif() 34 | -------------------------------------------------------------------------------- /cmake/WLIBCModules.cmake: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | include_guard(GLOBAL) 9 | 10 | # Global variable for enabled modules 11 | set(wlibc_enabled_modules) 12 | 13 | # Macro for adding modules 14 | macro(wlibc_add_module ...) 15 | foreach(module ${ARGV}) 16 | list(APPEND wlibc_enabled_modules ${module}) 17 | if(module MATCHES "sys.") 18 | string(REPLACE "sys." "sys/" module ${module}) 19 | endif() 20 | add_subdirectory(${module}) 21 | endforeach() 22 | endmacro() 23 | 24 | 25 | # Function for defining tests 26 | function(wlibc_module ...) 27 | set(wlibc_module_options) 28 | set(wlibc_one_value_keywords MODULE) 29 | set(wlibc_multi_value keywords SOURCES HEADERS) 30 | cmake_parse_arguments(WLIBC_MODULE_ARG "${wlibc_module_options}" "${wlibc_one_value_keywords}" "${wlibc_multi_value}" ${ARGV}) 31 | add_library(${WLIBC_MODULE_ARG_MODULE} OBJECT ${WLIBC_MODULE_ARG_SOURCES}) 32 | foreach(header ${WLIBC_MODULE_ARG_HEADERS}) 33 | if(header MATCHES "sys/") 34 | install(FILES ${CMAKE_SOURCE_DIR}/include/${header} DESTINATION include/sys) 35 | else() 36 | install(FILES ${CMAKE_SOURCE_DIR}/include/${header} DESTINATION include) 37 | endif() 38 | endforeach() 39 | endfunction() 40 | -------------------------------------------------------------------------------- /cmake/WLIBCTests.cmake: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | include_guard(GLOBAL) 9 | 10 | # Function for adding tests 11 | function(wlibc_add_tests ...) 12 | foreach(test ${ARGV}) 13 | add_executable(test-${test} test-${test}.c) 14 | target_link_libraries(test-${test} wlibc) 15 | add_test(NAME test-${test} COMMAND test-${test} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 16 | set_tests_properties(test-${test} PROPERTIES TIMEOUT 30) 17 | 18 | # In a shared build the output directory of the dll needs to be exported to PATH. 19 | if(BUILD_SHARED_LIBS) 20 | string(REPLACE ";" "\;" PATH "$ENV{PATH}") 21 | set_tests_properties(test-${test} PROPERTIES ENVIRONMENT "PATH=${CMAKE_BINARY_DIR}\;${PATH}") 22 | endif() 23 | 24 | endforeach() 25 | endfunction() 26 | -------------------------------------------------------------------------------- /include/alloca.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_ALLOCA_H 9 | #define WLIBC_ALLOCA_H 10 | #include 11 | #endif 12 | -------------------------------------------------------------------------------- /include/byteswap.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_BYTESWAP_H 9 | #define WLIBC_BYTESWAP_H 10 | 11 | // clang-format off 12 | 13 | // Given an unsigned N-bit argument X, reverse the byte order and return. 14 | 15 | // N = 16 16 | #define bswap_16(x) ((((x) & 0x00ffui16) << 8) | \ 17 | (((x) & 0xff00ui16) >> 8)) 18 | 19 | // N = 32 20 | #define bswap_32(x) ((((x) & 0x000000ffui32) << 24) | \ 21 | (((x) & 0x0000ff00ui32) << 8) | \ 22 | (((x) & 0x00ff0000ui32) >> 8) | \ 23 | (((x) & 0xff000000ui32) >> 24)) 24 | 25 | // N = 64 26 | #define bswap_64(x) ((((x) & 0x00000000000000ffui64) << 56) | \ 27 | (((x) & 0x000000000000ff00ui64) << 40) | \ 28 | (((x) & 0x0000000000ff0000ui64) << 24) | \ 29 | (((x) & 0x00000000ff000000ui64) << 8) | \ 30 | (((x) & 0x000000ff00000000ui64) >> 8) | \ 31 | (((x) & 0x0000ff0000000000ui64) >> 24) | \ 32 | (((x) & 0x00ff000000000000ui64) >> 40) | \ 33 | (((x) & 0xff00000000000000ui64) >> 56)) 34 | 35 | // clang-format on 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/dlfcn.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_DLFCN_H 9 | #define WLIBC_DLFCN_H 10 | 11 | #include 12 | 13 | _WLIBC_BEGIN_DECLS 14 | 15 | /* The flags argument to dlopen is unused. Below macros are 16 | provided for compatibilty */ 17 | #define RTLD_LAZY 0x0 // Lazy function call binding. 18 | #define RTLD_NOW 0x0 // Immediate function call binding. 19 | #define RTLD_GLOBAL 0x0 // Load symbols in global namespace 20 | #define RTLD_LOCAL 0x0 // Do not load symbols in global namespace 21 | 22 | extern unsigned long _wlibc_last_dlfcn_error; 23 | 24 | WLIBC_API void *wlibc_dlopen(const char *filename, int flags); 25 | 26 | WLIBC_INLINE void *dlopen(const char *filename, int flags) 27 | { 28 | return wlibc_dlopen(filename, flags); 29 | } 30 | 31 | WLIBC_API char *wlibc_dlerror(void); 32 | 33 | WLIBC_INLINE void *dlerror(void) 34 | { 35 | return wlibc_dlerror(); 36 | } 37 | 38 | WLIBC_API int wlibc_dlclose(void *handle); 39 | 40 | WLIBC_INLINE int dlclose(void *handle) 41 | { 42 | return wlibc_dlclose(handle); 43 | } 44 | 45 | WLIBC_API void *wlibc_dlsym(void *restrict handle, const char *restrict symbol); 46 | 47 | WLIBC_INLINE void *dlsym(void *restrict handle, const char *restrict symbol) 48 | { 49 | return wlibc_dlsym(handle, symbol); 50 | } 51 | 52 | _WLIBC_END_DECLS 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/getopt.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_GETOPT_H 9 | #define WLIBC_GETOPT_H 10 | 11 | #include 12 | 13 | _WLIBC_BEGIN_DECLS 14 | 15 | extern char *optarg; // Stores the parameter given to an option. 16 | extern int optind; // Next index of arv to be processed. 17 | extern int opterr; // Controls printing of error messages. 18 | extern int optopt; // Stores the unknown option. 19 | 20 | struct option 21 | { 22 | const char *name; 23 | int has_arg; 24 | int *flag; 25 | int val; 26 | }; 27 | 28 | /* Names for the values of the 'has_arg' field of 'struct option'. */ 29 | 30 | #define no_argument 0 31 | #define required_argument 1 32 | #define optional_argument 2 33 | 34 | WLIBC_API int wlibc_common_getopt(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex); 35 | 36 | WLIBC_INLINE int getopt(int argc, char *argv[], const char *optstring) 37 | { 38 | return wlibc_common_getopt(argc, argv, optstring, NULL, NULL); 39 | } 40 | 41 | WLIBC_INLINE int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex) 42 | { 43 | return wlibc_common_getopt(argc, argv, optstring, longopts, longindex); 44 | } 45 | 46 | _WLIBC_END_DECLS 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/internal/convert.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_CONVERT_INTERNAL_H 9 | #define WLIBC_CONVERT_INTERNAL_H 10 | 11 | #include 12 | #include 13 | 14 | struct timespec LARGE_INTEGER_to_timespec(LARGE_INTEGER LT); 15 | // struct timespec is greater than 8 bytes, pass it as pointer. 16 | LARGE_INTEGER timespec_to_LARGE_INTEGER(const struct timespec *time); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/internal/dirent.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_DIRENT_INTERNAL_H 9 | #define WLIBC_DIRENT_INTERNAL_H 10 | 11 | #include 12 | #include 13 | 14 | typedef struct _WLIBC_DIR 15 | { 16 | unsigned int magic; 17 | int fd; 18 | void *buffer; 19 | size_t offset; 20 | size_t read_data; 21 | size_t received_data; 22 | RTL_CRITICAL_SECTION critical; 23 | } DIR; 24 | 25 | #define DIR_STREAM_MAGIC 0x1 26 | #define VALIDATE_DIR_STREAM(stream, ret) \ 27 | if (stream == NULL || stream->magic != DIR_STREAM_MAGIC) \ 28 | { \ 29 | errno = EBADF; \ 30 | return ret; \ 31 | } 32 | 33 | #define LOCK_DIR_STREAM(stream) RtlEnterCriticalSection(&(stream->critical)) 34 | #define UNLOCK_DIR_STREAM(stream) RtlLeaveCriticalSection(&(stream->critical)) 35 | 36 | #define DIRENT_DIR_BUFFER_SIZE 131072 // 128 KB. This allows a minimum of 250 entries. 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/internal/error.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_INTERNAL_ERROR_H 9 | #define WLIBC_INTERNAL_ERROR_H 10 | 11 | #include 12 | 13 | void map_doserror_to_errno(DWORD error); 14 | void map_ntstatus_to_errno(NTSTATUS status); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/internal/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_MB_WC_CONVERT_H 9 | #define WLIBC_MB_WC_CONVERT_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | char *wc_to_mb(const wchar_t *wstr); 16 | wchar_t *mb_to_wc(const char *str); 17 | 18 | char *mbstrcat(const char *str1, const char *str2); 19 | wchar_t *wcstrcat(const wchar_t *wstr1, const wchar_t *wstr2); 20 | 21 | int is_absolute_path(const char *str); 22 | int is_absolute_pathw(const wchar_t *wstr); 23 | 24 | // .exe, .bat, .com, .cmd 25 | int has_executable_extenstion(const wchar_t *wstr); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/internal/path.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_PATH_INTERNAL_H 9 | #define WLIBC_PATH_INTERNAL_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // \Device\HarddiskVolume1\Windows\System32 17 | UNICODE_STRING *get_absolute_ntpath2(int dirfd, const char *path, handle_t *type); 18 | UNICODE_STRING *get_fd_ntpath(int fd); 19 | 20 | WLIBC_INLINE UNICODE_STRING *get_absolute_ntpath(int dirfd, const char *path) 21 | { 22 | return get_absolute_ntpath2(dirfd, path, NULL); 23 | } 24 | 25 | // C:\Windows\System32 26 | UNICODE_STRING *get_absolute_dospath(int dirfd, const char *path); 27 | UNICODE_STRING *get_fd_dospath(int fd); 28 | 29 | UNICODE_STRING *ntpath_to_dospath(const UNICODE_STRING *ntpath); 30 | UNICODE_STRING *dospath_to_ntpath(const UNICODE_STRING *dospath); 31 | 32 | UNICODE_STRING *get_handle_ntpath(HANDLE handle); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/internal/registry.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_REGISTRY_INTERNAL_H 9 | #define WLIBC_REGISTRY_INTERNAL_H 10 | 11 | #include 12 | #include 13 | 14 | void *get_registry_value(const wchar_t *restrict basekey, const wchar_t *restrict subkey, size_t *restrict outsize); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/internal/sched.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SCHED_INTERNAL_H 9 | #define WLIBC_SCHED_INTERNAL_H 10 | 11 | #include 12 | 13 | #define VALIDATE_SCHED_POLICY(policy, error, ret) \ 14 | if (policy != SCHED_IDLE && policy != SCHED_RR && policy != SCHED_FIFO && policy != SCHED_BATCH && policy != SCHED_SPORADIC) \ 15 | { \ 16 | errno = error; \ 17 | return ret; \ 18 | } 19 | 20 | #define VALIDATE_SCHED_PRIORITY(priority, error, ret) \ 21 | if ((priority) > SCHED_MAX_PRIORITY || (priority) < SCHED_MIN_PRIORITY) \ 22 | { \ 23 | errno = error; \ 24 | return ret; \ 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/internal/signal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SIGNAL_INTERNAL_H 9 | #define WLIBC_SIGNAL_INTERNAL_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef struct _siginfo 16 | { 17 | signal_t action; 18 | int flags; 19 | int mask; 20 | } siginfo; 21 | 22 | extern RTL_SRWLOCK _wlibc_signal_srw; 23 | extern siginfo _wlibc_signal_table[NSIG]; 24 | 25 | void signal_init(void); 26 | void signal_cleanup(void); 27 | 28 | void get_siginfo(int sig, siginfo *sinfo); 29 | void set_siginfo(int sig, const siginfo *sinfo); 30 | 31 | #define SHARED_LOCK_SIGNAL_TABLE() RtlAcquireSRWLockShared(&_wlibc_signal_srw) 32 | #define SHARED_UNLOCK_SIGNAL_TABLE() RtlReleaseSRWLockShared(&_wlibc_signal_srw) 33 | #define EXCLUSIVE_LOCK_SIGNAL_TABLE() RtlAcquireSRWLockExclusive(&_wlibc_signal_srw) 34 | #define EXCLUSIVE_UNLOCK_SIGNAL_TABLE() RtlReleaseSRWLockExclusive(&_wlibc_signal_srw) 35 | 36 | #define VALIDATE_SIGSET(sigset) VALIDATE_PTR(sigset, EINVAL, -1) 37 | 38 | #define VALIDATE_SIGNAL(signal) \ 39 | if (signal <= 0 || signal >= NSIG) \ 40 | { \ 41 | errno = EINVAL; \ 42 | return -1; \ 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/internal/spawn.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SPAWN_INTERNAL_H 9 | #define WLIBC_SPAWN_INTERNAL_H 10 | 11 | #include 12 | #include 13 | 14 | typedef struct _processinfo 15 | { 16 | HANDLE handle; 17 | DWORD id; 18 | } processinfo; 19 | 20 | extern processinfo *_wlibc_process_table; 21 | extern size_t _wlibc_process_table_size; 22 | extern size_t _wlibc_child_process_count; 23 | 24 | extern RTL_SRWLOCK _wlibc_process_table_srwlock; 25 | 26 | void process_init(void); 27 | void process_cleanup(void); 28 | 29 | void get_processinfo(pid_t pid, processinfo *pinfo); 30 | 31 | int add_child(DWORD id, HANDLE child); 32 | void delete_child(DWORD id); 33 | 34 | #define SHARED_LOCK_PROCESS_TABLE() RtlAcquireSRWLockShared(&_wlibc_process_table_srwlock) 35 | #define SHARED_UNLOCK_PROCESS_TABLE() RtlReleaseSRWLockShared(&_wlibc_process_table_srwlock) 36 | #define EXCLUSIVE_LOCK_PROCESS_TABLE() RtlAcquireSRWLockExclusive(&_wlibc_process_table_srwlock) 37 | #define EXCLUSIVE_UNLOCK_PROCESS_TABLE() RtlReleaseSRWLockExclusive(&_wlibc_process_table_srwlock) 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/internal/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_THREAD_INTERNAL_H 9 | #define WLIBC_THREAD_INTERNAL_H 10 | 11 | #include 12 | #include 13 | 14 | typedef void *(*thread_start_t)(void *); 15 | typedef void (*dtor_t)(void *); 16 | typedef void (*cleanup_t)(void *); 17 | 18 | extern DWORD _wlibc_threadinfo_index; 19 | extern ULONGLONG _wlibc_tls_bitmap; 20 | extern dtor_t _wlibc_tls_destructors[64]; 21 | 22 | typedef struct _tls_entry 23 | { 24 | void *value; 25 | } tls_entry; 26 | 27 | typedef struct _cleanup_entry 28 | { 29 | cleanup_t routine; 30 | void *arg; 31 | } cleanup_entry; 32 | 33 | typedef struct _threadinfo 34 | { 35 | HANDLE handle; 36 | DWORD id; 37 | sigset_t sigmask; 38 | sigset_t pending; 39 | DWORD cancelstate; 40 | DWORD canceltype; 41 | thread_start_t routine; 42 | void *args; 43 | void *result; 44 | DWORD cleanup_slots_allocated; 45 | DWORD cleanup_slots_used; 46 | cleanup_entry *cleanup_entries; 47 | tls_entry slots[64]; 48 | } threadinfo; 49 | 50 | void threads_init(void); 51 | void threads_cleanup(void); 52 | void cleanup_tls(threadinfo *tinfo); 53 | void execute_cleanup(threadinfo *tinfo); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/internal/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_TIMER_INTERNAL_H 9 | #define WLIBC_TIMER_INTERNAL_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | typedef struct _timerinfo 17 | { 18 | HANDLE handle; 19 | LONGLONG period; 20 | thread_t thread; 21 | struct sigevent event; 22 | } timerinfo; 23 | 24 | extern timerinfo real_itimer; 25 | extern timerinfo virtual_itimer; 26 | extern timerinfo prof_itimer; 27 | extern thread_t itimer_thread; 28 | 29 | void initialize_itimers(void); 30 | void cleanup_itimers(void); 31 | 32 | void *itimer_proc(void *arg); 33 | void *timer_proc(void *arg); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/internal/validate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_VALIDATE_INTERNAL_H 9 | #define WLIBC_VALIDATE_INTERNAL_H 10 | 11 | #define VALIDATE_PTR(ptr, error, ret) \ 12 | if (ptr == NULL) \ 13 | { \ 14 | errno = error; \ 15 | return ret; \ 16 | } 17 | 18 | #define VALIDATE_STRING(str, error, ret) \ 19 | if (str == NULL || str[0] == '\0') \ 20 | { \ 21 | errno = error; \ 22 | return ret; \ 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_IO_H 9 | #define WLIBC_IO_H 10 | 11 | #include 12 | 13 | _WLIBC_BEGIN_DECLS 14 | 15 | /* 16 | * Below functions are no-op and defined here for compatibility. We always do binary IO with files. 17 | * By introducing our io.h we prevent including MSVC's io.h which redeclares a few symbols (rename, remove). 18 | */ 19 | 20 | WLIBC_INLINE int _setmode(int fd, int mode) 21 | { 22 | return 0; 23 | } 24 | 25 | #define setmode _setmode 26 | 27 | // From fcntl.h 28 | WLIBC_API intptr_t wlibc_get_osfhandle(int fd); 29 | WLIBC_API int wlibc_open_osfhandle(intptr_t handle, int flags); 30 | 31 | WLIBC_INLINE intptr_t _get_osfhandle(int fd) 32 | { 33 | return wlibc_get_osfhandle(fd); 34 | } 35 | 36 | WLIBC_INLINE int _open_osfhandle(intptr_t handle, int flags) 37 | { 38 | return wlibc_open_osfhandle(handle, flags); 39 | } 40 | 41 | _WLIBC_END_DECLS 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/poll.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_POLL_H 9 | #define WLIBC_POLL_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | _WLIBC_BEGIN_DECLS 16 | 17 | // Requested events 18 | #define POLLIN 0x001 // There is data to read. 19 | #define POLLPRI 0x002 // There is urgent data to read. 20 | #define POLLOUT 0x004 // Writing now will not block. 21 | #define POLLRDNORM 0x040 // Normal data may be read. 22 | #define POLLRDBAND 0x080 // Priority data may be read. 23 | #define POLLWRNORM 0x100 // Writing now will not block. 24 | #define POLLWRBAND 0x200 // Priority data may be written. 25 | 26 | // Return events 27 | #define POLLERR 0x008 // Error condition. 28 | #define POLLHUP 0x010 // Hung up. 29 | #define POLLNVAL 0x020 // Invalid polling request. 30 | 31 | typedef unsigned long long int nfds_t; 32 | 33 | struct pollfd 34 | { 35 | int fd; // File descriptor. 36 | short events; // Requested events. 37 | short revents; // Returned events. 38 | }; 39 | 40 | WLIBC_API int wlibc_common_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask); 41 | 42 | WLIBC_INLINE int poll(struct pollfd *fds, nfds_t nfds, int timeout) 43 | { 44 | struct timespec timespec_timeout; 45 | if (timeout >= 0) 46 | { 47 | timespec_timeout.tv_sec = timeout / 1000; 48 | timespec_timeout.tv_nsec = ((timeout % 1000) * 1000000) % 1000000000; 49 | } 50 | 51 | return wlibc_common_poll(fds, nfds, timeout < 0 ? NULL : ×pec_timeout, NULL); 52 | } 53 | 54 | WLIBC_INLINE int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask) 55 | { 56 | return wlibc_common_poll(fds, nfds, timeout, sigmask); 57 | } 58 | 59 | _WLIBC_END_DECLS 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/stdio-hooks.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_STDIO_HOOKS_H 9 | #define WLIBC_STDIO_HOOKS_H 10 | 11 | #include 12 | 13 | #define fopen wlibc_fopen 14 | #define fdopen wlibc_fdopen 15 | #define freopen wlibc_freopen 16 | #define fileno wlibc_fileno 17 | #define fclose wlibc_fclose 18 | #define popen wlibc_popen 19 | #define pclose wlibc_pclose 20 | 21 | #include 22 | 23 | _WLIBC_BEGIN_DECLS 24 | 25 | // File hooks 26 | WLIBC_API FILE *wlibc_fopen(const char *filename, const char *mode); 27 | WLIBC_API FILE *wlibc_fdopen(int fd, const char *mode); 28 | WLIBC_API FILE *wlibc_freopen(const char *filename, const char *mode, FILE *stream); 29 | WLIBC_API int wlibc_fileno(FILE *stream); 30 | WLIBC_API int wlibc_fclose(FILE *stream); 31 | 32 | // Pipe hooks 33 | WLIBC_API FILE *wlibc_popen(const char *command, const char *mode); 34 | WLIBC_API int wlibc_pclose(FILE *stream); 35 | 36 | _WLIBC_END_DECLS 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/sys/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_FILE_H 9 | #define WLIBC_SYS_FILE_H 10 | 11 | #include 12 | 13 | _WLIBC_BEGIN_DECLS 14 | 15 | #define LOCK_SH 1 // Shared lock 16 | #define LOCK_EX 2 // Exclusive lock 17 | #define LOCK_UN 4 // Unlock 18 | #define LOCK_NB 8 // Don't block when locking 19 | 20 | WLIBC_API int wlibc_flock(int fd, int operation); 21 | 22 | WLIBC_INLINE int flock(int fd, int operation) 23 | { 24 | return wlibc_flock(fd, operation); 25 | } 26 | 27 | _WLIBC_END_DECLS 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/sys/fstypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_FSTYPES_H 9 | #define WLIBC_SYS_FSTYPES_H 10 | 11 | #define UNKNOWN_FS 0 12 | #define FAT32_FS 1 13 | #define EXFAT_FS 2 14 | #define NTFS_FS 3 15 | #define HPFS_FS 4 16 | #define REFS_FS 5 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/sys/ioctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_IOCTL_H 9 | #define WLIBC_SYS_IOCTL_H 10 | 11 | #include 12 | #include 13 | 14 | _WLIBC_BEGIN_DECLS 15 | 16 | struct winsize 17 | { 18 | unsigned short ws_row; // row characters 19 | unsigned short ws_col; // column characters 20 | unsigned short ws_xpixel; // horizontal pixels 21 | unsigned short ws_ypixel; // vertical pixels 22 | }; 23 | 24 | // Supported IOCTLS 25 | #define TIOCGWINSZ 1 // Get console window size 26 | #define TIOCSWINSZ 2 // Set console window size 27 | #define FIONREAD 3 // Bytes available for reading 28 | #define FIONWRITE 4 // Bytes already written 29 | 30 | WLIBC_API int wlibc_ioctl(int fd, unsigned long request, va_list args); 31 | 32 | WLIBC_INLINE int ioctl(int fd, unsigned long request, ...) 33 | { 34 | va_list args; 35 | va_start(args, request); 36 | int result = wlibc_ioctl(fd, request, args); 37 | va_end(args); 38 | return result; 39 | } 40 | 41 | _WLIBC_END_DECLS 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/sys/mount.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_MOUNT_H 9 | #define WLIBC_SYS_MOUNT_H 10 | 11 | #include 12 | #include 13 | 14 | #define MNT_WAIT 0 15 | #define MNT_NOWAIT 0 16 | 17 | WLIBC_API int wlibc_getmntinfo(struct statfs **mounts, int mode); 18 | 19 | WLIBC_INLINE int getmntinfo(struct statfs **mounts, int mode) 20 | { 21 | return wlibc_getmntinfo(mounts, mode); 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/sys/param.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_PARAM_H 9 | #define WLIBC_SYS_PARAM_H 10 | 11 | #include 12 | #include 13 | 14 | _WLIBC_BEGIN_DECLS 15 | 16 | // Constants. 17 | #ifndef NOGROUP 18 | # define NOGROUP 65535 19 | #endif 20 | #ifndef MAXPATHLEN 21 | # define MAXPATHLEN 32768 22 | #endif 23 | #ifndef MAXSYMLINKS 24 | # define MAXSYMLINKS 20 // CHECK 25 | #endif 26 | #ifndef NOFILE 27 | # define NOFILE 1048576 28 | #endif 29 | #ifndef MAXHOSTNAMELEN 30 | # define MAXHOSTNAMELEN 256 31 | #endif 32 | #ifndef NODEV 33 | # define NODEV ((dev_t)-1) // Non-existent device. 34 | #endif 35 | 36 | // Unit of `st_blocks'. 37 | #ifndef DEV_BSIZE 38 | # define DEV_BSIZE 512 39 | #endif 40 | 41 | // Bit map related macros. 42 | #define NBBY CHAR_BIT 43 | #define setbit(a, i) ((a)[(i) / NBBY] |= 1 << ((i) % NBBY)) 44 | #define clrbit(a, i) ((a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) 45 | #define isset(a, i) ((a)[(i) / NBBY] & (1 << ((i) % NBBY))) 46 | #define isclr(a, i) (((a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) 47 | 48 | // Macros for counting and rounding. 49 | #define howmany(x, y) (((x) + ((y)-1)) / (y)) // Number of groups of y items made from a total of x items. 50 | #define roundup(x, y) ((howmany(x, y)) * (y)) // Round up x to nearest multiple of y. 51 | #define powerof2(x) ((((x)-1) & (x)) == 0) // Is x a power of 2. 52 | 53 | // Macros for min/max. 54 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 55 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 56 | 57 | _WLIBC_END_DECLS 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/sys/random.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_RANDOM_H 9 | #define WLIBC_SYS_RANDOM_H 10 | 11 | #include 12 | #include 13 | 14 | _WLIBC_BEGIN_DECLS 15 | 16 | #define GRND_RANDOM 0 // Unsupported 17 | #define GRND_NONBLOCK 0 // Unsupported 18 | 19 | /* 20 | #define RD_RAND 1 // random 21 | #define RD_SEED 2 // entropy 22 | */ 23 | 24 | WLIBC_API ssize_t wlibc_generate_random_bytes(void *buffer, size_t length, int source); 25 | 26 | #pragma warning(push) 27 | #pragma warning(disable : 4100) // Unused parameter 28 | 29 | WLIBC_INLINE ssize_t getrandom(void *buffer, size_t length, unsigned int flags WLIBC_UNUSED) 30 | { 31 | return wlibc_generate_random_bytes(buffer, length, 1); 32 | } 33 | 34 | #pragma warning(pop) 35 | 36 | WLIBC_INLINE int getentropy(void *buffer, size_t length) 37 | { 38 | return (int)wlibc_generate_random_bytes(buffer, length, 2); 39 | } 40 | 41 | _WLIBC_END_DECLS 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/sys/times.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_TIMES_H 9 | #define WLIBC_SYS_TIMES_H 10 | 11 | #include 12 | #include 13 | 14 | struct tms 15 | { 16 | clock_t tms_utime; // User CPU time. 17 | clock_t tms_stime; // System CPU time. 18 | clock_t tms_cutime; // User CPU time of dead children. 19 | clock_t tms_cstime; // System CPU time of dead children. 20 | }; 21 | 22 | WLIBC_API clock_t wlibc_times(struct tms *tmsbuf); 23 | 24 | WLIBC_INLINE clock_t times(struct tms *tmsbuf) 25 | { 26 | return wlibc_times(tmsbuf); 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/sys/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_TYPES_H 9 | #define WLIBC_SYS_TYPES_H 10 | 11 | typedef int mode_t; 12 | typedef unsigned long long ino_t; // 64-bit inodes only 13 | typedef long long int off_t; 14 | typedef int uid_t; 15 | typedef int gid_t; 16 | typedef int pid_t; 17 | typedef int id_t; 18 | typedef long long int ssize_t; 19 | typedef unsigned int dev_t; 20 | typedef unsigned long nlink_t; 21 | typedef unsigned short blksize_t; 22 | typedef unsigned int blkcnt_t; 23 | typedef unsigned long long fsblkcnt_t; 24 | typedef unsigned long long fsfilcnt_t; 25 | typedef long suseconds_t; 26 | typedef unsigned long long useconds_t; 27 | 28 | #endif -------------------------------------------------------------------------------- /include/sys/utsname.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_USTNAME_H 9 | #define WLIBC_SYS_USTNAME_H 10 | 11 | #include 12 | 13 | _WLIBC_BEGIN_DECLS 14 | 15 | #define WLIBC_UTSNAME_LENGTH 64 16 | 17 | struct utsname 18 | { 19 | /* Name of the implementation of the operating system. */ 20 | char sysname[WLIBC_UTSNAME_LENGTH]; 21 | /* Name of this node on the network. */ 22 | char nodename[WLIBC_UTSNAME_LENGTH]; 23 | /* Current release level of this implementation. */ 24 | char release[WLIBC_UTSNAME_LENGTH]; 25 | /* Current version level of this release. */ 26 | char version[WLIBC_UTSNAME_LENGTH]; 27 | /* Name of the hardware type the system is running on. */ 28 | char machine[WLIBC_UTSNAME_LENGTH]; 29 | /* Name of the domain of this node on the network. */ 30 | char domainname[WLIBC_UTSNAME_LENGTH]; 31 | }; 32 | 33 | WLIBC_API int wlibc_uname(struct utsname *name); 34 | WLIBC_INLINE int uname(struct utsname *name) 35 | { 36 | return wlibc_uname(name); 37 | } 38 | 39 | _WLIBC_END_DECLS 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/sys/wait.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYS_WAIT_H 9 | #define WLIBC_SYS_WAIT_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | _WLIBC_BEGIN_DECLS 16 | 17 | // Processes with exit codes 3(SIGABRT compat) or greater than 128 are considered to be terminated a signal. 18 | #define W_EXITCODE(wstatus, sig) (wstatus) 19 | #define WIFEXITED(wstatus) ((wstatus) != 3 && (wstatus) < 128) 20 | #define WEXITSTATUS(wstatus) (wstatus) // exit status 21 | 22 | // Only SIGSTOP can suspend a process. 23 | #define W_STOPCODE(sig) (128 + SIGSTOP) 24 | #define WIFSTOPPED(wstatus) ((wstatus) == 128 + SIGSTOP) 25 | #define WSTOPSIG(status) (SIGSTOP) 26 | 27 | // Maintain MSVCRT compatibility for abort behaviour. `abort` sets the exit code as 3. 28 | #define WIFSIGNALED(wstatus) ((wstatus) == 3 || (wstatus) > 128) 29 | #define WTERMSIG(wstatus) ((wstatus) == 3 ? SIGABRT : ((wstatus)-128)) 30 | #define WCOREDUMP(wstatus) (0) // Core dumps, not supported 31 | #define WCOREFLAG 0 32 | 33 | #define W_CONTINUED -1 34 | #define WIFCONTINUED(wstatus) ((wstatus) == W_CONTINUED) 35 | 36 | // Options for waitpid. 37 | #define WUNTRACED 0x0 // Unsupported 38 | #define WNOHANG 0x1 // wait returns immediately 39 | #define WCONTINUED 0x2 // Unsupported 40 | 41 | WLIBC_API pid_t wlibc_waitpid(pid_t pid, int *wstatus, int options); 42 | WLIBC_INLINE pid_t waitpid(pid_t pid, int *wstatus, int options) 43 | { 44 | return wlibc_waitpid(pid, wstatus, options); 45 | } 46 | 47 | WLIBC_INLINE pid_t wait(int *wstatus) 48 | { 49 | return wlibc_waitpid(-1, wstatus, 0); 50 | } 51 | 52 | _WLIBC_END_DECLS 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/sysexits.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_SYSEXITS_H 9 | #define WLIBC_SYSEXITS_H 10 | 11 | #define EX_OK 0 // Successful termination 12 | #define EX_USAGE 64 // Incorrect command line usage 13 | #define EX_DATAERR 65 // Data format error 14 | #define EX_NOINPUT 66 // Cannot open input 15 | #define EX_NOUSER 67 // User unknown 16 | #define EX_NOHOST 68 // Host unknown 17 | #define EX_UNAVAILABLE 69 // Service unavailable 18 | #define EX_SOFTWARE 70 // Internal software error 19 | #define EX_OSERR 71 // System error 20 | #define EX_OSFILE 72 // Critical OS file missing 21 | #define EX_CANTCREAT 73 // Cannot create output 22 | #define EX_IOERR 74 // Input/Output error 23 | #define EX_TEMPFAIL 75 // Temporary failure 24 | #define EX_PROTOCOL 76 // Protocol error 25 | #define EX_NOPERM 77 // Permission denied 26 | #define EX_CONFIG 78 // Configuration error 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/wlibc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #ifndef WLIBC_H 9 | #define WLIBC_H 10 | 11 | #include 12 | 13 | #if BUILDING_WLIBC 14 | # ifdef WLIBC_DLL 15 | # define WLIBC_API __declspec(dllexport) 16 | # else 17 | # define WLIBC_API 18 | # endif 19 | #else 20 | # define WLIBC_API /*__declspec(dllimport)*/ 21 | #endif 22 | 23 | /* For C++ compilers compiling C code */ 24 | #ifdef __cplusplus 25 | # define _WLIBC_BEGIN_DECLS \ 26 | extern "C" \ 27 | { 28 | # define _WLIBC_END_DECLS } 29 | #else 30 | # define _WLIBC_BEGIN_DECLS 31 | # define _WLIBC_END_DECLS 32 | #endif 33 | 34 | #define WLIBC_INLINE __forceinline 35 | #define WLIBC_NORETURN __declspec(noreturn) 36 | 37 | #if defined __clang__ 38 | # define WLIBC_UNUSED __attribute__((unused)) 39 | # define WLIBC_NONNULL __attribute__((nonnull)) 40 | #elif defined _MSC_VER 41 | # define WLIBC_UNUSED 42 | # define WLIBC_NONNULL 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/dirent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE dirent 10 | 11 | SOURCES 12 | alphasort.c 13 | closedir.c 14 | dirfd.c 15 | opendir.c 16 | readdir.c 17 | rewinddir.c 18 | scandir.c 19 | seekdir.c 20 | telldir.c 21 | 22 | HEADERS 23 | dirent.h 24 | ) 25 | -------------------------------------------------------------------------------- /src/dirent/alphasort.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_alphasort(const struct dirent **e1, const struct dirent **e2) 12 | { 13 | return strcoll((*e1)->d_name, (*e2)->d_name); 14 | } 15 | -------------------------------------------------------------------------------- /src/dirent/closedir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int wlibc_closedir(DIR *dirstream) 15 | { 16 | VALIDATE_DIR_STREAM(dirstream, -1); 17 | 18 | if (!close_fd(dirstream->fd)) 19 | { 20 | // Free the memory of DIR. 21 | RtlDeleteCriticalSection(&(dirstream->critical)); 22 | if (RtlFreeHeap(NtCurrentProcessHeap(), 0, dirstream) == FALSE) 23 | { 24 | return -1; 25 | } 26 | 27 | return 0; 28 | } 29 | else 30 | { 31 | return -1; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/dirent/dirfd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_dirfd(DIR *dirstream) 12 | { 13 | int fd; 14 | VALIDATE_DIR_STREAM(dirstream, -1); 15 | LOCK_DIR_STREAM(dirstream); 16 | fd = dirstream->fd; 17 | UNLOCK_DIR_STREAM(dirstream); 18 | return fd; 19 | } 20 | -------------------------------------------------------------------------------- /src/dirent/opendir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static DIR *initialize_dirstream(int fd) 17 | { 18 | DIR *dirstream = (DIR *)RtlAllocateHeap(NtCurrentProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIR) + DIRENT_DIR_BUFFER_SIZE); 19 | 20 | if (dirstream == NULL) 21 | { 22 | errno = ENOMEM; 23 | return NULL; 24 | } 25 | 26 | dirstream->magic = DIR_STREAM_MAGIC; 27 | dirstream->fd = fd; 28 | dirstream->buffer = (void *)((char *)dirstream + sizeof(DIR)); 29 | 30 | RtlInitializeCriticalSection(&(dirstream->critical)); 31 | 32 | return dirstream; 33 | } 34 | 35 | DIR *wlibc_opendir(const char *path) 36 | { 37 | VALIDATE_PATH(path, ENOENT, NULL); 38 | 39 | HANDLE handle = just_open(AT_FDCWD, path, FILE_READ_ATTRIBUTES | FILE_TRAVERSE | FILE_LIST_DIRECTORY | SYNCHRONIZE, 40 | FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 41 | if (handle == NULL) 42 | { 43 | // errno wil be set by just_open 44 | return NULL; 45 | } 46 | 47 | int fd = register_to_fd_table(handle, DIRECTORY_HANDLE, O_RDONLY | O_CLOEXEC | O_DIRECTORY); 48 | 49 | DIR *dirstream = initialize_dirstream(fd); 50 | 51 | // Close the file descriptor if we fail to initialize the stream. 52 | if (dirstream == NULL) 53 | { 54 | close_fd(fd); 55 | } 56 | 57 | return dirstream; 58 | } 59 | 60 | DIR *wlibc_fdopendir(int fd) 61 | { 62 | handle_t _type = get_fd_type(fd); 63 | if (_type != DIRECTORY_HANDLE || _type == INVALID_HANDLE) 64 | { 65 | errno = (_type == INVALID_HANDLE ? EBADF : ENOTDIR); 66 | return NULL; 67 | } 68 | 69 | DIR *dirstream = initialize_dirstream(fd); 70 | 71 | return dirstream; 72 | } 73 | -------------------------------------------------------------------------------- /src/dirent/rewinddir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void wlibc_rewinddir(DIR *dirstream) 16 | { 17 | VALIDATE_DIR_STREAM(dirstream, ); 18 | 19 | NTSTATUS status; 20 | IO_STATUS_BLOCK io; 21 | 22 | LOCK_DIR_STREAM(dirstream); 23 | 24 | memset(dirstream->buffer, 0, DIRENT_DIR_BUFFER_SIZE); 25 | status = NtQueryDirectoryFileEx(get_fd_handle(dirstream->fd), NULL, NULL, NULL, &io, dirstream->buffer, DIRENT_DIR_BUFFER_SIZE, 26 | FileIdExtdBothDirectoryInformation, FILE_QUERY_RESTART_SCAN, NULL); 27 | if (status != STATUS_SUCCESS) 28 | { 29 | map_ntstatus_to_errno(status); 30 | } 31 | 32 | dirstream->received_data = io.Information; 33 | dirstream->read_data = 0; 34 | dirstream->offset = 0; 35 | 36 | UNLOCK_DIR_STREAM(dirstream); 37 | } 38 | -------------------------------------------------------------------------------- /src/dirent/seekdir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void wlibc_seekdir(DIR *dirstream, long long int pos) 15 | { 16 | VALIDATE_DIR_STREAM(dirstream, ); 17 | LOCK_DIR_STREAM(dirstream); 18 | // This value should be given by telldir 19 | dirstream->offset = pos; 20 | UNLOCK_DIR_STREAM(dirstream); 21 | } 22 | -------------------------------------------------------------------------------- /src/dirent/telldir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | off_t wlibc_telldir(DIR *dirstream) 14 | { 15 | off_t offset; 16 | VALIDATE_DIR_STREAM(dirstream, -1); 17 | 18 | LOCK_DIR_STREAM(dirstream); 19 | // Return the offset in DIR->buffer. 20 | // NOTE: This is actually not the file offset in the directory entry. 21 | // You should treat this strictly as an opaque value. 22 | offset = dirstream->offset; 23 | UNLOCK_DIR_STREAM(dirstream); 24 | 25 | return offset; 26 | } 27 | -------------------------------------------------------------------------------- /src/dlfcn/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE dlfcn 10 | 11 | SOURCES 12 | dlclose.c 13 | dlerror.c 14 | dlopen.c 15 | dlsym.c 16 | 17 | HEADERS 18 | dlfcn.h 19 | ) 20 | -------------------------------------------------------------------------------- /src/dlfcn/dlclose.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_dlclose(void *handle) 12 | { 13 | NTSTATUS status; 14 | 15 | status = LdrUnloadDll(handle); 16 | if (status != STATUS_SUCCESS) 17 | { 18 | _wlibc_last_dlfcn_error = status; 19 | return -1; 20 | } 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/dlfcn/dlerror.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | unsigned long _wlibc_last_dlfcn_error = 0; 12 | 13 | char *wlibc_dlerror(void) 14 | { 15 | switch (_wlibc_last_dlfcn_error) 16 | { 17 | case STATUS_INVALID_FILE_FOR_SECTION: 18 | return "This file is not a valid Win32 application."; 19 | case STATUS_DLL_NOT_FOUND: 20 | return "The specified module could not be found."; 21 | case STATUS_ENTRYPOINT_NOT_FOUND: 22 | case STATUS_ORDINAL_NOT_FOUND: 23 | return "The specified procedure could not be found."; 24 | case STATUS_SUCCESS: // No error. 25 | default: 26 | return NULL; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/dlfcn/dlopen.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void *wlibc_dlopen(const char *filename, int flags) 15 | { 16 | NTSTATUS status; 17 | UTF8_STRING u8_image; 18 | UNICODE_STRING u16_image; 19 | HANDLE handle; 20 | 21 | VALIDATE_PATH(filename, ENOENT, NULL); 22 | UNREFERENCED_PARAMETER(flags); 23 | 24 | RtlInitUTF8String(&u8_image, filename); 25 | status = RtlUTF8StringToUnicodeString(&u16_image, &u8_image, TRUE); 26 | if (status != STATUS_SUCCESS) 27 | { 28 | map_ntstatus_to_errno(status); 29 | return NULL; 30 | } 31 | 32 | status = LdrLoadDll(NULL, NULL, &u16_image, &handle); 33 | if (status != STATUS_SUCCESS) 34 | { 35 | _wlibc_last_dlfcn_error = status; 36 | handle = NULL; 37 | } 38 | 39 | RtlFreeUnicodeString(&u16_image); 40 | return handle; 41 | } 42 | -------------------------------------------------------------------------------- /src/dlfcn/dlsym.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void *wlibc_dlsym(void *restrict handle, const char *restrict symbol) 14 | { 15 | NTSTATUS status; 16 | UTF8_STRING u8_symbol; 17 | PVOID procedure = NULL; 18 | 19 | VALIDATE_PTR(handle, EINVAL, NULL); // We know that handle can't be 0. 20 | VALIDATE_STRING(symbol, EINVAL, NULL); 21 | 22 | RtlInitUTF8String(&u8_symbol, symbol); 23 | status = LdrGetProcedureAddressForCaller(handle, &u8_symbol, 0, &procedure, 0, NULL); 24 | if (status != STATUS_SUCCESS) 25 | { 26 | _wlibc_last_dlfcn_error = status; 27 | return NULL; 28 | } 29 | 30 | return procedure; 31 | } 32 | -------------------------------------------------------------------------------- /src/errno/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE errno 10 | 11 | SOURCES 12 | program.c 13 | 14 | HEADERS 15 | errno.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/errno/program.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | char *program_invocation_name = NULL; 12 | char *program_invocation_short_name = NULL; 13 | 14 | void init_program_name(void) 15 | { 16 | NTSTATUS status; 17 | UTF8_STRING u8_program; 18 | 19 | // Fetch path name from RTL_USER_PROCESS_PARAMETERS. 20 | // This will be freed automatically during program termination. 21 | status = RtlUnicodeStringToUTF8String(&u8_program, &NtCurrentPeb()->ProcessParameters->ImagePathName, TRUE); 22 | if (status != STATUS_SUCCESS) 23 | { 24 | // Exit the program due to insufficient memory. 25 | RtlExitUserProcess(STATUS_NO_MEMORY); 26 | } 27 | 28 | // Convert back slashes to forward slashes. 29 | int last_slash = 0; 30 | for (int i = 0; i < u8_program.Length; ++i) 31 | { 32 | if (u8_program.Buffer[i] == '\\') 33 | { 34 | u8_program.Buffer[i] = '/'; 35 | last_slash = i + 1; 36 | } 37 | } 38 | 39 | // 'program_invocation_name' is the full path of the program. 40 | // 'program_invocation_short_name' is the last component of the program. 41 | program_invocation_name = u8_program.Buffer; 42 | program_invocation_short_name = u8_program.Buffer + last_slash; 43 | } 44 | -------------------------------------------------------------------------------- /src/error/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE error 10 | 11 | SOURCES 12 | error.c 13 | 14 | HEADERS 15 | err.h 16 | error.h 17 | ) 18 | -------------------------------------------------------------------------------- /src/fcntl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE fcntl 10 | 11 | SOURCES 12 | fcntl.c 13 | internal.c 14 | open.c 15 | osfhandle.c 16 | 17 | HEADERS 18 | fcntl.h 19 | ) 20 | -------------------------------------------------------------------------------- /src/fcntl/fcntl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int do_dup(int oldfd, int newfd, int flags); 14 | 15 | static int do_dupfd(int old_fd, int new_fd, int o_cloexec) 16 | { 17 | // Find nearest available file descriptor to new_fd which is >= newfd 18 | while (validate_fd(new_fd)) 19 | { 20 | ++new_fd; 21 | } 22 | 23 | return do_dup(old_fd, new_fd, o_cloexec); 24 | } 25 | 26 | int wlibc_fcntl(int fd, int cmd, va_list args) 27 | { 28 | if (!validate_fd(fd)) 29 | { 30 | return -1; 31 | } 32 | 33 | switch (cmd) 34 | { 35 | case F_DUPFD: 36 | return do_dupfd(fd, va_arg(args, int), 0); 37 | case F_DUPFD_CLOEXEC: 38 | return do_dupfd(fd, va_arg(args, int), O_CLOEXEC); 39 | case F_GETFD: 40 | return (get_fd_flags(fd) & O_CLOEXEC); 41 | case F_SETFD: 42 | int f_setfd_flags = (va_arg(args, int) & O_CLOEXEC); 43 | add_fd_flags(fd, f_setfd_flags); 44 | return 0; 45 | case F_GETFL: 46 | return get_fd_flags(fd); 47 | case F_SETFL: 48 | int f_setfl_flags = (va_arg(args, int) & (O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK)); 49 | // only O_APPEND works for now. 50 | // O_DIRECT and O_NONBLOCK require reopening the file. TODO 51 | add_fd_flags(fd, f_setfl_flags); 52 | return 0; 53 | default: 54 | errno = EINVAL; 55 | return -1; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/getopt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE getopt 10 | 11 | SOURCES 12 | getopt.c 13 | 14 | HEADERS 15 | getopt.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/grp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE grp 10 | 11 | SOURCES 12 | grent.c 13 | grgid.c 14 | grnam.c 15 | 16 | HEADERS 17 | grp.h 18 | ) 19 | -------------------------------------------------------------------------------- /src/internal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | set(internal_SOURCES 9 | convert.c 10 | error.c 11 | misc.c 12 | path.c 13 | registry.c 14 | security.c) 15 | 16 | add_library(internal OBJECT ${internal_SOURCES}) 17 | add_library(wmain OBJECT wmain.c) 18 | 19 | if(CMAKE_C_COMPILER_ID STREQUAL "Clang") 20 | target_link_options(wmain PUBLIC -Wl,-entry:wmainCRTStartup) 21 | elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 22 | target_link_options(wmain PUBLIC /ENTRY:wmainCRTStartup /SUBSYSTEM:CONSOLE) 23 | endif() 24 | 25 | if(ENABLE_POSIX_IO) 26 | target_compile_definitions(wmain PRIVATE WLIBC_IO) 27 | endif() 28 | if(ENABLE_POSIX_SIGNALS) 29 | target_compile_definitions(wmain PRIVATE WLIBC_SIGNALS) 30 | endif() 31 | if(ENABLE_SPAWN) 32 | target_compile_definitions(wmain PRIVATE WLIBC_SPAWN) 33 | endif() 34 | if(ENABLE_THREADS) 35 | target_compile_definitions(wmain PRIVATE WLIBC_THREADS) 36 | endif() 37 | if(ENABLE_ACLS) 38 | target_compile_definitions(wmain PRIVATE WLIBC_ACLS) 39 | endif() 40 | if(ENABLE_TIMERS) 41 | target_compile_definitions(wmain PRIVATE WLIBC_TIMERS) 42 | endif() 43 | if(ENABLE_EXTENDED_ERRNO) 44 | target_compile_definitions(wmain PRIVATE WLIBC_ERRNO) 45 | endif() 46 | -------------------------------------------------------------------------------- /src/internal/convert.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | 10 | /* 116444736000000000 is the number of 100 nanosecond intervals from 11 | January 1st 1601 to January 1st 1970 (UTC) 12 | */ 13 | 14 | struct timespec LARGE_INTEGER_to_timespec(LARGE_INTEGER LT) 15 | { 16 | struct timespec result; 17 | time_t epoch = LT.QuadPart - 116444736000000000LL; 18 | result.tv_sec = epoch / 10000000; 19 | result.tv_nsec = (epoch % 10000000) * 100; 20 | return result; 21 | } 22 | 23 | LARGE_INTEGER timespec_to_LARGE_INTEGER(const struct timespec *time) 24 | { 25 | LARGE_INTEGER L; 26 | L.QuadPart = time->tv_sec * 10000000 + time->tv_nsec / 100; 27 | L.QuadPart += 116444736000000000LL; 28 | return L; 29 | } 30 | -------------------------------------------------------------------------------- /src/langinfo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE langinfo 10 | 11 | SOURCES 12 | langinfo.c 13 | 14 | HEADERS 15 | langinfo.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/poll/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE poll 10 | 11 | SOURCES 12 | fdset.c 13 | poll.c 14 | select.c 15 | 16 | HEADERS 17 | poll.h 18 | sys/select.h 19 | ) 20 | -------------------------------------------------------------------------------- /src/poll/fdset.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | void wlibc_fd_clr(int fd, fd_set *set) 13 | { 14 | if (set == NULL || fd >= FD_SETSIZE || fd < 0) 15 | { 16 | errno = EINVAL; 17 | return; 18 | } 19 | 20 | set->masks[fd / 64] &= ~(1ull << (fd % 64)); 21 | } 22 | 23 | void wlibc_fd_set(int fd, fd_set *set) 24 | { 25 | if (set == NULL || fd >= FD_SETSIZE || fd < 0) 26 | { 27 | errno = EINVAL; 28 | return; 29 | } 30 | 31 | set->masks[fd / 64] |= 1ull << (fd % 64); 32 | } 33 | 34 | void wlibc_fd_zero(fd_set *set) 35 | { 36 | if (set == NULL) 37 | { 38 | errno = EINVAL; 39 | return; 40 | } 41 | 42 | memset(set, 0, sizeof(fd_set)); 43 | } 44 | 45 | int wlibc_fd_isset(int fd, fd_set *set) 46 | { 47 | if (set == NULL || fd >= FD_SETSIZE || fd < 0) 48 | { 49 | errno = EINVAL; 50 | return 0; 51 | } 52 | 53 | return ((set->masks[fd / 64] & (1ull << (fd % 64))) != 0); 54 | } 55 | -------------------------------------------------------------------------------- /src/pwd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE pwd 10 | 11 | SOURCES 12 | pwent.c 13 | pwnam.c 14 | pwuid.c 15 | 16 | HEADERS 17 | pwd.h 18 | ) 19 | -------------------------------------------------------------------------------- /src/sched/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sched 10 | 11 | SOURCES 12 | affinity.c 13 | cpuset.c 14 | open.c 15 | param.c 16 | scheduler.c 17 | yield.c 18 | 19 | HEADERS 20 | sched.h 21 | ) 22 | -------------------------------------------------------------------------------- /src/sched/open.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | HANDLE open_process(DWORD pid, ACCESS_MASK access) 12 | { 13 | NTSTATUS status; 14 | OBJECT_ATTRIBUTES object; 15 | CLIENT_ID client_id; 16 | HANDLE handle = 0; 17 | 18 | if (pid == 0) 19 | { 20 | // Return the current process. 21 | return NtCurrentProcess(); 22 | } 23 | 24 | InitializeObjectAttributes(&object, NULL, 0, NULL, NULL); 25 | client_id.UniqueProcess = (HANDLE)(LONG_PTR)pid; 26 | client_id.UniqueThread = 0; 27 | 28 | status = NtOpenProcess(&handle, access, &object, &client_id); 29 | if (status != STATUS_SUCCESS) 30 | { 31 | map_ntstatus_to_errno(status); 32 | return NULL; 33 | } 34 | 35 | // Successful handle creation. 36 | return handle; 37 | } 38 | -------------------------------------------------------------------------------- /src/sched/yield.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_sched_yield(void) 12 | { 13 | NtYieldExecution(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/signal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE signal 10 | 11 | SOURCES 12 | internal.c 13 | raise.c 14 | sigaction.c 15 | signal.c 16 | sigprocmask.c 17 | 18 | HEADERS 19 | signal.h 20 | ) 21 | -------------------------------------------------------------------------------- /src/signal/sigaction.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int do_sigaction(int sig, const struct sigaction *new_action, struct sigaction *old_action) 14 | { 15 | 16 | int status = 0; 17 | siginfo sinfo; 18 | 19 | if (old_action) 20 | { 21 | get_siginfo(sig, &sinfo); 22 | 23 | old_action->sa_handler = sinfo.action; 24 | old_action->sa_flags = sinfo.flags; 25 | old_action->sa_mask = sinfo.mask; 26 | } 27 | 28 | if (new_action == NULL) 29 | { 30 | return 0; 31 | } 32 | 33 | if (sig == SIGKILL || sig == SIGSTOP) 34 | { 35 | errno = EINVAL; 36 | return -1; 37 | } 38 | 39 | // Update the signal handling information in the signal table. 40 | sinfo.action = new_action->sa_handler; 41 | sinfo.flags = new_action->sa_flags; 42 | sinfo.mask = new_action->sa_mask; 43 | 44 | set_siginfo(sig, &sinfo); 45 | 46 | return status; 47 | } 48 | 49 | int wlibc_sigaction(int sig, const struct sigaction *new_action, struct sigaction *old_action) 50 | { 51 | VALIDATE_SIGNAL(sig); 52 | 53 | return do_sigaction(sig, new_action, old_action); 54 | } 55 | -------------------------------------------------------------------------------- /src/signal/signal.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int do_sigaction(int sig, const struct sigaction *new_action, struct sigaction *old_action); 13 | 14 | signal_t wlibc_signal(int sig, signal_t handler) 15 | { 16 | int status; 17 | struct sigaction new_action, old_action; 18 | 19 | if (sig <= 0 || sig >= NSIG) 20 | { 21 | errno = EINVAL; 22 | return SIG_ERR; 23 | } 24 | 25 | if (handler == SIG_ERR) 26 | { 27 | errno = EINVAL; 28 | return SIG_ERR; 29 | } 30 | 31 | if (handler == SIG_GET) 32 | { 33 | // This will not fail. 34 | do_sigaction(sig, NULL, &old_action); 35 | return old_action.sa_handler; 36 | } 37 | 38 | new_action.sa_handler = handler; 39 | new_action.sa_mask = 1u << sig; // Always add the signal to the mask. 40 | new_action.sa_flags = 0; 41 | 42 | status = do_sigaction(sig, &new_action, &old_action); 43 | 44 | if (status != 0) 45 | { 46 | return SIG_ERR; 47 | } 48 | 49 | return old_action.sa_handler; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/spawn/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE spawn 10 | 11 | SOURCES 12 | actions.c 13 | attributes.c 14 | internal.c 15 | spawn.c 16 | 17 | HEADERS 18 | spawn.h 19 | ) 20 | -------------------------------------------------------------------------------- /src/stdio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE stdio 10 | 11 | SOURCES 12 | clearerr.c 13 | fclose.c 14 | fdopen.c 15 | feof.c 16 | ferror.c 17 | fflush.c 18 | fgetc.c 19 | fgets.c 20 | fileno.c 21 | fileops.c 22 | flock.c 23 | fopen.c 24 | fputc.c 25 | fputs.c 26 | fread.c 27 | freopen.c 28 | fseek.c 29 | ftell.c 30 | fwrite.c 31 | getdelim.c 32 | internal.c 33 | mode.c 34 | pclose.c 35 | perror.c 36 | popen.c 37 | printf.c 38 | rename.c 39 | scanf.c 40 | setvbuf.c 41 | temp.c 42 | ungetc.c 43 | #pipe-hooks.c 44 | #stdio-hooks.c 45 | 46 | HEADERS 47 | stdio.h 48 | stdio_ext.h 49 | #stdio-hooks.h 50 | ) 51 | -------------------------------------------------------------------------------- /src/stdio/clearerr.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | void common_clearerr(FILE *stream) 12 | { 13 | stream->error = 0; 14 | } 15 | 16 | void wlibc_clearerr_unlocked(FILE *stream) 17 | { 18 | VALIDATE_FILE_STREAM(stream, ); 19 | common_clearerr(stream); 20 | } 21 | 22 | void wlibc_clearerr(FILE *stream) 23 | { 24 | VALIDATE_FILE_STREAM(stream, ); 25 | 26 | LOCK_FILE_STREAM(stream); 27 | common_clearerr(stream); 28 | UNLOCK_FILE_STREAM(stream); 29 | } 30 | -------------------------------------------------------------------------------- /src/stdio/fclose.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void close_all_streams(void); 14 | int common_fflush(FILE *stream); 15 | int wlibc_close(int fd); 16 | 17 | int common_fclose(FILE *stream) 18 | { 19 | int fd = stream->fd; 20 | 21 | common_fflush(stream); 22 | 23 | if ((stream->buf_mode & _IOBUFFER_INTERNAL) && (stream->buf_mode & _IOBUFFER_ALLOCATED)) 24 | { 25 | RtlFreeHeap(NtCurrentProcessHeap(), 0, stream->buffer); 26 | } 27 | 28 | // stream is freed here 29 | delete_stream(stream); 30 | 31 | return wlibc_close(fd); 32 | } 33 | 34 | int wlibc_fclose(FILE *stream) 35 | { 36 | VALIDATE_FILE_STREAM(stream, -1); 37 | return common_fclose(stream); 38 | } 39 | 40 | int wlibc_fcloseall() 41 | { 42 | close_all_streams(); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/stdio/fdopen.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | FILE *wlibc_fdopen(int fd, const char *mode) 16 | { 17 | fdinfo info; 18 | get_fdinfo(fd, &info); 19 | 20 | if (info.type == DIRECTORY_HANDLE || info.type == INVALID_HANDLE) 21 | { 22 | errno = (info.type == INVALID_HANDLE ? EBADF : EISDIR); 23 | return NULL; 24 | } 25 | 26 | int std_flags = parse_mode(mode); 27 | int fd_flags = info.flags; 28 | 29 | int important_fd_flags = fd_flags & (O_APPEND | O_ACCMODE); 30 | int important_std_flags = std_flags & (O_APPEND | O_ACCMODE); 31 | 32 | if ((important_fd_flags & O_APPEND) != (important_std_flags & O_APPEND)) 33 | { 34 | errno = EINVAL; 35 | return NULL; 36 | } 37 | 38 | // Underlying fd was not opened for writing but the stream is requesting write access 39 | if (important_std_flags & O_ACCMODE) 40 | { 41 | if ((important_fd_flags & O_ACCMODE) == 0) 42 | { 43 | errno = EINVAL; 44 | return NULL; 45 | } 46 | } 47 | 48 | FILE *stream = create_stream(fd, _IOBUFFER_INTERNAL | _IOFBF | get_buf_mode(fd_flags), 512); 49 | return stream; 50 | } 51 | -------------------------------------------------------------------------------- /src/stdio/feof.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int common_feof(FILE *stream) 12 | { 13 | return stream->error == _IOEOF ? _IOEOF : 0; 14 | } 15 | 16 | int wlibc_feof_unlocked(FILE *stream) 17 | { 18 | VALIDATE_FILE_STREAM(stream, 0); 19 | return common_feof(stream); 20 | } 21 | 22 | int wlibc_feof(FILE *stream) 23 | { 24 | VALIDATE_FILE_STREAM(stream, 0); 25 | 26 | LOCK_FILE_STREAM(stream); 27 | int error = common_feof(stream); 28 | UNLOCK_FILE_STREAM(stream); 29 | 30 | return error; 31 | } 32 | -------------------------------------------------------------------------------- /src/stdio/ferror.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int common_ferror(FILE *stream) 12 | { 13 | return stream->error == _IOERROR ? _IOERROR : 0; 14 | } 15 | 16 | int wlibc_ferror_unlocked(FILE *stream) 17 | { 18 | VALIDATE_FILE_STREAM(stream, 0); 19 | return common_ferror(stream); 20 | } 21 | 22 | int wlibc_ferror(FILE *stream) 23 | { 24 | VALIDATE_FILE_STREAM(stream, 0); 25 | 26 | LOCK_FILE_STREAM(stream); 27 | int error = common_ferror(stream); 28 | UNLOCK_FILE_STREAM(stream); 29 | 30 | return error; 31 | } 32 | -------------------------------------------------------------------------------- /src/stdio/fgetc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | size_t common_fread(void *restrict buffer, size_t size, size_t count, FILE *restrict stream); 12 | 13 | int common_fgetc(FILE *stream) 14 | { 15 | char ch; 16 | if (((stream->buf_mode & _IONBF) == 0) && stream->prev_op == OP_READ) 17 | { 18 | if (stream->start != stream->end && stream->pos != stream->end) 19 | { 20 | ch = stream->buffer[stream->pos++ - stream->start]; 21 | return ch; 22 | } 23 | } 24 | common_fread(&ch, 1, 1, stream); 25 | if (stream->error == _IOEOF) 26 | { 27 | return EOF; 28 | } 29 | return ch; 30 | } 31 | 32 | int wlibc_fgetc_unlocked(FILE *stream) 33 | { 34 | VALIDATE_FILE_STREAM(stream, EOF); 35 | return common_fgetc(stream); 36 | } 37 | 38 | int wlibc_fgetc(FILE *stream) 39 | { 40 | VALIDATE_FILE_STREAM(stream, EOF); 41 | LOCK_FILE_STREAM(stream); 42 | int ch = common_fgetc(stream); 43 | UNLOCK_FILE_STREAM(stream); 44 | return ch; 45 | } 46 | -------------------------------------------------------------------------------- /src/stdio/fgets.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int common_fgetc(FILE *stream); 13 | 14 | char *common_fgets(char *restrict buffer, size_t count, FILE *restrict stream) 15 | { 16 | char ch = 0; 17 | size_t read_count = 0; 18 | 19 | while (ch != '\n' && read_count + 1 < count) 20 | { 21 | ch = (char)common_fgetc(stream); 22 | if (ch == EOF) 23 | { 24 | break; 25 | } 26 | buffer[read_count++] = ch; 27 | } 28 | 29 | buffer[read_count] = '\0'; 30 | return buffer; 31 | } 32 | 33 | char *wlibc_fgets_unlocked(char *restrict buffer, size_t count, FILE *restrict stream) 34 | { 35 | if (buffer == NULL || count < 1) 36 | { 37 | errno = EINVAL; 38 | return NULL; 39 | } 40 | 41 | if (count == 1) 42 | { 43 | buffer[0] = '\0'; 44 | return buffer; 45 | } 46 | 47 | VALIDATE_FILE_STREAM(stream, NULL); 48 | return common_fgets(buffer, count, stream); 49 | } 50 | 51 | char *wlibc_fgets(char *restrict buffer, size_t count, FILE *restrict stream) 52 | { 53 | if (buffer == NULL || count < 1) 54 | { 55 | errno = EINVAL; 56 | return NULL; 57 | } 58 | 59 | if (count == 1) 60 | { 61 | buffer[0] = '\0'; 62 | return buffer; 63 | } 64 | 65 | VALIDATE_FILE_STREAM(stream, NULL); 66 | LOCK_FILE_STREAM(stream); 67 | char *buf = common_fgets(buffer, count, stream); 68 | UNLOCK_FILE_STREAM(stream); 69 | return buf; 70 | } 71 | -------------------------------------------------------------------------------- /src/stdio/fileno.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int common_fileno(FILE *stream) 12 | { 13 | return stream->fd; 14 | } 15 | 16 | int wlibc_fileno_unlocked(FILE *stream) 17 | { 18 | VALIDATE_FILE_STREAM(stream, -1); 19 | return common_fileno(stream); 20 | } 21 | 22 | int wlibc_fileno(FILE *stream) 23 | { 24 | VALIDATE_FILE_STREAM(stream, -1); 25 | 26 | LOCK_FILE_STREAM(stream); 27 | int fd = common_fileno(stream); 28 | UNLOCK_FILE_STREAM(stream); 29 | 30 | return fd; 31 | } 32 | -------------------------------------------------------------------------------- /src/stdio/flock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define LOCK 0 14 | #define UNLOCK 1 15 | #define TRYLOCK 2 16 | 17 | int wlibc_lockfile_op(FILE *stream, int op) 18 | { 19 | VALIDATE_FILE_STREAM(stream, EOF); 20 | 21 | if (op == LOCK) 22 | { 23 | RtlEnterCriticalSection(&(stream->critical)); 24 | return 0; 25 | } 26 | if (op == UNLOCK) 27 | { 28 | RtlLeaveCriticalSection(&(stream->critical)); 29 | return 0; 30 | } 31 | if (op == TRYLOCK) 32 | { 33 | BOOLEAN result = RtlTryEnterCriticalSection(&(stream->critical)); 34 | if (result == 0) 35 | { 36 | return -1; // Another thread holds the lock, fail by return non-zero 37 | } 38 | return 0; 39 | } 40 | 41 | // Unreachable 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /src/stdio/fopen.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int do_open(int dirfd, const char *name, int oflags, mode_t perm); 15 | 16 | FILE *wlibc_fopen(const char *restrict name, const char *restrict mode) 17 | { 18 | VALIDATE_PATH(name, ENOENT, NULL); 19 | 20 | if (mode == NULL) 21 | { 22 | errno = EINVAL; 23 | return NULL; 24 | } 25 | 26 | int flags = parse_mode(mode); 27 | int fd = do_open(AT_FDCWD, name, flags | O_NOTDIR, 0700); 28 | 29 | if (fd == -1) 30 | { 31 | return NULL; 32 | } 33 | 34 | FILE *stream = create_stream(fd, _IOBUFFER_INTERNAL | _IOFBF | get_buf_mode(flags), 512); 35 | return stream; 36 | } 37 | -------------------------------------------------------------------------------- /src/stdio/fputc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | size_t common_fwrite(void *restrict buffer, size_t size, size_t count, FILE *restrict stream); 12 | 13 | int common_fputc(int ch, FILE *stream) 14 | { 15 | if (((stream->buf_mode & _IONBF) == 0) && stream->prev_op == OP_WRITE) 16 | { 17 | if (stream->start != stream->end && stream->pos != stream->end) 18 | { 19 | stream->buffer[stream->pos++ - stream->start] = (char)ch; 20 | return ch; 21 | } 22 | } 23 | size_t res = common_fwrite(&ch, 1, 1, stream); 24 | if (res != 1) 25 | { 26 | return EOF; 27 | } 28 | 29 | return ch; 30 | } 31 | 32 | int wlibc_fputc_unlocked(int ch, FILE *stream) 33 | { 34 | VALIDATE_FILE_STREAM(stream, EOF); 35 | return common_fputc(ch, stream); 36 | } 37 | 38 | int wlibc_fputc(int ch, FILE *stream) 39 | { 40 | VALIDATE_FILE_STREAM(stream, EOF); 41 | LOCK_FILE_STREAM(stream); 42 | int result = common_fputc(ch, stream); 43 | UNLOCK_FILE_STREAM(stream); 44 | return result; 45 | } 46 | -------------------------------------------------------------------------------- /src/stdio/fputs.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | size_t common_fwrite(const char *restrict buffer, size_t size, size_t count, FILE *restrict stream); 14 | 15 | int common_fputs(const char *restrict buffer, FILE *restrict stream) 16 | { 17 | size_t length = strlen(buffer); 18 | int result = (int)common_fwrite(buffer, 1, length, stream); 19 | return result; 20 | } 21 | 22 | int wlibc_fputs_unlocked(const char *restrict buffer, FILE *restrict stream) 23 | { 24 | if (buffer == NULL) 25 | { 26 | errno = EINVAL; 27 | return EOF; 28 | } 29 | 30 | VALIDATE_FILE_STREAM(stream, EOF); 31 | return common_fputs(buffer, stream); 32 | } 33 | 34 | int wlibc_fputs(const char *restrict buffer, FILE *restrict stream) 35 | { 36 | if (buffer == NULL) 37 | { 38 | errno = EINVAL; 39 | return EOF; 40 | } 41 | 42 | VALIDATE_FILE_STREAM(stream, EOF); 43 | 44 | LOCK_FILE_STREAM(stream); 45 | int result = common_fputs(buffer, stream); 46 | UNLOCK_FILE_STREAM(stream); 47 | 48 | return result; 49 | } 50 | -------------------------------------------------------------------------------- /src/stdio/fseek.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int common_fflush(FILE *stream); 14 | 15 | int common_fseek(FILE *stream, ssize_t offset, int whence) 16 | { 17 | // If the stream was written to previously flush 18 | if (stream->prev_op == OP_WRITE) 19 | { 20 | common_fflush(stream); 21 | } 22 | 23 | // No need to seek 24 | if (whence == SEEK_CUR && stream->prev_op == OP_READ) 25 | { 26 | size_t new_pos = stream->pos + offset; 27 | if (new_pos >= stream->start && new_pos <= stream->end && stream->start != stream->end) 28 | { 29 | stream->pos = new_pos; 30 | return 0; 31 | } 32 | } 33 | 34 | off_t result = lseek(stream->fd, offset, whence); 35 | 36 | if (result != -1) 37 | { 38 | stream->pos = result; 39 | stream->start = stream->pos; 40 | stream->end = stream->pos; 41 | 42 | if (whence == SEEK_SET && offset == 0) 43 | { 44 | // Clear any error 45 | stream->error = 0; 46 | } 47 | else 48 | { 49 | // Clear eof only 50 | stream->error = stream->error & ~_IOEOF; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | return -1; 57 | } 58 | 59 | int wlibc_fseek(FILE *stream, ssize_t offset, int whence) 60 | { 61 | VALIDATE_FILE_STREAM(stream, EOF); 62 | if (whence < 0 || whence > 2) 63 | { 64 | errno = EINVAL; 65 | return EOF; 66 | } 67 | 68 | int result; 69 | LOCK_FILE_STREAM(stream); 70 | result = common_fseek(stream, offset, whence); 71 | UNLOCK_FILE_STREAM(stream); 72 | return result; 73 | } 74 | -------------------------------------------------------------------------------- /src/stdio/ftell.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | ssize_t wlibc_ftell(FILE *stream) 14 | { 15 | VALIDATE_FILE_STREAM(stream, EOF); 16 | ssize_t result; 17 | LOCK_FILE_STREAM(stream); 18 | result = stream->pos; 19 | UNLOCK_FILE_STREAM(stream); 20 | return result; 21 | } 22 | -------------------------------------------------------------------------------- /src/stdio/mode.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int parse_mode(const char *mode) 13 | { 14 | int flags = 0; 15 | for (int i = 0; mode[i] != '\0'; i++) 16 | { 17 | switch (mode[i]) 18 | { 19 | case 'r': 20 | flags |= O_RDONLY; 21 | break; 22 | case 'w': 23 | flags |= O_WRONLY | O_CREAT | O_TRUNC; 24 | break; 25 | case '+': 26 | flags &= ~O_WRONLY; // remove O_WRONLY as O_RDONLY is 0 27 | flags |= O_RDWR; 28 | break; 29 | case 'a': 30 | flags |= O_WRONLY | O_APPEND | O_CREAT; 31 | break; 32 | // GNU Extenstions 33 | case 'x': 34 | flags |= O_EXCL; 35 | break; 36 | case 'm': 37 | // flags // mmap TODO 38 | break; 39 | // Microsoft Extensions 40 | case 'b': 41 | flags |= O_BINARY; 42 | break; 43 | case 't': 44 | flags |= O_TEXT; 45 | break; 46 | case 'c': 47 | flags |= O_SYNC; 48 | break; 49 | case 'N': 50 | case 'e': // glibc O_CLOEXEC 51 | flags |= O_NOINHERIT; 52 | break; 53 | case 'S': 54 | flags |= O_SEQUENTIAL; 55 | break; 56 | case 'R': 57 | flags |= O_RANDOM; 58 | break; 59 | case 'T': // fallthrough 60 | case 'D': 61 | flags |= O_SHORT_LIVED; 62 | break; 63 | default: 64 | break; 65 | } 66 | } 67 | 68 | return flags; 69 | } 70 | 71 | int get_buf_mode(int flags) 72 | { 73 | if (flags & O_RDWR) 74 | { 75 | return _IOBUFFER_RDWR; 76 | } 77 | else if (flags & O_WRONLY) 78 | { 79 | return _IOBUFFER_WRONLY; 80 | } 81 | else //(flags == O_RDONLY) 82 | { 83 | return _IOBUFFER_RDONLY; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/stdio/pclose.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int common_fclose(FILE *stream); 14 | 15 | int wlibc_pclose(FILE *stream) 16 | { 17 | VALIDATE_FILE_STREAM(stream, -1); 18 | 19 | HANDLE process = stream->phandle; 20 | common_fclose(stream); 21 | 22 | if (WaitForSingleObject(process, INFINITE) == WAIT_FAILED) 23 | { 24 | map_doserror_to_errno(GetLastError()); 25 | return -1; 26 | } 27 | DWORD exit_code = 0; 28 | if (!GetExitCodeProcess(process, &exit_code)) 29 | { 30 | map_doserror_to_errno(GetLastError()); 31 | return -1; 32 | } 33 | 34 | return exit_code; 35 | } 36 | -------------------------------------------------------------------------------- /src/stdio/pipe-hooks.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int parse_mode(const char *mode); 17 | 18 | FILE *wlibc_popen(const char *command, const char *mode) 19 | { 20 | int length = strlen(command) + 1; 21 | char *win_command = (char *)malloc(sizeof(char) * length); 22 | strcpy(win_command, command); 23 | char *temp = win_command; 24 | // Iterate the first argument only, convert any forward slash to back slash for cmd.exe 25 | while (*win_command != '\0' && *win_command != ' ') 26 | { 27 | if (*win_command == '/') 28 | { 29 | *win_command = '\\'; 30 | } 31 | ++win_command; 32 | } 33 | win_command = temp; 34 | 35 | FILE *_PIPE = _popen(win_command, mode); 36 | free(win_command); 37 | 38 | if (_PIPE == NULL) 39 | { 40 | return NULL; 41 | } 42 | int flags = parse_mode(mode); 43 | HANDLE pipe_handle = (HANDLE)_get_osfhandle(_fileno(_PIPE)); 44 | register_to_fd_table(pipe_handle, NULL, PIPE_HANDLE, flags); 45 | return _PIPE; 46 | } 47 | 48 | int wlibc_pclose(FILE *stream) 49 | { 50 | int status = -1; 51 | if (stream) 52 | { 53 | HANDLE pipe_handle = (HANDLE)_get_osfhandle(_fileno(stream)); 54 | status = _pclose(stream); // Underlying OS handle is closed here 55 | unregister_from_fd_table(pipe_handle); 56 | } 57 | 58 | return status; 59 | } 60 | -------------------------------------------------------------------------------- /src/stdio/scanf.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int __cdecl __stdio_common_vsscanf(_In_ unsigned __int64 _Options, _In_reads_(_BufferCount) _Pre_z_ char const *_Buffer, 16 | _In_ size_t _BufferCount, _In_z_ _Scanf_format_string_params_(2) char const *_Format, 17 | _In_opt_ _locale_t _Locale, va_list _ArgList); 18 | 19 | int wlibc_vfscanf(FILE *restrict stream, const char *restrict format, va_list args) 20 | { 21 | if (format == NULL) 22 | { 23 | errno = EINVAL; 24 | return -1; 25 | } 26 | 27 | if(stream == NULL) 28 | { 29 | return -1; 30 | } 31 | 32 | #if 0 33 | ssize_t initial_pos = wlibc_ftell(stream); 34 | // Assume no one is going to read more than 1024 characters at a time. 35 | // This is a BAD assumption and will only work once. Let's keep it for the time being 36 | char buffer[1024]; 37 | memset(buffer,0,1024); 38 | fread(buffer,1,1024,stream); 39 | #endif 40 | char buffer[1024]; 41 | int result = wlibc_vsscanf(buffer, format, args); 42 | 43 | return result; 44 | // TODO this is hard 45 | } 46 | 47 | int wlibc_vsscanf(const char *restrict str, const char *restrict format, va_list args) 48 | { 49 | if (format == NULL || str == NULL) 50 | { 51 | errno = EINVAL; 52 | return -1; 53 | } 54 | return __stdio_common_vsscanf(_CRT_INTERNAL_LOCAL_SCANF_OPTIONS, str, (size_t)-1, format, NULL, args); 55 | } 56 | -------------------------------------------------------------------------------- /src/stdio/ungetc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int common_ungetc(int ch, FILE *stream) 14 | { 15 | // Only perform on an input stream 16 | if(stream->prev_op != OP_READ) 17 | { 18 | return EOF; 19 | } 20 | 21 | if (stream->pos > stream->start) 22 | { 23 | stream->pos--; 24 | stream->buffer[stream->pos - stream->start] = (char)ch; 25 | // clear eof flag 26 | stream->error = stream->error & ~_IOEOF; 27 | return ch; 28 | } 29 | 30 | return EOF; 31 | } 32 | 33 | int wlibc_ungetc(int ch, FILE *stream) 34 | { 35 | if(ch == EOF) 36 | { 37 | return EOF; 38 | } 39 | 40 | VALIDATE_FILE_STREAM(stream, EOF); 41 | LOCK_FILE_STREAM(stream); 42 | int result = common_ungetc(ch, stream); 43 | UNLOCK_FILE_STREAM(stream); 44 | 45 | return result; 46 | } 47 | -------------------------------------------------------------------------------- /src/stdlib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE stdlib 10 | 11 | SOURCES 12 | mkstemp.c 13 | setenv.c 14 | unsetenv.c 15 | 16 | HEADERS 17 | stdlib.h 18 | ) 19 | -------------------------------------------------------------------------------- /src/stdlib/setenv.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | The environment variables are managed with the environ table. 13 | Let's not mess with MSVC's environment handling by directly calling 14 | SetEnvironmentVariable(). 15 | */ 16 | 17 | int wlibc_setenv(const char *restrict name, const char *restrict value, int overwrite) 18 | { 19 | errno_t err; 20 | if (!getenv(name)) // Variable not found 21 | { 22 | err = _putenv_s(name, value); 23 | return err == 0 ? 0 : -1; 24 | } 25 | else 26 | { 27 | if (overwrite) 28 | { 29 | err = _putenv_s(name, value); 30 | } 31 | else 32 | { 33 | return 0; 34 | } 35 | } 36 | return err == 0 ? 0 : -1; 37 | } 38 | 39 | int wlibc_wsetenv(const wchar_t *restrict name, const wchar_t *restrict value, int overwrite) 40 | { 41 | errno_t err; 42 | if (!_wgetenv(name)) // Variable not found 43 | { 44 | err = _wputenv_s(name, value); 45 | return err == 0 ? 0 : -1; 46 | } 47 | else 48 | { 49 | if (overwrite) 50 | { 51 | err = _wputenv_s(name, value); 52 | } 53 | else 54 | { 55 | return 0; 56 | } 57 | } 58 | return err == 0 ? 0 : -1; 59 | } 60 | -------------------------------------------------------------------------------- /src/stdlib/unsetenv.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_unsetenv(const char *name) 12 | { 13 | errno_t err = _putenv_s(name, ""); 14 | return err == 0 ? 0 : -1; 15 | } 16 | 17 | int wlibc_wunsetenv(const wchar_t *name) 18 | { 19 | errno_t err = _wputenv_s(name, L""); 20 | return err == 0 ? 0 : -1; 21 | } 22 | -------------------------------------------------------------------------------- /src/string/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE string 10 | 11 | SOURCES 12 | ffs.c 13 | memrchr.c 14 | strerror.c 15 | strndup.c 16 | strsignal.c 17 | 18 | HEADERS 19 | string.h 20 | strings.h 21 | ) 22 | -------------------------------------------------------------------------------- /src/string/ffs.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #pragma intrinsic(_BitScanForward) 12 | #pragma intrinsic(_BitScanForward64) 13 | 14 | int wlibc_ffs32(int bytes_32) 15 | { 16 | unsigned long index; 17 | if (_BitScanForward(&index, bytes_32) == 1) 18 | { 19 | // LSB is 1 20 | return index + 1; 21 | } 22 | return 0; 23 | } 24 | 25 | int wlibc_ffs64(long long int bytes_64) 26 | { 27 | unsigned long index; 28 | if (_BitScanForward64(&index, bytes_64) == 1) 29 | { 30 | // LSB is 1 31 | return index + 1; 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /src/string/memrchr.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | 10 | void *wlibc_memrchr(const void *str, int character, size_t size) 11 | { 12 | // A simple memrchr implementation. 13 | // TODO make this fast. 14 | 15 | const char *start = (const char *)str; 16 | const char *end = (const char *)str + size; 17 | 18 | while (1) 19 | { 20 | --end; 21 | 22 | if (end < start) 23 | { 24 | break; 25 | } 26 | 27 | if (*end == character) 28 | { 29 | return (void *)end; 30 | } 31 | } 32 | 33 | return NULL; 34 | } 35 | -------------------------------------------------------------------------------- /src/string/strndup.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | char *wlibc_strndup(const char *str, size_t size) 12 | { 13 | size_t length = strnlen(str, size); 14 | char *result = (char *)malloc(length + 1); 15 | 16 | if (result == NULL) 17 | { 18 | errno = ENOMEM; 19 | return NULL; 20 | } 21 | 22 | // Null terminate the string. 23 | result[length] = '\0'; 24 | memcpy(result, str, length); 25 | 26 | return result; 27 | } 28 | -------------------------------------------------------------------------------- /src/string/strsignal.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | const char *const sys_siglist[NSIG] = {"Hangup", 12 | "Interrupt", 13 | "Quit", 14 | "Illegal instruction", 15 | "Trap", 16 | "Abnormal termination", 17 | "Bus error", 18 | "Floating point exception", 19 | "Kill", 20 | "User defined signal 1", 21 | "Segment violation", 22 | "User defined signal 2", 23 | "Broken pipe", 24 | "Alarm clock", 25 | "Terminate", 26 | "Stack fault ", 27 | "Child terminated or stopped", 28 | "Continue", 29 | "Background read from control terminal", 30 | "Background write to control terminal", 31 | "Keyboard stop", 32 | "Stop", 33 | "Urgent data is available at a socket", 34 | "CPU time limit exceeded", 35 | "File size limit exceeded", 36 | "Virtual timer expired", 37 | "Profiling timer expired", 38 | "Window size change", 39 | "Pollable event", 40 | "Power failure imminent", 41 | "Bad syscall"}; 42 | 43 | char *wlibc_strsignal(int sig) 44 | { 45 | if (sig >= NSIG) 46 | { 47 | return "Unkown signal"; 48 | } 49 | 50 | return (char *)sys_siglist[sig]; 51 | } 52 | -------------------------------------------------------------------------------- /src/sys/acl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.acl 10 | 11 | SOURCES 12 | acl.c 13 | entry.c 14 | flags.c 15 | object.c 16 | perm.c 17 | qualifier.c 18 | tag.c 19 | 20 | HEADERS 21 | sys/acl.h 22 | ) 23 | -------------------------------------------------------------------------------- /src/sys/acl/flags.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_acl_add_flag(acl_flagset_t flagset, acl_flag_t flag) 12 | { 13 | VALIDATE_ACL_FLAGSET(flagset, -1); 14 | VALIDATE_ACL_FLAGS(flag, -1); 15 | 16 | *flagset |= flag; 17 | return 0; 18 | } 19 | 20 | int wlibc_acl_clear_flags(acl_flagset_t flagset) 21 | { 22 | VALIDATE_ACL_FLAGSET(flagset, -1); 23 | 24 | *flagset = 0; 25 | return 0; 26 | } 27 | 28 | int wlibc_acl_delete_flag(acl_flagset_t flagset, acl_flag_t flag) 29 | { 30 | VALIDATE_ACL_FLAGSET(flagset, -1); 31 | VALIDATE_ACL_FLAGS(flag, -1); 32 | 33 | *flagset &= ~flag; 34 | return 0; 35 | } 36 | 37 | int wlibc_acl_get_flag(acl_flagset_t flagset, acl_flag_t flag) 38 | { 39 | VALIDATE_ACL_FLAGSET(flagset, -1); 40 | VALIDATE_ACL_FLAGS(flag, -1); 41 | 42 | return (*flagset & flag) == flag; 43 | } 44 | 45 | int wlibc_acl_get_flagset(acl_entry_t entry, acl_flagset_t *flagset) 46 | { 47 | VALIDATE_ACL_ENTRY(entry, -1); 48 | VALIDATE_PTR(flagset, EINVAL, -1); 49 | 50 | *flagset = &entry->flags; 51 | 52 | return 0; 53 | } 54 | 55 | int wlibc_acl_set_flagset(acl_entry_t entry, acl_flagset_t flagset) 56 | { 57 | VALIDATE_ACL_ENTRY(entry, -1); 58 | VALIDATE_ACL_FLAGSET(flagset, -1); 59 | VALIDATE_ACL_FLAGS(*flagset, -1); 60 | 61 | entry->flags = *flagset; 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/sys/acl/perm.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_acl_add_perm(acl_permset_t permset, acl_perm_t perm) 12 | { 13 | VALIDATE_ACL_PERMSET(permset, -1); 14 | VALIDATE_ACL_PERMS(perm, -1); 15 | 16 | *permset |= perm; 17 | return 0; 18 | } 19 | 20 | int wlibc_acl_clear_perms(acl_permset_t permset) 21 | { 22 | VALIDATE_ACL_PERMSET(permset, -1); 23 | 24 | *permset = 0; 25 | return 0; 26 | } 27 | 28 | int wlibc_acl_delete_perm(acl_permset_t permset, acl_perm_t perm) 29 | { 30 | VALIDATE_ACL_PERMSET(permset, -1); 31 | VALIDATE_ACL_PERMS(perm, -1); 32 | 33 | *permset &= ~perm; 34 | return 0; 35 | } 36 | 37 | int wlibc_acl_get_perm(acl_permset_t permset, acl_perm_t perm) 38 | { 39 | VALIDATE_ACL_PERMSET(permset, -1); 40 | VALIDATE_ACL_PERMS(perm, -1); 41 | 42 | return (*permset & perm) == perm; 43 | } 44 | 45 | int wlibc_acl_get_permset(acl_entry_t entry, acl_permset_t *permset) 46 | { 47 | VALIDATE_ACL_ENTRY(entry, -1); 48 | VALIDATE_PTR(permset, EINVAL, -1); 49 | 50 | if (entry->type != ACL_EXTENDED_ALLOW && entry->type != ACL_EXTENDED_DENY) 51 | { 52 | // Unsupported ace type. 53 | errno = ENOTSUP; 54 | return -1; 55 | } 56 | 57 | *permset = &entry->mask; 58 | 59 | return 0; 60 | } 61 | 62 | int wlibc_acl_set_permset(acl_entry_t entry, acl_permset_t permset) 63 | { 64 | VALIDATE_ACL_ENTRY(entry, -1); 65 | VALIDATE_ACL_PERMSET(permset, -1); 66 | VALIDATE_ACL_PERMS(*permset, -1); 67 | 68 | entry->mask = *permset; 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /src/sys/acl/qualifier.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | acl_qualifier_t wlibc_acl_get_qualifier(acl_entry_t entry) 15 | { 16 | VALIDATE_ACL_ENTRY(entry, NULL); 17 | 18 | return (acl_qualifier_t) & (entry->sid); 19 | } 20 | 21 | int wlibc_acl_set_qualifier(acl_entry_t entry, const acl_qualifier_t qualifier) 22 | { 23 | VALIDATE_ACL_ENTRY(entry, -1); 24 | 25 | NTSTATUS status; 26 | 27 | status = RtlCopySid(SECURITY_SID_SIZE(SID_MAX_SUB_AUTHORITIES), &entry->sid, qualifier); 28 | if (status != STATUS_SUCCESS) 29 | { 30 | map_ntstatus_to_errno(status); 31 | return -1; 32 | } 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/sys/acl/tag.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_acl_get_tag_type(acl_entry_t entry, acl_tag_t *tag) 13 | { 14 | VALIDATE_ACL_ENTRY(entry, -1); 15 | VALIDATE_PTR(tag, EINVAL, -1); 16 | 17 | // If the type is other than allow or deny, set tag to be undefined. 18 | // NOTE: This is only because we only support these 2 types. Other types if set 19 | // will work properly when copying, etc. 20 | // Just don't set tag when it is undefined. 21 | if(entry->type == ACL_EXTENDED_ALLOW || entry->type == ACL_EXTENDED_DENY) 22 | { 23 | *tag = entry->type; 24 | } 25 | else 26 | { 27 | *tag = ACL_UNDEFINED_TAG; 28 | } 29 | 30 | return 0; 31 | } 32 | 33 | int wlibc_acl_set_tag_type(acl_entry_t entry, acl_tag_t tag) 34 | { 35 | VALIDATE_ACL_ENTRY(entry, -1); 36 | VALIDATE_ACL_TAG(tag, -1); 37 | 38 | entry->type = tag; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/sys/file/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.file 10 | 11 | SOURCES 12 | flock.c 13 | 14 | HEADERS 15 | sys/file.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/sys/file/flock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int wlibc_flock(int fd, int operation) 15 | { 16 | NTSTATUS status; 17 | IO_STATUS_BLOCK io; 18 | HANDLE handle; 19 | LARGE_INTEGER offset, length; 20 | fdinfo info; 21 | 22 | get_fdinfo(fd, &info); 23 | 24 | // Only support regular files 25 | if (info.type != FILE_HANDLE) 26 | { 27 | errno = EBADF; 28 | return -1; 29 | } 30 | 31 | int nonblock = (operation & LOCK_NB) ? 1 : 0; 32 | operation = operation & ~LOCK_NB; 33 | 34 | if (operation != LOCK_SH && operation != LOCK_EX && operation != LOCK_UN) 35 | { 36 | errno = EINVAL; 37 | return -1; 38 | } 39 | 40 | handle = info.handle; 41 | 42 | // We are always locking the entire file 43 | offset.QuadPart = 0; 44 | length.QuadPart = -1; 45 | 46 | switch (operation) 47 | { 48 | case LOCK_SH: 49 | status = NtLockFile(handle, NULL, NULL, NULL, &io, &offset, &length, 0, nonblock == 1 ? TRUE : FALSE, FALSE); 50 | break; 51 | case LOCK_EX: 52 | status = NtLockFile(handle, NULL, NULL, NULL, &io, &offset, &length, 0, nonblock == 1 ? TRUE : FALSE, TRUE); 53 | break; 54 | case LOCK_UN: 55 | status = NtUnlockFile(handle, &io, &offset, &length, 0); 56 | break; 57 | default: 58 | // This should never happen. 59 | status = STATUS_INVALID_PARAMETER_2; 60 | break; 61 | } 62 | 63 | if (status != STATUS_SUCCESS) 64 | { 65 | if (status == STATUS_LOCK_NOT_GRANTED && nonblock == 1) 66 | { 67 | errno = EWOULDBLOCK; 68 | } 69 | else 70 | { 71 | map_ntstatus_to_errno(status); 72 | } 73 | return -1; 74 | } 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/sys/ioctl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.ioctl 10 | 11 | SOURCES 12 | ioctl.c 13 | 14 | HEADERS 15 | sys/ioctl.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/sys/mman/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.mman 10 | 11 | SOURCES 12 | mlock.c 13 | mmap.c 14 | mprotect.c 15 | msync.c 16 | munlock.c 17 | munmap.c 18 | 19 | HEADERS 20 | sys/mman.h 21 | ) 22 | -------------------------------------------------------------------------------- /src/sys/mman/mlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_mlock(const void *address, size_t size) 13 | { 14 | NTSTATUS status; 15 | 16 | status = NtLockVirtualMemory(NtCurrentProcess(), (PVOID *)&address, &size, MAP_PROCESS); 17 | if (status != STATUS_SUCCESS) 18 | { 19 | map_ntstatus_to_errno(status); 20 | return -1; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/sys/mman/mprotect.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // From mmap.c 13 | ULONG determine_protection(int protection); 14 | 15 | int wlibc_mprotect(void *address, size_t size, int protection) 16 | { 17 | NTSTATUS status; 18 | ULONG new_protection, old_protection; 19 | 20 | if (protection > (PROT_READ | PROT_WRITE | PROT_EXEC)) 21 | { 22 | errno = EINVAL; 23 | return -1; 24 | } 25 | 26 | new_protection = determine_protection(protection); 27 | 28 | status = NtProtectVirtualMemory(NtCurrentProcess(), &address, &size, new_protection, &old_protection); 29 | if (status != STATUS_SUCCESS) 30 | { 31 | map_ntstatus_to_errno(status); 32 | return -1; 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/sys/mman/msync.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_msync(void *address, size_t size, int flags) 13 | { 14 | NTSTATUS status; 15 | IO_STATUS_BLOCK io; 16 | 17 | if (flags > MS_SYNC) 18 | { 19 | errno = EINVAL; 20 | return -1; 21 | } 22 | 23 | status = NtFlushVirtualMemory(NtCurrentProcess(), &address, &size, &io); 24 | if (status != STATUS_SUCCESS) 25 | { 26 | map_ntstatus_to_errno(status); 27 | return -1; 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/sys/mman/munlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_munlock(const void *address, size_t size) 13 | { 14 | NTSTATUS status; 15 | 16 | status = NtUnlockVirtualMemory(NtCurrentProcess(), (PVOID *)&address, &size, MAP_PROCESS); 17 | if (status != STATUS_SUCCESS) 18 | { 19 | map_ntstatus_to_errno(status); 20 | return -1; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/sys/mman/munmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_munmap(void *address, size_t size) 13 | { 14 | NTSTATUS status; 15 | 16 | UNREFERENCED_PARAMETER(size); 17 | 18 | status = NtUnmapViewOfSectionEx(NtCurrentProcess(), address, 0); 19 | if (status != STATUS_SUCCESS) 20 | { 21 | map_ntstatus_to_errno(status); 22 | return -1; 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/sys/mount/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.mount 10 | 11 | SOURCES 12 | getmntinfo.c 13 | 14 | HEADERS 15 | sys/mount.h 16 | ) -------------------------------------------------------------------------------- /src/sys/random/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.random 10 | 11 | SOURCES 12 | random.c 13 | 14 | HEADERS 15 | sys/random.h 16 | ) 17 | 18 | if(CMAKE_C_COMPILER_ID STREQUAL "Clang") 19 | target_compile_options(sys.random PRIVATE -mrdrnd -mrdseed) # clang needs these flags enabled to use the machine intrinsics 20 | endif() 21 | -------------------------------------------------------------------------------- /src/sys/resource/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.resource 10 | 11 | SOURCES 12 | priority.c 13 | rlimit.c 14 | rusage.c 15 | 16 | HEADERS 17 | sys/resource.h 18 | ) 19 | -------------------------------------------------------------------------------- /src/sys/stat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.stat 10 | 11 | SOURCES 12 | chflags.c 13 | chmod.c 14 | mkdir.c 15 | stat.c 16 | statx.c 17 | utimens.c 18 | 19 | HEADERS 20 | sys/stat.h 21 | ) 22 | -------------------------------------------------------------------------------- /src/sys/stat/mkdir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int wlibc_common_mkdir(int dirfd, const char *path, mode_t mode) 18 | { 19 | if (mode > 0777) 20 | { 21 | errno = EINVAL; 22 | return -1; 23 | } 24 | VALIDATE_PATH_AND_DIRFD(path, dirfd); 25 | 26 | NTSTATUS status; 27 | IO_STATUS_BLOCK io; 28 | UNICODE_STRING *u16_ntpath; 29 | OBJECT_ATTRIBUTES object; 30 | PSECURITY_DESCRIPTOR security_descriptor = (PSECURITY_DESCRIPTOR)get_security_descriptor(mode & 0777, 1); 31 | HANDLE handle; 32 | 33 | u16_ntpath = get_absolute_ntpath(dirfd, path); 34 | if (u16_ntpath == NULL) 35 | { 36 | // errno will be set by `get_absolute_ntpath` 37 | return -1; 38 | } 39 | 40 | InitializeObjectAttributes(&object, u16_ntpath, OBJ_CASE_INSENSITIVE, NULL, security_descriptor); 41 | status = NtCreateFile(&handle, FILE_READ_ATTRIBUTES, &object, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, 42 | FILE_DIRECTORY_FILE, NULL, 0); 43 | RtlFreeHeap(NtCurrentProcessHeap(), 0, u16_ntpath); 44 | 45 | if (status != STATUS_SUCCESS) 46 | { 47 | map_ntstatus_to_errno(status); 48 | return -1; 49 | } 50 | 51 | NtClose(handle); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/sys/statfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.statfs 10 | 11 | SOURCES 12 | statfs.c 13 | 14 | HEADERS 15 | sys/statfs.h 16 | sys/fstypes.h 17 | ) 18 | -------------------------------------------------------------------------------- /src/sys/statvfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.statvfs 10 | 11 | SOURCES 12 | statvfs.c 13 | 14 | HEADERS 15 | sys/statvfs.h 16 | sys/fstypes.h 17 | ) 18 | -------------------------------------------------------------------------------- /src/sys/time/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.time 10 | 11 | SOURCES 12 | clock.c 13 | gettimeofday.c 14 | internal.c 15 | itimer.c 16 | timer.c 17 | utimes.c 18 | 19 | HEADERS 20 | sys/time.h 21 | ) 22 | -------------------------------------------------------------------------------- /src/sys/time/clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define VALIDATE_CLOCK(id) \ 15 | { \ 16 | if (id != CLOCK_REALTIME && id != CLOCK_MONOTONIC) \ 17 | { \ 18 | errno = EINVAL; \ 19 | return -1; \ 20 | } \ 21 | } 22 | 23 | int wlibc_clock_getres(clockid_t id, struct timespec *res) 24 | { 25 | VALIDATE_CLOCK(id); 26 | 27 | if (res != NULL) 28 | { 29 | // Resolution of clocks in Windows is 100ns. 30 | res->tv_nsec = 100; 31 | res->tv_sec = 0; 32 | } 33 | 34 | return 0; 35 | } 36 | 37 | int wlibc_clock_gettime(clockid_t id, struct timespec *ts) 38 | { 39 | LARGE_INTEGER epoch = {0}; 40 | 41 | VALIDATE_CLOCK(id); 42 | VALIDATE_PTR(ts, EINVAL, -1); 43 | 44 | switch (id) 45 | { 46 | case CLOCK_REALTIME: 47 | GetSystemTimePreciseAsFileTime((LPFILETIME)&epoch); 48 | break; 49 | case CLOCK_MONOTONIC: 50 | QueryPerformanceCounter(&epoch); 51 | break; 52 | } 53 | 54 | // The values reported here should be from January 1st 1601 UTC. 55 | ts->tv_sec = epoch.QuadPart / 10000000; 56 | ts->tv_nsec = (epoch.QuadPart % 10) * 100; 57 | 58 | return 0; 59 | } 60 | 61 | int wlibc_clock_settime(clockid_t id, const struct timespec *ts) 62 | { 63 | VALIDATE_CLOCK(id); 64 | VALIDATE_PTR(ts, EINVAL, -1); 65 | 66 | // We don't support changing the time. 67 | errno = ENOTSUP; 68 | return -1; 69 | } 70 | -------------------------------------------------------------------------------- /src/sys/time/gettimeofday.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* 116444736000000000 is the number of 100 nanosecond intervals from 15 | January 1st 1601 to January 1st 1970 (UTC) 16 | */ 17 | 18 | int wlibc_gettimeofday(struct timeval *restrict tp) 19 | { 20 | VALIDATE_PTR(tp, EINVAL, -1); 21 | 22 | SYSTEMTIME systemtime; 23 | FILETIME filetime; 24 | GetSystemTime(&systemtime); 25 | SystemTimeToFileTime(&systemtime, &filetime); 26 | time_t epoch = ((time_t)filetime.dwHighDateTime << 32) + filetime.dwLowDateTime; 27 | epoch -= 116444736000000000LL; 28 | tp->tv_sec = epoch / 10000000; 29 | tp->tv_usec = (epoch % 10000000) / 10; 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /src/sys/time/utimes.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_common_utimes(int dirfd, const char *path, const struct timeval times[2], int flags) 12 | { 13 | struct timespec timespec[2]; 14 | 15 | if (times == NULL) 16 | { 17 | return wlibc_common_utimens(dirfd, path, NULL, flags); 18 | } 19 | 20 | timespec[0].tv_sec = times[0].tv_sec; 21 | timespec[0].tv_nsec = times[0].tv_usec * 1000; 22 | 23 | timespec[1].tv_sec = times[1].tv_sec; 24 | timespec[1].tv_sec = times[1].tv_usec * 1000; 25 | 26 | return wlibc_common_utimens(dirfd, path, timespec, flags); 27 | } 28 | -------------------------------------------------------------------------------- /src/sys/times/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.times 10 | 11 | SOURCES 12 | times.c 13 | 14 | HEADERS 15 | sys/times.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/sys/times/times.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define TO_CLOCK_T(number) ((clock_t)(number) / (10000000 / CLOCKS_PER_SEC)) 14 | 15 | clock_t wlibc_times(struct tms *tmsbuf) 16 | { 17 | NTSTATUS status; 18 | KERNEL_USER_TIMES user_times; 19 | SYSTEM_TIMEOFDAY_INFORMATION time_info; 20 | 21 | if (tmsbuf == NULL) 22 | { 23 | errno = EINVAL; 24 | return -1; 25 | } 26 | 27 | status = NtQueryInformationProcess(NtCurrentProcess(), ProcessTimes, &user_times, sizeof(KERNEL_USER_TIMES), NULL); 28 | if (status != STATUS_SUCCESS) 29 | { 30 | map_ntstatus_to_errno(status); 31 | return -1; 32 | } 33 | 34 | // Ignore these fields. 35 | tmsbuf->tms_cstime = 0; 36 | tmsbuf->tms_cutime = 0; 37 | 38 | tmsbuf->tms_stime = TO_CLOCK_T(user_times.KernelTime.QuadPart); 39 | tmsbuf->tms_utime = TO_CLOCK_T(user_times.UserTime.QuadPart); 40 | 41 | status = NtQuerySystemInformation(SystemTimeOfDayInformation, &time_info, sizeof(time_info), NULL); 42 | if (status != STATUS_SUCCESS) 43 | { 44 | map_ntstatus_to_errno(status); 45 | return -1; 46 | } 47 | 48 | return TO_CLOCK_T(time_info.CurrentTime.QuadPart - time_info.BootTime.QuadPart); 49 | } 50 | -------------------------------------------------------------------------------- /src/sys/utsname/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.utsname 10 | 11 | SOURCES 12 | uname.c 13 | 14 | HEADERS 15 | sys/utsname.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/sys/wait/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.wait 10 | 11 | SOURCES 12 | waitpid.c 13 | 14 | HEADERS 15 | sys/wait.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/sys/xattr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE sys.xattr 10 | 11 | SOURCES 12 | getxattr.c 13 | listxattr.c 14 | setxattr.c 15 | 16 | HEADERS 17 | sys/xattr.h 18 | ) 19 | -------------------------------------------------------------------------------- /src/termios/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE termios 10 | 11 | SOURCES 12 | tcattr.c 13 | tcmisc.c 14 | 15 | HEADERS 16 | termios.h 17 | ) 18 | -------------------------------------------------------------------------------- /src/termios/tcmisc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int wlibc_tcsendbreak(int fd, int duration) 14 | { 15 | fdinfo info; 16 | 17 | get_fdinfo(fd, &info); 18 | 19 | if (info.type != CONSOLE_HANDLE) 20 | { 21 | errno = EBADF; 22 | return -1; 23 | } 24 | 25 | if(duration < 0) 26 | { 27 | errno = EINVAL; 28 | return -1; 29 | } 30 | 31 | // Just validate and return. 32 | return 0; 33 | } 34 | 35 | int wlibc_tcdrain(int fd) 36 | { 37 | fdinfo info; 38 | 39 | get_fdinfo(fd, &info); 40 | 41 | if (info.type != CONSOLE_HANDLE) 42 | { 43 | errno = EBADF; 44 | return -1; 45 | } 46 | 47 | // Just validate and return. 48 | return 0; 49 | } 50 | 51 | int wlibc_tcflow(int fd, int action) 52 | { 53 | fdinfo info; 54 | 55 | get_fdinfo(fd, &info); 56 | 57 | if (info.type != CONSOLE_HANDLE) 58 | { 59 | errno = EBADF; 60 | return -1; 61 | } 62 | 63 | if (action < TCOOFF || action > TCION) 64 | { 65 | errno = EINVAL; 66 | return -1; 67 | } 68 | 69 | // Just validate and return. 70 | return 0; 71 | } 72 | 73 | int wlibc_tcflush(int fd, int queue) 74 | { 75 | if (queue < TCIFLUSH || queue > TCIOFLUSH) 76 | { 77 | errno = EINVAL; 78 | return -1; 79 | } 80 | 81 | return wlibc_tcdrain(fd); 82 | } 83 | -------------------------------------------------------------------------------- /src/thread/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE thread 10 | 11 | SOURCES 12 | barrier.c 13 | cond.c 14 | internal.c 15 | key.c 16 | mutex.c 17 | once.c 18 | rwlock.c 19 | thread.c 20 | 21 | HEADERS 22 | pthread.h 23 | thread.h 24 | threads.h 25 | ) 26 | -------------------------------------------------------------------------------- /src/thread/key.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma intrinsic(_BitScanForward64) 14 | 15 | #define VALIDATE_TLS_ENTRY(index, result) \ 16 | if ((_wlibc_tls_bitmap & (1ull << index)) == 0) \ 17 | { \ 18 | return result; \ 19 | } 20 | 21 | int wlibc_tss_create(key_t *index, dtor_t destructor) 22 | { 23 | // Find a free slot. 24 | if (_BitScanForward64(index, ~_wlibc_tls_bitmap) == 1) 25 | { 26 | _wlibc_tls_bitmap |= (1ull << *index); 27 | _wlibc_tls_destructors[*index] = destructor; 28 | return 0; 29 | } 30 | 31 | // No free slot found. 32 | return -1; 33 | } 34 | 35 | void *wlibc_tss_get(key_t index) 36 | { 37 | VALIDATE_TLS_ENTRY(index, NULL); 38 | 39 | threadinfo *tinfo = TlsGetValue(_wlibc_threadinfo_index); 40 | return tinfo->slots[index].value; 41 | } 42 | 43 | int wlibc_tss_set(key_t index, const void *data) 44 | { 45 | VALIDATE_TLS_ENTRY(index, -1); 46 | 47 | threadinfo *tinfo = TlsGetValue(_wlibc_threadinfo_index); 48 | tinfo->slots[index].value = (void *)data; 49 | return 0; 50 | } 51 | 52 | int wlibc_tss_delete(key_t index) 53 | { 54 | VALIDATE_TLS_ENTRY(index, -1); 55 | 56 | _wlibc_tls_bitmap &= ~(1ull << index); 57 | _wlibc_tls_destructors[index] = NULL; 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /src/thread/once.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_thread_once(once_t *control, void (*init)(void)) 13 | { 14 | 15 | if(control == NULL || init == NULL) 16 | { 17 | errno = EINVAL; 18 | return -1; 19 | } 20 | 21 | BOOL result; 22 | 23 | // This is pretty much identitical to `InitOnceExecuteOnce`. Except this return 0 on success. 24 | // Casting our init function to PINIT_ONCE_FN is alright as user has control over init. 25 | result = RtlRunOnceExecuteOnce((PRTL_RUN_ONCE)control, (PINIT_ONCE_FN)init, NULL, NULL); 26 | if (result != 0) 27 | { 28 | // No errors are defined for this. 29 | return -1; 30 | } 31 | 32 | return result; 33 | } 34 | -------------------------------------------------------------------------------- /src/unistd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE unistd 10 | 11 | SOURCES 12 | access.c 13 | alarm.c 14 | chdir.c 15 | chown.c 16 | close.c 17 | conf.c 18 | domainname.c 19 | dup.c 20 | exec.c 21 | fsync.c 22 | getcwd.c 23 | getdtablesize.c 24 | getpagesize.c 25 | gid.c 26 | hostname.c 27 | isatty.c 28 | kill.c 29 | link.c 30 | lseek.c 31 | nice.c 32 | pid.c 33 | pipe.c 34 | pread.c 35 | pwrite.c 36 | read.c 37 | readlink.c 38 | remove.c 39 | sleep.c 40 | symlink.c 41 | truncate.c 42 | ttyname.c 43 | uid.c 44 | write.c 45 | 46 | HEADERS 47 | unistd.h 48 | process.h 49 | ) 50 | -------------------------------------------------------------------------------- /src/unistd/alarm.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | unsigned int wlibc_alarm(unsigned int seconds) 12 | { 13 | unsigned int result; 14 | struct itimerval due = {0}, old = {0}; 15 | 16 | // Cancel the timer first. 17 | setitimer(ITIMER_REAL, &due, &old); 18 | 19 | // Set the new timer. 20 | due.it_value.tv_sec = seconds; 21 | setitimer(ITIMER_REAL, &due, NULL); 22 | 23 | result = (unsigned int)old.it_value.tv_sec; 24 | 25 | return result; 26 | } 27 | -------------------------------------------------------------------------------- /src/unistd/chdir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int common_chdir(const wchar_t *wname) 16 | { 17 | // Changing the 'DosPath' in RTL_USER_PROCESS_PARAMETERS does not work. 18 | // Just call 'SetCurrentDirectoryW' and call it a day. 19 | // Luckily doing this also updates 'DosPath', so all is well. 20 | if (!SetCurrentDirectoryW(wname)) 21 | { 22 | map_doserror_to_errno(GetLastError()); 23 | return -1; 24 | } 25 | 26 | return 0; 27 | } 28 | 29 | int wlibc_chdir(const char *name) 30 | { 31 | VALIDATE_PATH(name, ENOENT, -1); 32 | 33 | NTSTATUS status; 34 | UTF8_STRING u8_name; 35 | UNICODE_STRING u16_name; 36 | 37 | RtlInitUTF8String(&u8_name, name); 38 | status = RtlUTF8StringToUnicodeString(&u16_name, &u8_name, TRUE); 39 | 40 | if (status != STATUS_SUCCESS) 41 | { 42 | map_ntstatus_to_errno(status); 43 | return -1; 44 | } 45 | 46 | int result = common_chdir(u16_name.Buffer); 47 | 48 | RtlFreeUnicodeString(&u16_name); 49 | return result; 50 | } 51 | 52 | int wlibc_fchdir(int fd) 53 | { 54 | if (get_fd_type(fd) != DIRECTORY_HANDLE) 55 | { 56 | errno = ENOTDIR; 57 | return -1; 58 | } 59 | 60 | UNICODE_STRING *dirpath = get_fd_dospath(fd); 61 | if (dirpath == NULL) 62 | { 63 | // errno will be set by `get_fd_dospath`. 64 | return -1; 65 | } 66 | 67 | int result = common_chdir(dirpath->Buffer); 68 | RtlFreeHeap(NtCurrentProcessHeap(), 0, dirpath); 69 | 70 | return result; 71 | } 72 | -------------------------------------------------------------------------------- /src/unistd/close.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int wlibc_close(int fd) 14 | { 15 | if(fd == AT_FDCWD) 16 | { 17 | // Special fd value. 18 | return 0; 19 | } 20 | 21 | if (!validate_fd(fd)) 22 | { 23 | errno = EBADF; 24 | return -1; 25 | } 26 | 27 | return close_fd(fd); 28 | } 29 | -------------------------------------------------------------------------------- /src/unistd/domainname.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int wlibc_getdomainname(char *name, size_t length) 15 | { 16 | if (name == NULL || length <= 0) 17 | { 18 | errno = EINVAL; 19 | return -1; 20 | } 21 | 22 | NTSTATUS status; 23 | UNICODE_STRING u16_domainname; 24 | UTF8_STRING u8_domainname; 25 | size_t size = 0; 26 | void *data = NULL; 27 | 28 | data = get_registry_value(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", L"Domain", &size); 29 | if (data == NULL) 30 | { 31 | // Fallback to 'localdomain' 32 | if (length < 12) 33 | { 34 | errno = EINVAL; 35 | return -1; 36 | } 37 | 38 | memcpy(name, "localdomain", 12); 39 | return 0; 40 | } 41 | 42 | u16_domainname.Length = (USHORT)size; 43 | u16_domainname.MaximumLength = (USHORT)size; 44 | u16_domainname.Buffer = data; 45 | 46 | u8_domainname.Buffer = name; 47 | u8_domainname.MaximumLength = (USHORT)length; 48 | status = RtlUnicodeStringToUTF8String(&u8_domainname, &u16_domainname, FALSE); 49 | RtlFreeHeap(NtCurrentProcessHeap(), 0, data); 50 | 51 | if (status != STATUS_SUCCESS) 52 | { 53 | map_ntstatus_to_errno(status); 54 | return -1; 55 | } 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/unistd/fsync.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int common_sync(int fd, int sync_all) 14 | { 15 | NTSTATUS status; 16 | IO_STATUS_BLOCK io; 17 | HANDLE handle; 18 | fdinfo info; 19 | 20 | get_fdinfo(fd, &info); 21 | 22 | if (info.type != FILE_HANDLE) 23 | { 24 | errno = EROFS; 25 | return -1; 26 | } 27 | 28 | handle = info.handle; 29 | 30 | status = NtFlushBuffersFileEx(handle, sync_all == 1 ? 0 : FLUSH_FLAGS_FILE_DATA_SYNC_ONLY, NULL, 0, &io); 31 | if (status != STATUS_SUCCESS) 32 | { 33 | map_ntstatus_to_errno(status); 34 | return -1; 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | int wlibc_fdatasync(int fd) 41 | { 42 | return common_sync(fd, 0); 43 | } 44 | 45 | int wlibc_fsync(int fd) 46 | { 47 | return common_sync(fd, 1); 48 | } 49 | -------------------------------------------------------------------------------- /src/unistd/getdtablesize.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_getdtablesize() 12 | { 13 | return 8192; // From rlimit.c 14 | } 15 | -------------------------------------------------------------------------------- /src/unistd/getpagesize.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int wlibc_getpagesize() 12 | { 13 | // This will not fail. 14 | SYSTEM_BASIC_INFORMATION basic_info; 15 | NtQuerySystemInformation(SystemBasicInformation, &basic_info, sizeof(SYSTEM_BASIC_INFORMATION), NULL); 16 | return basic_info.PageSize; 17 | } 18 | -------------------------------------------------------------------------------- /src/unistd/gid.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | gid_t wlibc_getgid() 12 | { 13 | return current_gid; 14 | } 15 | 16 | int wlibc_setgid(gid_t gid) 17 | { 18 | // Nop 19 | UNREFERENCED_PARAMETER(gid); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/unistd/hostname.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int wlibc_gethostname(char *name, size_t length) 15 | { 16 | if (name == NULL || length <= 0) 17 | { 18 | errno = EINVAL; 19 | return -1; 20 | } 21 | 22 | NTSTATUS status; 23 | UNICODE_STRING u16_hostname; 24 | UTF8_STRING u8_hostname; 25 | size_t size = 0; 26 | void *data = NULL; 27 | 28 | // Both of the queries should be the same, prefer 'Hostname' to 'ComputerName' 29 | data = get_registry_value(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", L"HostName", &size); 30 | if (data == NULL) 31 | { 32 | data = get_registry_value(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName", 33 | L"ComputerName", &size); 34 | if (data == NULL) 35 | { 36 | // errno will be set by get_registry_value 37 | return -1; 38 | } 39 | } 40 | 41 | u16_hostname.Length = (USHORT)size; 42 | u16_hostname.MaximumLength = (USHORT)size; 43 | u16_hostname.Buffer = data; 44 | 45 | u8_hostname.Buffer = name; 46 | u8_hostname.MaximumLength = (USHORT)length; 47 | status = RtlUnicodeStringToUTF8String(&u8_hostname, &u16_hostname, FALSE); 48 | RtlFreeHeap(NtCurrentProcessHeap(), 0, data); 49 | 50 | if (status != STATUS_SUCCESS) 51 | { 52 | map_ntstatus_to_errno(status); 53 | return -1; 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /src/unistd/isatty.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_isatty(int fd) 13 | { 14 | handle_t type = get_fd_type(fd); 15 | 16 | if (type == INVALID_HANDLE) 17 | { 18 | errno = EBADF; 19 | return 0; 20 | } 21 | 22 | if (type == CONSOLE_HANDLE) 23 | { 24 | return 1; 25 | } 26 | 27 | // else 28 | errno = ENOTTY; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/unistd/kill.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // From sched/open.c 15 | HANDLE open_process(DWORD pid, ACCESS_MASK access); 16 | 17 | int wlibc_kill(pid_t pid, int sig) 18 | { 19 | NTSTATUS status; 20 | HANDLE process; 21 | 22 | if (sig < 0 || sig > NSIG) 23 | { 24 | errno = EINVAL; 25 | return -1; 26 | } 27 | 28 | // If pid is us, then call raise directly. 29 | if (pid == (pid_t)NtCurrentProcessId()) 30 | { 31 | return wlibc_raise(sig); 32 | } 33 | 34 | process = open_process(pid, PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME); 35 | if (process == NULL) 36 | { 37 | // errno will be set by `open_process`. 38 | return -1; 39 | } 40 | 41 | // If sigstop is given suspend the process. 42 | if (sig == SIGSTOP) 43 | { 44 | status = NtSuspendProcess(process); 45 | NtClose(process); 46 | 47 | if (status != STATUS_SUCCESS) 48 | { 49 | map_ntstatus_to_errno(status); 50 | return -1; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | // If sigcont is given resume the process. 57 | if (sig == SIGCONT) 58 | { 59 | status = NtResumeProcess(process); 60 | NtClose(process); 61 | 62 | if (status != STATUS_SUCCESS) 63 | { 64 | map_ntstatus_to_errno(status); 65 | return -1; 66 | } 67 | 68 | return 0; 69 | } 70 | 71 | status = NtTerminateProcess(process, 128 + sig); 72 | NtClose(process); 73 | 74 | if (status != STATUS_SUCCESS) 75 | { 76 | map_ntstatus_to_errno(status); 77 | return -1; 78 | } 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/unistd/pid.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | pid_t wlibc_getpid() 12 | { 13 | return (pid_t)NtCurrentProcessId(); 14 | } 15 | 16 | pid_t wlibc_getppid() 17 | { 18 | // This will not fail. 19 | PROCESS_BASIC_INFORMATION basic_info; 20 | NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &basic_info, sizeof(PROCESS_BASIC_INFORMATION), NULL); 21 | return (pid_t)(INT_PTR)basic_info.InheritedFromUniqueProcessId; 22 | } 23 | 24 | pid_t wlibc_gettid() 25 | { 26 | return (pid_t)NtCurrentThreadId(); 27 | } 28 | -------------------------------------------------------------------------------- /src/unistd/pread.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | ssize_t wlibc_pread(int fd, void *buffer, size_t count, off_t offset) 15 | { 16 | ssize_t result = 0; 17 | NTSTATUS status; 18 | IO_STATUS_BLOCK io; 19 | HANDLE handle; 20 | LARGE_INTEGER byte_offset; 21 | FILE_POSITION_INFORMATION pos_info; 22 | fdinfo info; 23 | 24 | if (buffer == NULL) 25 | { 26 | errno = EFAULT; 27 | return -1; 28 | } 29 | 30 | get_fdinfo(fd, &info); 31 | 32 | switch (info.type) 33 | { 34 | case FILE_HANDLE: 35 | case NULL_HANDLE: 36 | break; 37 | case DIRECTORY_HANDLE: 38 | errno = EISDIR; 39 | return -1; 40 | case CONSOLE_HANDLE: 41 | case PIPE_HANDLE: 42 | errno = ESPIPE; 43 | return -1; 44 | case INVALID_HANDLE: 45 | errno = EBADF; 46 | return -1; 47 | } 48 | 49 | handle = info.handle; 50 | 51 | status = NtQueryInformationFile(handle, &io, &pos_info, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); 52 | if (status != STATUS_SUCCESS) 53 | { 54 | map_ntstatus_to_errno(status); 55 | return -1; 56 | } 57 | 58 | byte_offset.QuadPart = offset; 59 | status = NtReadFile(handle, NULL, NULL, NULL, &io, buffer, (ULONG)count, &byte_offset, NULL); 60 | if (status != STATUS_SUCCESS && status != STATUS_PENDING && status != STATUS_END_OF_FILE) 61 | { 62 | map_ntstatus_to_errno(status); 63 | return -1; 64 | } 65 | result = io.Information; 66 | 67 | status = NtSetInformationFile(handle, &io, &pos_info, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); 68 | if (status != STATUS_SUCCESS) 69 | { 70 | map_ntstatus_to_errno(status); 71 | return -1; 72 | } 73 | 74 | return result; 75 | } 76 | -------------------------------------------------------------------------------- /src/unistd/pwrite.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | ssize_t wlibc_pwrite(int fd, const void *buffer, size_t count, off_t offset) 15 | { 16 | ssize_t result = 0; 17 | NTSTATUS status; 18 | IO_STATUS_BLOCK io; 19 | HANDLE handle; 20 | LARGE_INTEGER byte_offset; 21 | FILE_POSITION_INFORMATION pos_info; 22 | fdinfo info; 23 | 24 | if (buffer == NULL) 25 | { 26 | errno = EFAULT; 27 | return -1; 28 | } 29 | 30 | get_fdinfo(fd, &info); 31 | 32 | switch (info.type) 33 | { 34 | case FILE_HANDLE: 35 | case NULL_HANDLE: 36 | break; 37 | case DIRECTORY_HANDLE: 38 | errno = EISDIR; 39 | return -1; 40 | case CONSOLE_HANDLE: 41 | case PIPE_HANDLE: 42 | errno = ESPIPE; 43 | return -1; 44 | case INVALID_HANDLE: 45 | errno = EBADF; 46 | return -1; 47 | } 48 | 49 | handle = info.handle; 50 | 51 | status = NtQueryInformationFile(handle, &io, &pos_info, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); 52 | if (status != STATUS_SUCCESS) 53 | { 54 | map_ntstatus_to_errno(status); 55 | return -1; 56 | } 57 | 58 | byte_offset.QuadPart = offset; 59 | status = NtWriteFile(handle, NULL, NULL, NULL, &io, (PVOID)buffer, (ULONG)count, &byte_offset, NULL); 60 | if (status != STATUS_SUCCESS && status != STATUS_PENDING) 61 | { 62 | map_ntstatus_to_errno(status); 63 | return -1; 64 | } 65 | result = io.Information; 66 | 67 | status = NtSetInformationFile(handle, &io, &pos_info, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); 68 | if (status != STATUS_SUCCESS) 69 | { 70 | map_ntstatus_to_errno(status); 71 | return -1; 72 | } 73 | 74 | return result; 75 | } 76 | -------------------------------------------------------------------------------- /src/unistd/read.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | ssize_t wlibc_read(int fd, void *buffer, size_t count) 16 | { 17 | NTSTATUS status; 18 | IO_STATUS_BLOCK io; 19 | HANDLE handle; 20 | fdinfo info; 21 | 22 | if (buffer == NULL) 23 | { 24 | errno = EFAULT; 25 | return -1; 26 | } 27 | 28 | get_fdinfo(fd, &info); 29 | 30 | if (info.type == DIRECTORY_HANDLE || info.type == INVALID_HANDLE) 31 | { 32 | errno = (info.type == DIRECTORY_HANDLE ? EISDIR : EBADF); 33 | return -1; 34 | } 35 | 36 | handle = info.handle; 37 | io.Information = 0; 38 | 39 | status = NtReadFile(handle, NULL, NULL, NULL, &io, buffer, (ULONG)count, NULL, NULL); 40 | if (status != STATUS_SUCCESS && status != STATUS_PENDING && status != STATUS_END_OF_FILE && status != STATUS_PIPE_BROKEN && 41 | status != STATUS_PIPE_EMPTY) 42 | { 43 | // When status is set to STATUS_PIPE_BROKEN , it is not treated as an error. 44 | // Reading from a pipe with no write end is not an error apparently???. 45 | // Lots of software depend on this behaviour, changing this would lead to breakage. 46 | map_ntstatus_to_errno(status); 47 | return -1; 48 | } 49 | // NOTE: When we are reading from a pipe, if the write end is duplicated, only the result of one of those 50 | // writes will be read in. 51 | // `read` on linux reads all the data, even from the duplicated write ends in one shot(provided the given buffer is big enough). 52 | // We strictly don't have to conform to this as applications will check for the result of read, if 0 it means no more data is left. 53 | return io.Information; 54 | } 55 | -------------------------------------------------------------------------------- /src/unistd/remove.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int common_remove(int dirfd, const char *path, int flags) 15 | { 16 | ULONG options = FILE_OPEN_REPARSE_POINT; 17 | 18 | switch (flags) 19 | { 20 | case 0: 21 | options |= FILE_NON_DIRECTORY_FILE; 22 | break; 23 | case AT_REMOVEDIR: 24 | options |= FILE_DIRECTORY_FILE; 25 | break; 26 | default: // AT_REMOVEANY 27 | break; 28 | } 29 | 30 | HANDLE handle = just_open(dirfd, path, DELETE, options); 31 | if (handle == NULL) 32 | { 33 | // errno wil be set by just_open 34 | return -1; 35 | } 36 | 37 | // SetFileInformationByHandle with FileDispositionInfoEx can also be used 38 | NTSTATUS status; 39 | IO_STATUS_BLOCK io; 40 | FILE_DISPOSITION_INFORMATION_EX dispostion; 41 | 42 | dispostion.Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS | FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE; 43 | status = NtSetInformationFile(handle, &io, &dispostion, sizeof(FILE_DISPOSITION_INFORMATION_EX), FileDispositionInformationEx); 44 | NtClose(handle); 45 | 46 | if (status != STATUS_SUCCESS) 47 | { 48 | map_ntstatus_to_errno(status); 49 | return -1; 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | int wlibc_common_remove(int dirfd, const char *path, int flags) 56 | { 57 | if (flags != 0 && flags != AT_REMOVEDIR && flags != AT_REMOVEANY) 58 | { 59 | errno = EINVAL; 60 | return -1; 61 | } 62 | 63 | VALIDATE_PATH_AND_DIRFD(path, dirfd); 64 | 65 | return common_remove(dirfd, path, flags); 66 | } 67 | -------------------------------------------------------------------------------- /src/unistd/sleep.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int wlibc_common_sleep(long long nanoseconds_100) 13 | { 14 | // NTSTATUS status; 15 | LARGE_INTEGER interval; 16 | interval.QuadPart = -1 * nanoseconds_100; // relative 17 | /*status =*/NtDelayExecution(TRUE, &interval); 18 | // TODO see what to do in case of failure 19 | // if(status < 0) 20 | //{ 21 | // map_ntstatus_to_errno(status); 22 | //} 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/unistd/ttyname.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | char *wlibc_ttyname(int fd) 15 | { 16 | static char wlibc_ttyname_buffer[256]; 17 | if (wlibc_isatty(fd)) 18 | { 19 | GetConsoleOriginalTitleA(wlibc_ttyname_buffer, 256); 20 | return wlibc_ttyname_buffer; 21 | } 22 | 23 | return NULL; 24 | } 25 | 26 | int wlibc_ttyname_r(int fd, char *buffer, size_t bufsiz) 27 | { 28 | VALIDATE_PTR(buffer, EINVAL, EINVAL); 29 | 30 | if (wlibc_isatty(fd)) 31 | { 32 | if (GetConsoleOriginalTitleA(buffer, (DWORD)bufsiz) == 0) // bufsiz is too small 33 | { 34 | errno = ERANGE; 35 | return errno; 36 | } 37 | return 0; 38 | } 39 | 40 | return errno; 41 | } 42 | -------------------------------------------------------------------------------- /src/unistd/uid.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | uid_t wlibc_getuid() 12 | { 13 | return current_uid; 14 | } 15 | 16 | int wlibc_setuid(uid_t uid) 17 | { 18 | // Nop 19 | UNREFERENCED_PARAMETER(uid); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/unistd/write.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | ssize_t wlibc_write(int fd, const void *buffer, size_t count) 16 | { 17 | NTSTATUS status; 18 | IO_STATUS_BLOCK io; 19 | HANDLE handle; 20 | LARGE_INTEGER offset; 21 | fdinfo info; 22 | 23 | if (buffer == NULL) 24 | { 25 | errno = EFAULT; 26 | return -1; 27 | } 28 | 29 | get_fdinfo(fd, &info); 30 | 31 | if (info.type == DIRECTORY_HANDLE || info.type == INVALID_HANDLE) 32 | { 33 | errno = (info.type == DIRECTORY_HANDLE ? EISDIR : EBADF); 34 | return -1; 35 | } 36 | 37 | handle = info.handle; 38 | offset.HighPart = -1; 39 | 40 | if (info.flags & O_APPEND) 41 | { 42 | offset.LowPart = FILE_WRITE_TO_END_OF_FILE; 43 | } 44 | else 45 | { 46 | offset.LowPart = FILE_USE_FILE_POINTER_POSITION; 47 | } 48 | 49 | status = NtWriteFile(handle, NULL, NULL, NULL, &io, (PVOID)buffer, (ULONG)count, &offset, NULL); 50 | if (status != STATUS_SUCCESS && status != STATUS_PENDING) 51 | { 52 | // NOTE: According to POSIX when status is STATUS_PIPE_BROKEN the signal SIGPIPE should be raised. 53 | // The default behaviour of SIGPIPE is 'abort'. We will just set errno to EPIPE and return -1. 54 | map_ntstatus_to_errno(status); 55 | return -1; 56 | } 57 | 58 | return io.Information; 59 | } 60 | -------------------------------------------------------------------------------- /src/wchar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_module( 9 | MODULE wchar 10 | 11 | SOURCES 12 | width.c 13 | 14 | HEADERS 15 | wchar.h 16 | ) 17 | -------------------------------------------------------------------------------- /src/wchar/width.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | 10 | int wlibc_wcwidth(wchar_t wc) 11 | { 12 | // Test for NUL character. 13 | if (wc == 0) 14 | { 15 | return 0; 16 | } 17 | 18 | // Test for ASCII printable characters. 19 | if (wc >= 0x20 && wc < 0x7f) 20 | { 21 | return 1; 22 | } 23 | 24 | // Test for ASCII control characters. 25 | if (wc < 0xa0) 26 | { 27 | return -1; 28 | } 29 | 30 | // Test for surrogate pair values. 31 | // U+D800 to U+DBFF (high surrogate) 32 | // U+DC00 to U+DFFF (low surrogate) 33 | if (wc >= 0xd800 && wc <= 0xdfff) 34 | { 35 | return -1; 36 | } 37 | 38 | // Test for non spacing characters. 39 | if (wc >= 0x0300 && wc <= 0x036f) 40 | { 41 | return 0; 42 | } 43 | 44 | // TODO 45 | // Ignore other non spacing characters for now. 46 | // Ignore CJK (Chinese Japanese Korean) characters for now. 47 | 48 | return 1; 49 | } 50 | 51 | int wlibc_wcswidth(const wchar_t *wstr, size_t size) 52 | { 53 | int str_width = 0; 54 | int char_width = 0; 55 | 56 | for (size_t i = 0; wstr[i] != L'\0' && i < size; ++i) 57 | { 58 | char_width = wlibc_wcwidth(wstr[i]); 59 | 60 | if (char_width == -1) 61 | { 62 | return -1; 63 | } 64 | 65 | str_width += char_width; 66 | } 67 | 68 | return str_width; 69 | } 70 | -------------------------------------------------------------------------------- /tests/dirent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | dirent 10 | fdopendir 11 | opendir 12 | scandir) 13 | -------------------------------------------------------------------------------- /tests/dirent/test-fdopendir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int test_ENOTDIR() 14 | { 15 | errno = 0; 16 | DIR *D = NULL; 17 | const char *filename = "t-fdopendir.file"; 18 | 19 | int fd = open(filename, O_WRONLY | O_CREAT, 0700); 20 | ASSERT_NOTEQ(fd, -1); 21 | 22 | D = fdopendir(fd); 23 | ASSERT_ERRNO(ENOTDIR); 24 | ASSERT_NULL(D); 25 | 26 | ASSERT_SUCCESS(close(fd)); 27 | ASSERT_SUCCESS(unlink(filename)); 28 | 29 | return 0; 30 | } 31 | 32 | int test_okay() 33 | { 34 | errno = 0; 35 | int fd; 36 | DIR *D = NULL; 37 | 38 | fd = open(".", O_RDONLY); 39 | ASSERT_NOTEQ(fd, -1); 40 | 41 | D = fdopendir(fd); 42 | ASSERT_ERRNO(0); 43 | ASSERT_NOTNULL(D); 44 | ASSERT_SUCCESS(closedir(D)); 45 | 46 | // closedir should have closed the underlying file descriptor. 47 | ASSERT_FAIL(close(fd)); 48 | ASSERT_ERRNO(EBADF); 49 | 50 | return 0; 51 | } 52 | 53 | void cleanup() 54 | { 55 | remove("t-fdopendir.file"); 56 | } 57 | 58 | int main() 59 | { 60 | INITIAILIZE_TESTS(); 61 | CLEANUP(cleanup); 62 | 63 | TEST(test_ENOTDIR()); 64 | TEST(test_okay()); 65 | 66 | VERIFY_RESULT_AND_EXIT(); 67 | } 68 | -------------------------------------------------------------------------------- /tests/dlfcn/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(dlfcn) 9 | -------------------------------------------------------------------------------- /tests/errno/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(program) -------------------------------------------------------------------------------- /tests/errno/test-program.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int test_program() 12 | { 13 | printf("Full program name : %s\n", program_invocation_name); 14 | printf("Short program name : %s\n", program_invocation_short_name); 15 | 16 | // We can only reliably test for the short name. 17 | ASSERT_STREQ(program_invocation_short_name, "test-program.exe"); 18 | 19 | return 0; 20 | } 21 | 22 | int main() 23 | { 24 | INITIAILIZE_TESTS(); 25 | TEST(test_program()); 26 | VERIFY_RESULT_AND_EXIT(); 27 | } 28 | -------------------------------------------------------------------------------- /tests/error/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | err 10 | error) 11 | -------------------------------------------------------------------------------- /tests/error/test-err.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | const char *filename = "t-err.log"; 14 | 15 | void setup() 16 | { 17 | freopen(filename, "w+", stderr); 18 | } 19 | 20 | int cleanup() 21 | { 22 | ASSERT_SUCCESS(fclose(stderr)); 23 | ASSERT_SUCCESS(unlink(filename)); 24 | 25 | return 0; 26 | } 27 | 28 | int check_log(const char *content) 29 | { 30 | char buf[260]; 31 | fseek(stderr, 0, SEEK_SET); 32 | ASSERT_EQ(ftell(stderr), 0); 33 | fread(buf, 1, 260, stderr); 34 | ASSERT_MEMEQ(buf, content, (int)strlen(content)); 35 | 36 | // truncate file to make testing easier 37 | ASSERT_SUCCESS(ftruncate(fileno(stderr), 0)); 38 | lseek(fileno(stderr), 0, SEEK_SET); 39 | return 0; 40 | } 41 | 42 | int test_warn() 43 | { 44 | char buffer[512]; 45 | errno = EINVAL; 46 | 47 | warn("sample warning"); 48 | snprintf(buffer, 512, "test-err: %s: %s\n", "sample warning", strerror(EINVAL)); 49 | ASSERT_SUCCESS(check_log(buffer)) 50 | return 0; 51 | } 52 | 53 | int test_warnx() 54 | { 55 | char buffer[512]; 56 | warnx("sample warning"); 57 | snprintf(buffer, 512, "test-err: %s\n", "sample warning"); 58 | ASSERT_SUCCESS(check_log(buffer)) 59 | return 0; 60 | } 61 | 62 | int main() 63 | { 64 | INITIAILIZE_TESTS(); 65 | 66 | setup(); 67 | TEST(test_warn()); 68 | TEST(test_warnx()); 69 | cleanup(); 70 | 71 | VERIFY_RESULT_AND_EXIT(); 72 | } 73 | -------------------------------------------------------------------------------- /tests/error/test-error.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | const char *filename = "t-error.log"; 14 | 15 | void setup() 16 | { 17 | freopen(filename, "w+", stderr); 18 | } 19 | 20 | int cleanup() 21 | { 22 | ASSERT_SUCCESS(fclose(stderr)); 23 | ASSERT_SUCCESS(unlink(filename)); 24 | 25 | return 0; 26 | } 27 | 28 | int check_log(const char *content) 29 | { 30 | char buf[260]; 31 | fseek(stderr, 0, SEEK_SET); 32 | ASSERT_EQ(ftell(stderr), 0); 33 | fread(buf, 1, 260, stderr); 34 | ASSERT_MEMEQ(buf, content, (int)strlen(content)); 35 | 36 | // truncate file to make testing easier 37 | ASSERT_SUCCESS(ftruncate(fileno(stderr), 0)); 38 | lseek(fileno(stderr), 0, SEEK_SET); 39 | 40 | return 0; 41 | } 42 | 43 | int test_error() 44 | { 45 | char buffer[512]; 46 | error(0, EINVAL, "sample error"); 47 | snprintf(buffer, 512, "test-error: %s: %s\n", "sample error", strerror(EINVAL)); 48 | ASSERT_SUCCESS(check_log(buffer)) 49 | ASSERT_EQ(error_message_count, 1); 50 | return 0; 51 | } 52 | 53 | int test_error_at_line() 54 | { 55 | char buffer[512]; 56 | error_at_line(0, EINVAL, __FILE__, __LINE__, "sample error at line"); 57 | snprintf(buffer, 512, "test-error:%s:%d: %s: %s\n", __FILE__, __LINE__ - 1, "sample error at line", strerror(EINVAL)); 58 | ASSERT_SUCCESS(check_log(buffer)) 59 | ASSERT_EQ(error_message_count, 2); 60 | return 0; 61 | } 62 | 63 | int main() 64 | { 65 | INITIAILIZE_TESTS(); 66 | 67 | setup(); 68 | TEST(test_error()); 69 | TEST(test_error_at_line()); 70 | cleanup(); 71 | 72 | VERIFY_RESULT_AND_EXIT(); 73 | } 74 | -------------------------------------------------------------------------------- /tests/fcntl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | at 10 | open 11 | path 12 | fcntl 13 | sanity) 14 | -------------------------------------------------------------------------------- /tests/fcntl/test-at.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int test_EBADF() 14 | { 15 | errno = 0; 16 | int status = mkdirat(-1, "dummy", 0700); 17 | ASSERT_EQ(status, -1); 18 | ASSERT_ERRNO(EBADF); 19 | return 0; 20 | } 21 | 22 | int test_ENOTDIR() 23 | { 24 | errno = 0; 25 | int fd, status; 26 | const char *filename = "not-a-directory"; 27 | 28 | fd = creat(filename, 0700); 29 | ASSERT_NOTEQ(fd, -1); 30 | status = mkdirat(fd, "dummy", 0700); 31 | ASSERT_EQ(status, -1); 32 | ASSERT_ERRNO(ENOTDIR); 33 | 34 | ASSERT_SUCCESS(close(fd)); 35 | ASSERT_SUCCESS(unlink(filename)); 36 | 37 | return 0; 38 | } 39 | 40 | int test_absolute_path() 41 | { 42 | errno = 0; 43 | int status; 44 | char absolute_dirpath[260]; 45 | const char *dirname = "absolute-path.dir"; 46 | 47 | getcwd(absolute_dirpath, 260); 48 | strcat(absolute_dirpath, "/"); 49 | strcat(absolute_dirpath, dirname); 50 | 51 | status = mkdirat(-1, absolute_dirpath, 0700); 52 | ASSERT_EQ(status, 0); 53 | 54 | ASSERT_SUCCESS(rmdir(dirname)); 55 | return 0; 56 | } 57 | 58 | void cleanup() 59 | { 60 | remove("not-a-directory"); 61 | remove("absolute-path.dir"); 62 | } 63 | 64 | int main() 65 | { 66 | INITIAILIZE_TESTS(); 67 | 68 | TEST(test_EBADF()); 69 | TEST(test_ENOTDIR()); 70 | TEST(test_absolute_path()); 71 | 72 | VERIFY_RESULT_AND_EXIT(); 73 | } -------------------------------------------------------------------------------- /tests/fcntl/test-fcntl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int test_dupfd() 15 | { 16 | int old_fd = STDOUT_FILENO; 17 | int new_fd = fcntl(old_fd, F_DUPFD, 0); 18 | ASSERT_EQ(new_fd, 3); 19 | ASSERT_SUCCESS(close(new_fd)); 20 | 21 | return 0; 22 | } 23 | 24 | int test_flags() 25 | { 26 | int fd = creat("t-fcntl", 0700); 27 | 28 | int flags = fcntl(fd, F_GETFL); 29 | ASSERT_EQ(flags, (O_WRONLY | O_CREAT | O_TRUNC)); 30 | 31 | fcntl(fd, F_SETFL, O_APPEND | O_RDWR); 32 | flags = fcntl(fd, F_GETFL); 33 | ASSERT_EQ(flags, (O_WRONLY | O_CREAT | O_TRUNC | O_APPEND)); 34 | 35 | ASSERT_SUCCESS(close(fd)); 36 | ASSERT_SUCCESS(unlink("t-fcntl")); 37 | 38 | return 0; 39 | } 40 | 41 | void cleanup() 42 | { 43 | remove("t-fcntl"); 44 | } 45 | 46 | int main() 47 | { 48 | INITIAILIZE_TESTS(); 49 | CLEANUP(cleanup); 50 | 51 | TEST(test_dupfd()); 52 | TEST(test_flags()); 53 | 54 | VERIFY_RESULT_AND_EXIT(); 55 | } 56 | -------------------------------------------------------------------------------- /tests/getopt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(getopt) 9 | -------------------------------------------------------------------------------- /tests/grp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | grp) 10 | -------------------------------------------------------------------------------- /tests/langinfo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(langinfo) 9 | -------------------------------------------------------------------------------- /tests/langinfo/test-langinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int test_langinfo() 13 | { 14 | char *result; 15 | 16 | result = nl_langinfo(CODESET); 17 | ASSERT_STREQ(result, "C"); 18 | 19 | result = nl_langinfo(AM_STR); 20 | ASSERT_STREQ(result, "AM"); 21 | result = nl_langinfo(PM_STR); 22 | ASSERT_STREQ(result, "PM"); 23 | 24 | result = nl_langinfo(DAY_1); 25 | ASSERT_STREQ(result, "Sunday"); 26 | result = nl_langinfo(DAY_2); 27 | ASSERT_STREQ(result, "Monday"); 28 | result = nl_langinfo(DAY_3); 29 | ASSERT_STREQ(result, "Tuesday"); 30 | 31 | result = nl_langinfo(ABDAY_1); 32 | ASSERT_STREQ(result, "Sun"); 33 | result = nl_langinfo(ABDAY_2); 34 | ASSERT_STREQ(result, "Mon"); 35 | result = nl_langinfo(ABDAY_3); 36 | ASSERT_STREQ(result, "Tue"); 37 | 38 | result = nl_langinfo(MON_1); 39 | ASSERT_STREQ(result, "January"); 40 | result = nl_langinfo(MON_2); 41 | ASSERT_STREQ(result, "February"); 42 | result = nl_langinfo(MON_3); 43 | ASSERT_STREQ(result, "March"); 44 | 45 | result = nl_langinfo(ABMON_1); 46 | ASSERT_STREQ(result, "Jan"); 47 | result = nl_langinfo(ABMON_2); 48 | ASSERT_STREQ(result, "Feb"); 49 | result = nl_langinfo(ABMON_3); 50 | ASSERT_STREQ(result, "Mar"); 51 | 52 | return 0; 53 | } 54 | 55 | int test_CODESET_UTF8() 56 | { 57 | setlocale(LC_ALL, ".utf8"); 58 | char *result = nl_langinfo(CODESET); 59 | ASSERT_STREQ(result, "UTF-8"); 60 | 61 | return 0; 62 | } 63 | 64 | int main() 65 | { 66 | INITIAILIZE_TESTS(); 67 | 68 | TEST(test_langinfo()); 69 | TEST(test_CODESET_UTF8()); 70 | 71 | VERIFY_RESULT_AND_EXIT(); 72 | } 73 | -------------------------------------------------------------------------------- /tests/poll/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | select 10 | poll) -------------------------------------------------------------------------------- /tests/pthread/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | barrier 10 | cond 11 | key 12 | mutex 13 | once 14 | rwlock 15 | thread) 16 | -------------------------------------------------------------------------------- /tests/pthread/test-once.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int test_variable = 0; 12 | 13 | void init_function(void) 14 | { 15 | ++test_variable; 16 | } 17 | 18 | void *pthread_function(void *once) 19 | { 20 | pthread_once((pthread_once_t *)once, init_function); 21 | return NULL; 22 | } 23 | 24 | int test_once() 25 | { 26 | int status; 27 | void *result; 28 | pthread_t thread_1, thread_2; 29 | pthread_once_t once = PTHREAD_ONCE_INIT; 30 | 31 | status = pthread_create(&thread_1, NULL, pthread_function, (void *)&once); 32 | ASSERT_EQ(status, 0); 33 | 34 | status = pthread_create(&thread_2, NULL, pthread_function, (void *)&once); 35 | ASSERT_EQ(status, 0); 36 | 37 | status = pthread_join(thread_1, &result); 38 | ASSERT_EQ(status, 0); 39 | ASSERT_EQ(result, NULL); 40 | 41 | status = pthread_join(thread_2, &result); 42 | ASSERT_EQ(status, 0); 43 | ASSERT_EQ(result, NULL); 44 | 45 | ASSERT_EQ(test_variable, 1); 46 | 47 | return 0; 48 | } 49 | 50 | int main() 51 | { 52 | INITIAILIZE_TESTS(); 53 | TEST(test_once()); 54 | VERIFY_RESULT_AND_EXIT(); 55 | } 56 | -------------------------------------------------------------------------------- /tests/pwd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | pwd) 10 | -------------------------------------------------------------------------------- /tests/sched/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | cpuset 10 | sched) -------------------------------------------------------------------------------- /tests/signal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | segmentation-fault 10 | sigaction 11 | signal 12 | sigprocmask) 13 | -------------------------------------------------------------------------------- /tests/signal/test-segmentation-fault.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | void segv_handler(int sig) 13 | { 14 | exit(sig - SIGSEGV); 15 | } 16 | 17 | void test_SIGSEGV() 18 | { 19 | signal(SIGSEGV, segv_handler); 20 | 21 | // Cause a segmentation fault. 22 | volatile int *p = NULL; 23 | *p = 0; 24 | } 25 | 26 | int main() 27 | { 28 | // If this works correctly the exit code of the process should be 0. 29 | test_SIGSEGV(); 30 | exit(1); 31 | } -------------------------------------------------------------------------------- /tests/signal/test-sigaction.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int global_variable = 0; 12 | 13 | void my_sighandler(int sig) 14 | { 15 | global_variable += sig; 16 | } 17 | 18 | int test_SA_RESETHAND() 19 | { 20 | struct sigaction S; 21 | int status; 22 | 23 | S.sa_handler = my_sighandler; 24 | S.sa_flags = SA_RESETHAND | SA_NODEFER; 25 | S.sa_mask = 0; 26 | // Pick one with default action as ignore. 27 | status = sigaction(SIGCONT, &S, NULL); 28 | ASSERT_EQ(status, 0); 29 | 30 | raise(SIGCONT); 31 | ASSERT_EQ(global_variable, SIGCONT); 32 | // SIGCONT now must be noop. 33 | raise(SIGCONT); 34 | ASSERT_EQ(global_variable, SIGCONT); 35 | 36 | return 0; 37 | } 38 | 39 | int main() 40 | { 41 | INITIAILIZE_TESTS(); 42 | 43 | global_variable = 0; 44 | TEST(test_SA_RESETHAND()); 45 | 46 | VERIFY_RESULT_AND_EXIT(); 47 | } 48 | -------------------------------------------------------------------------------- /tests/signal/test-signal.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int global_variable = 0; 12 | 13 | #pragma warning(push) 14 | #pragma warning(disable : 4100) // Unused parameter 15 | 16 | void handler_1(int sig WLIBC_UNUSED) 17 | { 18 | ++global_variable; 19 | } 20 | 21 | void handler_2(int sig WLIBC_UNUSED) 22 | { 23 | --global_variable; 24 | } 25 | 26 | #pragma warning(pop) 27 | 28 | int test_SIGKILL() 29 | { 30 | // signal handler for SIGKILL can't be overridden 31 | signal_t old_handler = signal(SIGKILL, handler_1); 32 | ASSERT_ERRNO(EINVAL); 33 | ASSERT_EQ(old_handler, SIG_ERR); 34 | return 0; 35 | } 36 | 37 | int test_SIGINT() 38 | { 39 | signal_t old_handler = signal(SIGINT, handler_1); 40 | raise(SIGINT); 41 | 42 | ASSERT_EQ(old_handler, SIG_DFL); 43 | ASSERT_EQ(global_variable, 1); 44 | 45 | return 0; 46 | } 47 | 48 | int test_custom_signals() 49 | { 50 | signal_t old_handler; 51 | 52 | old_handler = signal(SIGHUP, handler_1); 53 | ASSERT_EQ(old_handler, SIG_DFL); 54 | raise(SIGHUP); 55 | ASSERT_EQ(global_variable, 1); 56 | 57 | old_handler = signal(SIGPIPE, handler_2); 58 | ASSERT_EQ(old_handler, SIG_DFL); 59 | raise(SIGPIPE); 60 | ASSERT_EQ(global_variable, 0); 61 | 62 | return 0; 63 | } 64 | 65 | int main() 66 | { 67 | INITIAILIZE_TESTS(); 68 | 69 | TEST(test_SIGKILL()); 70 | TEST(test_SIGINT()); 71 | 72 | global_variable = 0; 73 | TEST(test_custom_signals()); 74 | 75 | VERIFY_RESULT_AND_EXIT(); 76 | } 77 | -------------------------------------------------------------------------------- /tests/spawn/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(spawn) 9 | 10 | add_executable(basic basic.c) 11 | target_link_libraries(basic wlibc) 12 | 13 | add_executable(env env.c) 14 | target_link_libraries(env wlibc) 15 | 16 | add_executable(cwd cwd.c) 17 | target_link_libraries(cwd wlibc) 18 | 19 | add_executable(arg arg.c) 20 | target_link_libraries(arg wlibc) 21 | 22 | add_executable(inherit-wlibc inherit.c) 23 | target_link_libraries(inherit-wlibc wlibc) 24 | 25 | add_executable(inherit-msvcrt inherit.c) 26 | target_compile_definitions(inherit-msvcrt PRIVATE TESTING_MSVCRT) 27 | 28 | set_target_properties(basic env cwd arg inherit-wlibc inherit-msvcrt PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}) 29 | set_target_properties(basic env cwd arg inherit-wlibc inherit-msvcrt PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}) 30 | 31 | add_executable(simple simple.c) 32 | 33 | add_executable(arg-shebang arg.c) 34 | target_link_libraries(arg-shebang wlibc) 35 | 36 | add_executable(arg-shebang-spaces arg.c) 37 | target_link_libraries(arg-shebang-spaces wlibc) 38 | set_target_properties(arg-shebang-spaces PROPERTIES RUNTIME_OUTPUT_NAME "arg shebang") 39 | 40 | set_target_properties(simple arg-shebang arg-shebang-spaces PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/auxilary) 41 | set_target_properties(simple arg-shebang arg-shebang-spaces PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/auxilary) 42 | -------------------------------------------------------------------------------- /tests/spawn/arg.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) 12 | { 13 | for (int i = 0; i < argc; ++i) 14 | { 15 | write(STDOUT_FILENO, argv[i], strlen(argv[i]) + 1); 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/spawn/basic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | 10 | int main() 11 | { 12 | int length; 13 | char buffer[64]; 14 | 15 | length = (int)read(STDIN_FILENO, buffer, 64); 16 | write(STDOUT_FILENO, buffer, length); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/spawn/cwd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | char cwd[256]; 14 | 15 | getcwd(cwd, 256); 16 | write(STDOUT_FILENO, cwd, strlen(cwd) + 1); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/spawn/env.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | char *value = getenv("TEST_ENV"); 14 | 15 | if (value == NULL) 16 | { 17 | return 1; 18 | } 19 | 20 | if (memcmp(value, "Hello World", 11) != 0) 21 | { 22 | return 2; 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tests/spawn/simple.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | int main() 9 | { 10 | // Just a simple program to see whether path searching works. 11 | return 4096; 12 | } 13 | -------------------------------------------------------------------------------- /tests/stdio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | fdopen 10 | fflush 11 | fileio 12 | fileno 13 | fopen 14 | freopen 15 | getdelim 16 | internal 17 | pipe 18 | rename 19 | stream 20 | temp 21 | ungetc) 22 | 23 | add_executable(pipe-helper pipe-helper.c) 24 | target_link_libraries(pipe-helper wlibc) 25 | set_target_properties(pipe-helper PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}) 26 | set_target_properties(pipe-helper PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}) 27 | -------------------------------------------------------------------------------- /tests/stdio/pipe-helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char **argv) 13 | { 14 | if(argc != 2) 15 | { 16 | return 1; // Failed 17 | } 18 | 19 | int i = atoi(argv[1]); 20 | char buf[16]; 21 | switch (i) 22 | { 23 | case 1: 24 | // test_read 25 | write(STDOUT_FILENO, "hello", 5); 26 | break; 27 | case 2: 28 | // test_write 29 | read(STDIN_FILENO, buf, 5); 30 | buf[5] = '\0'; 31 | if (strcmp(buf, "hello")) 32 | { 33 | write(STDERR_FILENO, "write failed", 12); 34 | return 1; // Failed 35 | } 36 | break; 37 | case 3: 38 | // test_read_cr 39 | write(STDOUT_FILENO, "hello\r\nworld", 12); 40 | break; 41 | case 4: 42 | // test_write_cr 43 | read(STDIN_FILENO, buf, 12); 44 | buf[12] = '\0'; 45 | if (strcmp(buf, "hello\r\nworld")) 46 | { 47 | write(STDERR_FILENO, "write_cr failed", 15); 48 | return 1; // Failed 49 | } 50 | break; 51 | default: 52 | return 1; 53 | } 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /tests/stdio/test-fileno.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int test_std_streams() 12 | { 13 | int fd; 14 | fd = fileno(stdin); 15 | ASSERT_EQ(fd, 0); 16 | fd = fileno(stdout); 17 | ASSERT_EQ(fd, 1); 18 | fd = fileno(stderr); 19 | ASSERT_EQ(fd, 2); 20 | return 0; 21 | } 22 | 23 | int test_fopens() 24 | { 25 | FILE *f1, *f2, *f3; 26 | 27 | f1 = fopen("t-fopens1", "wD"); 28 | ASSERT_EQ(fileno(f1), 3); 29 | f2 = fopen("t-fopens2", "wD"); 30 | ASSERT_EQ(fileno(f2), 4); 31 | 32 | ASSERT_SUCCESS(fclose(f1)); 33 | 34 | f3 = fopen("t-fopens2", "wD"); 35 | ASSERT_EQ(fileno(f3), 3); 36 | 37 | ASSERT_SUCCESS(fclose(f2)); 38 | ASSERT_SUCCESS(fclose(f3)); 39 | 40 | return 0; 41 | } 42 | 43 | int main() 44 | { 45 | INITIAILIZE_TESTS(); 46 | TEST(test_std_streams()); 47 | TEST(test_fopens()); 48 | VERIFY_RESULT_AND_EXIT(); 49 | } 50 | -------------------------------------------------------------------------------- /tests/stdio/test-pipe.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int test_read() 12 | { 13 | int status; 14 | char buf[16]; 15 | size_t length; 16 | FILE *f; 17 | 18 | f = popen("pipe-helper 1", "r"); 19 | length = fread(buf, 1, 16, f); 20 | ASSERT_EQ(length, 5); 21 | ASSERT_MEMEQ(buf, "hello", (int)length); 22 | 23 | status = pclose(f); 24 | ASSERT_EQ(status, 0); 25 | 26 | return 0; 27 | } 28 | 29 | int test_write() 30 | { 31 | int status; 32 | size_t length; 33 | FILE *f; 34 | 35 | f = popen("pipe-helper 2", "w"); 36 | length = fwrite("hello", 1, 5, f); 37 | ASSERT_EQ(length, 5); 38 | 39 | status = pclose(f); 40 | ASSERT_EQ(status, 0); 41 | 42 | return 0; 43 | } 44 | 45 | int test_read_cr() 46 | { 47 | int status; 48 | char buf[16]; 49 | size_t length; 50 | FILE *f; 51 | 52 | f = popen("pipe-helper 3", "r"); 53 | length = fread(buf, 1, 16, f); 54 | ASSERT_EQ(length, 12); 55 | ASSERT_MEMEQ(buf, "hello\r\nworld", (int)length); 56 | 57 | status = pclose(f); 58 | ASSERT_EQ(status, 0); 59 | 60 | return 0; 61 | } 62 | 63 | int test_write_cr() 64 | { 65 | int status; 66 | size_t length; 67 | FILE *f; 68 | 69 | f = popen("pipe-helper 4", "w"); 70 | length = fwrite("hello\r\nworld", 1, 12, f); 71 | ASSERT_EQ(length, 12); 72 | 73 | status = pclose(f); 74 | ASSERT_EQ(status, 0); 75 | 76 | return 0; 77 | } 78 | 79 | int main() 80 | { 81 | INITIAILIZE_TESTS(); 82 | 83 | TEST(test_read()); 84 | TEST(test_write()); 85 | TEST(test_read_cr()); 86 | TEST(test_write_cr()); 87 | 88 | VERIFY_RESULT_AND_EXIT(); 89 | } 90 | -------------------------------------------------------------------------------- /tests/stdio/test-ungetc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int test_ungetc() 14 | { 15 | int result; 16 | char buffer[16]; 17 | size_t count; 18 | FILE *f; 19 | const char *filename = "t-ungetc"; 20 | 21 | f = fopen(filename, "w+"); 22 | 23 | // nothing has been read in yet, ungetc should return EOF 24 | result = ungetc('a', f); 25 | ASSERT_EQ(result, EOF); 26 | 27 | count = fwrite("hello world!", 1, 12, f); 28 | ASSERT_EQ(count, 12); 29 | 30 | // Something has been written, ungetc only operates on input stream so EOF again. 31 | result = ungetc('a', f); 32 | ASSERT_EQ(result, EOF); 33 | 34 | rewind(f); 35 | 36 | count = fread(buffer, 1, 16, f); 37 | ASSERT_EQ(count, 12); 38 | ASSERT_MEMEQ(buffer, "hello world!", 12); 39 | ASSERT_EQ(ftell(f), 12); 40 | ASSERT_EQ(feof(f), 1); 41 | 42 | result = ungetc('a', f); 43 | ASSERT_EQ(result, 'a'); 44 | ASSERT_EQ(ftell(f), 11); 45 | ASSERT_EQ(feof(f), 0); // eof bit should be cleared 46 | 47 | result = ungetc('b', f); 48 | ASSERT_EQ(result, 'b'); 49 | ASSERT_EQ(ftell(f), 10); 50 | ASSERT_EQ(feof(f), 0); 51 | 52 | count = fread(buffer, 1, 16, f); 53 | ASSERT_EQ(count, 2); 54 | ASSERT_MEMEQ(buffer, "ba", 2); 55 | 56 | ASSERT_SUCCESS(fclose(f)); 57 | ASSERT_SUCCESS(unlink(filename)); 58 | 59 | return 0; 60 | } 61 | 62 | void cleanup() 63 | { 64 | remove("t-ungetc"); 65 | } 66 | 67 | int main() 68 | { 69 | INITIAILIZE_TESTS(); 70 | CLEANUP(cleanup); 71 | TEST(test_ungetc()); 72 | VERIFY_RESULT_AND_EXIT(); 73 | } 74 | -------------------------------------------------------------------------------- /tests/stdlib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | env 10 | mkstemp) 11 | -------------------------------------------------------------------------------- /tests/stdlib/test-env.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int test_okay() 12 | { 13 | setenv("t-env", "good", 0); 14 | char *env = getenv("t-env"); 15 | ASSERT_STREQ(env, "good"); 16 | 17 | setenv("t-env", "bad", 0); // Should not overwrite 18 | env = getenv("t-env"); 19 | ASSERT_STREQ(env, "good"); 20 | 21 | setenv("t-env", "best", 1); 22 | env = getenv("t-env"); 23 | ASSERT_STREQ(env, "best"); 24 | 25 | unsetenv("t-env"); 26 | env = getenv("t-env"); 27 | ASSERT_NULL(env); 28 | 29 | return 0; 30 | } 31 | 32 | int main() 33 | { 34 | INITIAILIZE_TESTS(); 35 | TEST(test_okay()); 36 | VERIFY_RESULT_AND_EXIT(); 37 | } 38 | -------------------------------------------------------------------------------- /tests/sys/acl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(acl) 9 | -------------------------------------------------------------------------------- /tests/sys/file/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(flock) 9 | -------------------------------------------------------------------------------- /tests/sys/ioctl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(ioctl) 9 | -------------------------------------------------------------------------------- /tests/sys/ioctl/test-ioctl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int test_TIOCGWINSZ() 14 | { 15 | int fd; 16 | int status; 17 | struct winsize window; 18 | 19 | if (isatty(STDOUT_FILENO)) 20 | { 21 | fd = STDOUT_FILENO; 22 | } 23 | else if (isatty(STDERR_FILENO)) 24 | { 25 | fd = STDERR_FILENO; 26 | } 27 | else 28 | { 29 | // Cannot test this. 30 | return 0; 31 | } 32 | 33 | status = ioctl(fd, TIOCGWINSZ, &window); 34 | ASSERT_EQ(status, 0); 35 | 36 | printf("Window size: %hu columns %hu rows\n", window.ws_col, window.ws_row); 37 | 38 | return 0; 39 | } 40 | 41 | int test_FION() 42 | { 43 | int status; 44 | int bytes; 45 | int fd[2]; 46 | ssize_t count; 47 | char buffer[1024] = {0}; 48 | 49 | ASSERT_SUCCESS(pipe(fd)); 50 | 51 | count = write(fd[1], buffer, 1024); 52 | ASSERT_EQ(count, 1024); 53 | 54 | status = ioctl(fd[0], FIONREAD, &bytes); 55 | ASSERT_EQ(status, 0); 56 | ASSERT_EQ(bytes, 1024); 57 | 58 | status = ioctl(fd[1], FIONWRITE, &bytes); 59 | ASSERT_EQ(status, 0); 60 | ASSERT_EQ(bytes, 1024); 61 | 62 | ASSERT_SUCCESS(close(fd[0])); 63 | ASSERT_SUCCESS(close(fd[1])); 64 | 65 | return 0; 66 | } 67 | 68 | int main() 69 | { 70 | INITIAILIZE_TESTS(); 71 | 72 | TEST(test_TIOCGWINSZ()); 73 | TEST(test_FION()); 74 | 75 | VERIFY_RESULT_AND_EXIT(); 76 | } 77 | -------------------------------------------------------------------------------- /tests/sys/mman/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(mmap) 9 | -------------------------------------------------------------------------------- /tests/sys/mount/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(getmntinfo) 9 | -------------------------------------------------------------------------------- /tests/sys/mount/test-getmntinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void print_statfs(const struct statfs *statfsbuf) 14 | { 15 | printf("f_bsize (Filesystem block size): %lu\n", statfsbuf->f_bsize); 16 | printf("f_iosize (Optimal transfer size): %lu\n", statfsbuf->f_iosize); 17 | printf("f_flag (Filesystem attributes): %lu\n", statfsbuf->f_flag); 18 | printf("f_blocks (Total number of blocks): %llu\n", statfsbuf->f_blocks); 19 | printf("f_bfree (Number of free blocks): %llu\n", statfsbuf->f_bfree); 20 | printf("f_bavail (Number of free blocks for unprivileged users): %llu\n", statfsbuf->f_bavail); 21 | printf("f_fsid (Filesystem ID): %u-%u\n", statfsbuf->f_fsid.major, statfsbuf->f_fsid.minor); 22 | printf("f_namemax (Maximum path length): %lu\n", statfsbuf->f_namemax); 23 | printf("f_fstypename (Filesystem type): %s\n", statfsbuf->f_fstypename); 24 | printf("f_mntfromname (Mount from location): %s\n", statfsbuf->f_mntfromname); 25 | printf("f_mntonname (Mount to location): %s\n", statfsbuf->f_mntonname); 26 | } 27 | 28 | int test_getmntinfo() 29 | { 30 | int status; 31 | struct statfs *statfsbuf; 32 | 33 | status = getmntinfo(&statfsbuf, MNT_WAIT); 34 | ASSERT_NOTEQ(status, 0); 35 | 36 | printf("Got %d entries.\n", status); 37 | for (int i = 0; i < status; ++i) 38 | { 39 | print_statfs(&statfsbuf[i]); 40 | puts("\n"); 41 | } 42 | 43 | free(statfsbuf); 44 | return 0; 45 | } 46 | 47 | int main() 48 | { 49 | INITIAILIZE_TESTS(); 50 | TEST(test_getmntinfo()); 51 | VERIFY_RESULT_AND_EXIT(); 52 | } 53 | -------------------------------------------------------------------------------- /tests/sys/random/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(random) 9 | -------------------------------------------------------------------------------- /tests/sys/random/test-random.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int test_getrandom() 14 | { 15 | ssize_t result; 16 | char buffer[512]; 17 | 18 | result = getrandom(buffer, 512, 0); 19 | ASSERT_EQ(result, 512); 20 | 21 | // if length is odd last byte is not written 22 | result = getrandom(buffer, 511, 0); 23 | ASSERT_EQ(result, 510); 24 | 25 | result = getrandom(buffer, 510, 0); 26 | ASSERT_EQ(result, 510); 27 | 28 | result = getrandom(buffer, 509, 0); 29 | ASSERT_EQ(result, 508); 30 | 31 | result = getrandom(buffer, 508, 0); 32 | ASSERT_EQ(result, 508); 33 | 34 | result = getrandom(buffer, 507, 0); 35 | ASSERT_EQ(result, 506); 36 | 37 | result = getrandom(buffer, 506, 0); 38 | ASSERT_EQ(result, 506); 39 | 40 | result = getrandom(buffer, 505, 0); 41 | ASSERT_EQ(result, 504); 42 | 43 | return 0; 44 | } 45 | 46 | int test_getentropy() 47 | { 48 | ssize_t result; 49 | char buffer[512]; 50 | 51 | result = getentropy(buffer, 512); 52 | ASSERT_EQ(result, 512); 53 | 54 | // if length is odd last byte is not written 55 | result = getentropy(buffer, 511); 56 | ASSERT_EQ(result, 510); 57 | 58 | return 0; 59 | } 60 | 61 | void SIGILL_handler() 62 | { 63 | printf("rdrand, rdseed intrinsics not supported skipping test\n"); 64 | exit(0); 65 | } 66 | 67 | int main() 68 | { 69 | INITIAILIZE_TESTS(); 70 | 71 | // In CI this test sometimes fails with 'Illegal Instruction'. 72 | // Handle this exception and skip this test if it fails. 73 | signal(SIGILL, (signal_t)SIGILL_handler); 74 | 75 | TEST(test_getrandom()); 76 | TEST(test_getentropy()); 77 | 78 | VERIFY_RESULT_AND_EXIT(); 79 | } 80 | -------------------------------------------------------------------------------- /tests/sys/resource/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | priority 10 | rusage) 11 | -------------------------------------------------------------------------------- /tests/sys/resource/test-priority.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int test_priority() 12 | { 13 | int status; 14 | 15 | // As we increasing the nice value of the process, we don't need any special privileges to do so. 16 | for (int i = 1; i <= PRIO_MAX; ++i) 17 | { 18 | status = setpriority(PRIO_PROCESS, 0, i); 19 | ASSERT_EQ(status, 0); 20 | 21 | status = getpriority(PRIO_PROCESS, 0); 22 | // The status might be negative, make sure errno is 0. 23 | ASSERT_ERRNO(0); 24 | ASSERT_EQ(status, i); 25 | } 26 | 27 | return 0; 28 | } 29 | 30 | int main() 31 | { 32 | INITIAILIZE_TESTS(); 33 | TEST(test_priority()); 34 | VERIFY_RESULT_AND_EXIT(); 35 | } 36 | -------------------------------------------------------------------------------- /tests/sys/resource/test-rusage.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | int test_rusage() 12 | { 13 | int status; 14 | struct rusage usage; 15 | 16 | status = getrusage(RUSAGE_SELF, &usage); 17 | ASSERT_EQ(status, 0); 18 | 19 | printf("Kernel time : %lld\n", usage.ru_stime.tv_sec * 1000000 + usage.ru_stime.tv_usec); 20 | printf("User time : %lld\n", usage.ru_utime.tv_sec * 1000000 + usage.ru_utime.tv_usec); 21 | printf("Number of read operations : %llu\n", usage.ru_inblock); 22 | printf("Number of write operations: %llu\n", usage.ru_oublock); 23 | printf("Peak working set size : %llu\n", usage.ru_maxrss); 24 | printf("Shared memory size : %llu\n", usage.ru_ixrss); 25 | printf("Private memory size : %llu\n", usage.ru_idrss); 26 | printf("Private memory size : %llu\n", usage.ru_isrss); 27 | printf("Page reclaims : %llu\n", usage.ru_minflt); 28 | printf("Page faults : %llu\n", usage.ru_majflt); 29 | printf("Swap file usage : %llu\n", usage.ru_nswap); 30 | 31 | return 0; 32 | } 33 | 34 | int main() 35 | { 36 | INITIAILIZE_TESTS(); 37 | TEST(test_rusage()); 38 | VERIFY_RESULT_AND_EXIT(); 39 | } 40 | -------------------------------------------------------------------------------- /tests/sys/stat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | chflags 10 | chmod 11 | mkdir 12 | stat 13 | utimens) 14 | -------------------------------------------------------------------------------- /tests/sys/stat/test-mkdir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int test_ENOENT() 15 | { 16 | errno = 0; 17 | int status = mkdir("", 0700); 18 | ASSERT_EQ(status, -1); 19 | ASSERT_ERRNO(ENOENT); 20 | return 0; 21 | } 22 | 23 | int test_mkdir() 24 | { 25 | errno = 0; 26 | int status; 27 | const char *dirname = "t-mkdir"; 28 | 29 | status = mkdir(dirname, 0700); 30 | ASSERT_EQ(status, 0); 31 | ASSERT_EQ(GetFileAttributesA(dirname), FILE_ATTRIBUTE_DIRECTORY); 32 | 33 | // should fail with EEXIST 34 | status = mkdir(dirname, 0700); 35 | ASSERT_EQ(status, -1); 36 | ASSERT_ERRNO(EEXIST); 37 | 38 | ASSERT_SUCCESS(rmdir(dirname)); 39 | 40 | return 0; 41 | } 42 | 43 | int test_mkdirat() 44 | { 45 | errno = 0; 46 | int status; 47 | int dirfd; 48 | const char *dirname = "t-mkdirat"; 49 | const char *dirname_child = "t-mkdirat-child"; 50 | 51 | status = mkdir(dirname, 0700); 52 | ASSERT_EQ(status, 0); 53 | 54 | dirfd = open(dirname, O_RDONLY); 55 | ASSERT_EQ(dirfd,3); 56 | 57 | status = mkdirat(dirfd, dirname_child, 0700); 58 | ASSERT_EQ(status, 0); 59 | ASSERT_EQ(GetFileAttributesA("t-mkdirat/t-mkdirat-child"), FILE_ATTRIBUTE_DIRECTORY); 60 | 61 | ASSERT_SUCCESS(unlinkat(dirfd,dirname_child,AT_REMOVEDIR)); 62 | ASSERT_SUCCESS(close(dirfd)); 63 | ASSERT_SUCCESS(rmdir(dirname)); 64 | 65 | return 0; 66 | } 67 | 68 | void cleanup() 69 | { 70 | remove("t-mkdir"); 71 | remove("t-mkdirat/t-mkdirat-child"); 72 | remove("t-mkdirat"); 73 | } 74 | 75 | int main() 76 | { 77 | INITIAILIZE_TESTS(); 78 | CLEANUP(cleanup); 79 | 80 | TEST(test_ENOENT()); 81 | TEST(test_mkdir()); 82 | TEST(test_mkdirat()); 83 | 84 | VERIFY_RESULT_AND_EXIT(); 85 | } 86 | -------------------------------------------------------------------------------- /tests/sys/statfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(statfs) 9 | -------------------------------------------------------------------------------- /tests/sys/statvfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(statvfs) 9 | -------------------------------------------------------------------------------- /tests/sys/statvfs/test-statvfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void print_statvfs(const struct statvfs *statvfsbuf) 14 | { 15 | printf("f_bsize (Filesystem block size): %lu\n", statvfsbuf->f_bsize); 16 | printf("f_frsize (Fragment size): %lu\n", statvfsbuf->f_frsize); 17 | printf("f_flag (Filesystem attributes): %lu\n", statvfsbuf->f_flag); 18 | printf("f_blocks (Total number of blocks): %llu\n", statvfsbuf->f_blocks); 19 | printf("f_bfree (Number of free blocks): %llu\n", statvfsbuf->f_bfree); 20 | printf("f_bavail (Number of free blocks for unprivileged users): %llu\n", statvfsbuf->f_bavail); 21 | printf("f_fsid (Filesystem ID): %lu\n", statvfsbuf->f_fsid); 22 | printf("f_namemax (Maximum path length): %lu\n", statvfsbuf->f_namemax); 23 | printf("f_fstypename (Filesystem type): %s\n", statvfsbuf->f_fstypename); 24 | } 25 | 26 | int test_statvfs() 27 | { 28 | int status; 29 | struct statvfs statvfsbuf; 30 | char cwd[256]; 31 | 32 | getcwd(cwd, 256); 33 | 34 | status = statvfs(cwd, &statvfsbuf); 35 | ASSERT_EQ(status, 0); 36 | 37 | print_statvfs(&statvfsbuf); 38 | 39 | return 0; 40 | } 41 | 42 | int test_fstatvfs() 43 | { 44 | int status; 45 | int fd; 46 | struct statvfs statvfsbuf; 47 | char cwd[256]; 48 | 49 | getcwd(cwd, 256); 50 | 51 | fd = open(cwd, O_PATH | O_DIRECTORY); 52 | ASSERT_EQ(fd, 3); 53 | 54 | status = fstatvfs(fd, &statvfsbuf); 55 | ASSERT_EQ(status, 0); 56 | 57 | print_statvfs(&statvfsbuf); 58 | 59 | ASSERT_SUCCESS(close(fd)); 60 | 61 | return 0; 62 | } 63 | 64 | int main() 65 | { 66 | INITIAILIZE_TESTS(); 67 | TEST(test_statvfs()); 68 | TEST(test_fstatvfs()); 69 | VERIFY_RESULT_AND_EXIT(); 70 | } 71 | -------------------------------------------------------------------------------- /tests/sys/time/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | itimers 10 | timer) 11 | -------------------------------------------------------------------------------- /tests/sys/times/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(times) 9 | -------------------------------------------------------------------------------- /tests/sys/times/test-times.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Not really a test, just see if it works. 13 | int test_times() 14 | { 15 | clock_t clk; 16 | struct tms tmsbuf; 17 | 18 | usleep(10000); 19 | 20 | clk = times(&tmsbuf); 21 | ASSERT_NOTEQ(clk, -1); 22 | 23 | printf("Boot time (clock ticks) : %ld\n", clk); 24 | printf("User time (clock ticks) : %ld\n", tmsbuf.tms_utime); 25 | printf("Kernel time (clock ticks) : %ld\n", tmsbuf.tms_stime); 26 | 27 | return 0; 28 | } 29 | 30 | int main() 31 | { 32 | INITIAILIZE_TESTS(); 33 | TEST(test_times()); 34 | VERIFY_RESULT_AND_EXIT() 35 | } 36 | -------------------------------------------------------------------------------- /tests/sys/utsname/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(uname) 9 | -------------------------------------------------------------------------------- /tests/sys/utsname/test-uname.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | // Not really a test, just see if it works 12 | int test_uname() 13 | { 14 | struct utsname name; 15 | int status; 16 | 17 | status = uname(&name); 18 | ASSERT_EQ(status, 0); 19 | 20 | printf("sysname : %s\n", name.sysname); 21 | printf("version : %s\n", name.version); 22 | printf("release : %s\n", name.release); 23 | printf("machine : %s\n", name.machine); 24 | printf("nodename : %s\n", name.nodename); 25 | printf("domainname : %s\n", name.domainname); 26 | 27 | return 0; 28 | } 29 | 30 | int main() 31 | { 32 | INITIAILIZE_TESTS(); 33 | TEST(test_uname()); 34 | VERIFY_RESULT_AND_EXIT() 35 | } 36 | -------------------------------------------------------------------------------- /tests/sys/wait/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(waitpid) 9 | 10 | add_executable(child-helper child-helper.c) 11 | target_link_libraries(child-helper wlibc) 12 | -------------------------------------------------------------------------------- /tests/sys/wait/child-helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char **argv) 13 | { 14 | if (argc == 3) 15 | { 16 | int mode = atoi(argv[1]); 17 | if (mode == 1) 18 | { 19 | int duration = atoi(argv[2]); 20 | usleep(duration * 1000); 21 | } 22 | if (mode == 2) 23 | { 24 | int sig = atoi(argv[2]); 25 | raise(sig); 26 | } 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/sys/xattr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests(xattr) 9 | -------------------------------------------------------------------------------- /tests/threads/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | cnd 10 | init 11 | mtx 12 | thrd 13 | tss) 14 | -------------------------------------------------------------------------------- /tests/threads/test-init.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int test_variable = 0; 12 | 13 | void init_function(void) 14 | { 15 | ++test_variable; 16 | } 17 | 18 | int thrd_function(void *once) 19 | { 20 | call_once((once_flag *)once, init_function); 21 | return 1; 22 | } 23 | 24 | int test_init() 25 | { 26 | int status; 27 | int result; 28 | thrd_t thread_1, thread_2; 29 | once_flag once = ONCE_FLAG_INIT; 30 | 31 | status = thrd_create(&thread_1, thrd_function, (void *)&once); 32 | ASSERT_EQ(status, 0); 33 | 34 | status = thrd_create(&thread_2, thrd_function, (void *)&once); 35 | ASSERT_EQ(status, 0); 36 | 37 | status = thrd_join(thread_1, &result); 38 | ASSERT_EQ(status, 0); 39 | ASSERT_EQ(result, 1); 40 | 41 | status = thrd_join(thread_2, &result); 42 | ASSERT_EQ(status, 0); 43 | ASSERT_EQ(result, 1); 44 | 45 | ASSERT_EQ(test_variable, 1); 46 | 47 | return 0; 48 | } 49 | 50 | int main() 51 | { 52 | INITIAILIZE_TESTS(); 53 | TEST(test_init()); 54 | VERIFY_RESULT_AND_EXIT(); 55 | } 56 | -------------------------------------------------------------------------------- /tests/threads/test-thrd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | typedef struct _args_struct 12 | { 13 | int a, b; 14 | } args_struct; 15 | 16 | int func(void *arg) 17 | { 18 | args_struct *args = (args_struct *)arg; 19 | return (args->a + args->b); 20 | } 21 | 22 | int empty() 23 | { 24 | return 0; 25 | } 26 | 27 | int test_thread_basic() 28 | { 29 | int status; 30 | int result; 31 | args_struct args; 32 | thrd_t thread; 33 | 34 | args.a = 5; 35 | args.b = 10; 36 | 37 | status = thrd_create(&thread, func, (void *)&args); 38 | ASSERT_EQ(status, 0); 39 | 40 | status = thrd_join(thread, &result); 41 | ASSERT_EQ(status, 0); 42 | ASSERT_EQ(result, 15); 43 | 44 | return 0; 45 | } 46 | 47 | int test_join_detach() 48 | { 49 | int status; 50 | thrd_t thread; 51 | 52 | status = thrd_create(&thread, (thrd_start_t)empty, NULL); 53 | ASSERT_EQ(status, 0); 54 | 55 | status = thrd_detach(thread); 56 | ASSERT_EQ(status, 0); 57 | 58 | // Joining a detached thread should fail. 59 | status = thrd_join(thread, NULL); 60 | ASSERT_EQ(status, -1); 61 | 62 | // Repeated detach should also fail. 63 | status = thrd_detach(thread); 64 | ASSERT_EQ(status, -1); 65 | 66 | return 0; 67 | } 68 | 69 | int main() 70 | { 71 | INITIAILIZE_TESTS(); 72 | 73 | TEST(test_thread_basic()); 74 | TEST(test_join_detach()); 75 | 76 | VERIFY_RESULT_AND_EXIT(); 77 | } 78 | -------------------------------------------------------------------------------- /tests/unistd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | ]] 7 | 8 | wlibc_add_tests( 9 | access 10 | alarm 11 | close 12 | chdir 13 | chown 14 | dup 15 | getcwd 16 | io 17 | isatty 18 | kill 19 | link 20 | nice 21 | pio 22 | pipes 23 | symlinks 24 | remove 25 | truncate 26 | ttyname) 27 | 28 | add_executable(kill-helper kill-helper.c) 29 | -------------------------------------------------------------------------------- /tests/unistd/kill-helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | 9 | int main() 10 | { 11 | while (1) 12 | ; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/unistd/test-alarm.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int count = 0; 13 | 14 | void SIGALRM_handler(int sig) 15 | { 16 | count += sig; 17 | } 18 | 19 | int test_alarm() 20 | { 21 | int status; 22 | 23 | status = alarm(1); 24 | ASSERT_EQ(status, 0); 25 | 26 | usleep(1500000); // 1.5 seconds 27 | 28 | ASSERT_EQ(count, SIGALRM); 29 | 30 | return 0; 31 | } 32 | 33 | int main() 34 | { 35 | INITIAILIZE_TESTS(); 36 | 37 | signal(SIGALRM, SIGALRM_handler); 38 | TEST(test_alarm()); 39 | 40 | VERIFY_RESULT_AND_EXIT() 41 | } 42 | -------------------------------------------------------------------------------- /tests/unistd/test-close.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int test_EBADF() 16 | { 17 | int status = close(-1); 18 | ASSERT_EQ(status, -1); 19 | ASSERT_ERRNO(EBADF); 20 | return 0; 21 | } 22 | 23 | int test_okay_normal_file() 24 | { 25 | int status; 26 | int fd; 27 | const char *filename = "t-close"; 28 | HANDLE handle; 29 | DWORD error; 30 | BY_HANDLE_FILE_INFORMATION FILE_INFO; 31 | 32 | fd = open(filename, O_CREAT | O_RDONLY); 33 | ASSERT_EQ(fd, 3); 34 | handle = get_fd_handle(fd); 35 | status = close(fd); 36 | ASSERT_EQ(status, 0); 37 | 38 | // Check if the underlying handle is actually closed 39 | GetFileInformationByHandle(handle, &FILE_INFO); 40 | error = GetLastError(); 41 | ASSERT_EQ(error, ERROR_INVALID_HANDLE); 42 | 43 | ASSERT_SUCCESS(unlink(filename)); 44 | 45 | return 0; 46 | } 47 | 48 | int test_okay_directory() 49 | { 50 | int status; 51 | int fd; 52 | HANDLE handle; 53 | DWORD error; 54 | BY_HANDLE_FILE_INFORMATION FILE_INFO; 55 | 56 | fd = open(".", O_RDONLY); 57 | ASSERT_EQ(fd, 3); 58 | handle = get_fd_handle(fd); 59 | status = close(fd); 60 | ASSERT_EQ(status, 0); 61 | 62 | // Check if the underlying handle is actually closed 63 | GetFileInformationByHandle(handle, &FILE_INFO); 64 | error = GetLastError(); 65 | ASSERT_EQ(error, ERROR_INVALID_HANDLE); 66 | 67 | return 0; 68 | } 69 | 70 | void cleanup() 71 | { 72 | remove("t-close"); 73 | } 74 | 75 | int main() 76 | { 77 | INITIAILIZE_TESTS(); 78 | CLEANUP(cleanup); 79 | 80 | TEST(test_EBADF()); 81 | TEST(test_okay_normal_file()); 82 | TEST(test_okay_directory()); 83 | 84 | VERIFY_RESULT_AND_EXIT(); 85 | } 86 | -------------------------------------------------------------------------------- /tests/unistd/test-getcwd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // This is the only worthwhile test 13 | int test_ERANGE() 14 | { 15 | char buf[10]; 16 | getcwd(buf, 10); 17 | ASSERT_ERRNO(ERANGE); 18 | return 0; 19 | } 20 | 21 | int main() 22 | { 23 | INITIAILIZE_TESTS(); 24 | TEST(test_ERANGE()); 25 | VERIFY_RESULT_AND_EXIT(); 26 | } 27 | -------------------------------------------------------------------------------- /tests/unistd/test-kill.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int test_EINVAL() 16 | { 17 | errno = 0; 18 | int status = kill(getpid(), 64); 19 | ASSERT_ERRNO(EINVAL); 20 | ASSERT_EQ(status, -1); 21 | return 0; 22 | } 23 | 24 | int test_kill() 25 | { 26 | int status, wstatus = 0; 27 | pid_t pid; 28 | char *argv[] = {"kill-helper", NULL}; 29 | 30 | status = posix_spawn(&pid, "kill-helper", NULL, NULL, argv, NULL); 31 | ASSERT_EQ(status, 0); 32 | 33 | status = kill(pid, SIGTERM); 34 | ASSERT_EQ(status, 0); 35 | 36 | status = waitpid(pid, &wstatus, 0); 37 | ASSERT_EQ(status, pid); 38 | ASSERT_EQ(wstatus, 128 + SIGTERM); 39 | 40 | return 0; 41 | } 42 | 43 | int test_suspend() 44 | { 45 | int status, wstatus = 0; 46 | pid_t pid; 47 | char *argv[] = {"kill-helper", NULL}; 48 | 49 | status = posix_spawn(&pid, "kill-helper", NULL, NULL, argv, NULL); 50 | ASSERT_EQ(status, 0); 51 | 52 | // This should suspend the process. 53 | status = kill(pid, SIGSTOP); 54 | ASSERT_EQ(status, 0); 55 | 56 | usleep(1000); 57 | 58 | status = waitpid(pid, &wstatus, WNOHANG); 59 | ASSERT_EQ(status, 0); 60 | ASSERT_EQ(wstatus, -1); 61 | 62 | // Now kill the process. 63 | status = kill(pid, SIGTERM); 64 | ASSERT_EQ(status, 0); 65 | 66 | status = waitpid(pid, &wstatus, 0); 67 | ASSERT_EQ(status, pid); 68 | ASSERT_EQ(wstatus, 128 + SIGTERM); 69 | 70 | return 0; 71 | } 72 | 73 | int main() 74 | { 75 | INITIAILIZE_TESTS(); 76 | 77 | TEST(test_EINVAL()); 78 | TEST(test_kill()); 79 | TEST(test_suspend()); 80 | 81 | VERIFY_RESULT_AND_EXIT(); 82 | } 83 | -------------------------------------------------------------------------------- /tests/unistd/test-ttyname.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020-2025 Sibi Siddharthan 3 | 4 | Distributed under the MIT license. 5 | Refer to the LICENSE file at the root directory for details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int test_EBADF() 14 | { 15 | char *name = ttyname(3); 16 | ASSERT_ERRNO(EBADF); 17 | ASSERT_NULL(name); 18 | return 0; 19 | } 20 | 21 | int test_ENOTTY() 22 | { 23 | int fd = creat("t-ttyname", 0700); 24 | char *name = ttyname(fd); 25 | ASSERT_ERRNO(ENOTTY); 26 | ASSERT_NULL(name); 27 | ASSERT_SUCCESS(close(fd)); 28 | ASSERT_SUCCESS(unlink("t-ttyname")); 29 | return 0; 30 | } 31 | 32 | int test_ERANGE() 33 | { 34 | char name[4]; 35 | int result = ttyname_r(0, name, 4); 36 | ASSERT_ERRNO(ERANGE); 37 | ASSERT_EQ(result, ERANGE); 38 | return 0; 39 | } 40 | 41 | int test_okay() 42 | { 43 | fprintf(stderr, "%s\n", ttyname(0)); 44 | return 0; 45 | } 46 | 47 | int main() 48 | { 49 | INITIAILIZE_TESTS(); 50 | 51 | TEST(test_EBADF()); 52 | TEST(test_ENOTTY()); 53 | // Only run these if stdin is a console device 54 | if (isatty(0)) 55 | { 56 | TEST(test_ERANGE()); 57 | TEST(test_okay()); 58 | } 59 | 60 | VERIFY_RESULT_AND_EXIT(); 61 | } 62 | --------------------------------------------------------------------------------