Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,47 @@ aclocal.m4
.deps
/*.exe
*.dSYM/

# --- Added for CMake, MSVC, vcpkg, and Python workflows ---

# CMake & vcpkg
/build-*/
/out/
/bin/
CMakeCache.txt
CMakeFiles/
CMakeUserPresets.json
vcpkg_installed/
.vcpkg/
vcpkg-manifest-install.log

# Visual Studio & Windows artifacts
.vs/
*.sln
*.suo
*.user
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.obj
*.lib
*.exp
*.pdb
*.ilk
*.dll
*.idb
*.manifest

# Python
__pycache__/
*.py[cod]
*.class
.pytest_cache/
.venv/
venv/

# Scratch & Temporary
test_*.c
test_*.py
child_*.txt
*.i
190 changes: 190 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
cmake_minimum_required(VERSION 3.15)
project(rsync C CXX)

# Find dependencies
find_package(ZLIB QUIET)
if(NOT ZLIB_FOUND)
message(STATUS 'ZLIB not found in environment, fetching via FetchContent')
include(FetchContent)
FetchContent_Declare(
zlib
GIT_REPOSITORY https://github.com/madler/zlib.git
GIT_TAG v1.3.1
)
FetchContent_MakeAvailable(zlib)
if(NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
endif()
endif()
find_package(zstd CONFIG REQUIRED)
find_package(lz4 CONFIG REQUIRED)
find_package(xxHash CONFIG REQUIRED)
find_package(OpenSSL REQUIRED)

find_path(POPT_INCLUDE_DIR NAMES popt.h)
find_library(POPT_LIBRARY NAMES popt)

# Source files
set(RSYNC_SOURCES
flist.c rsync.c generator.c receiver.c cleanup.c sender.c exclude.c
util1.c util2.c main.c checksum.c match.c syscall.c log.c backup.c delete.c
options.c io.c compat.c hlink.c token.c uidlist.c socket.c hashtable.c
usage.c fileio.c batch.c clientname.c chmod.c acls.c xattrs.c
progress.c pipe.c
params.c loadparm.c clientserver.c access.c connection.c authenticate.c
lib/wildmatch.c lib/compat.c lib/snprintf.c lib/mdfour.c lib/md5.c
lib/permstring.c lib/pool_alloc.c lib/sysacls.c lib/sysxattrs.c
)

# Placeholder config.h to avoid compiler errors on Windows where configure wasn't run
set(HAVE_CONFIG_H 1)
set(RSYNC_VERSION "3.3.0")
set(HAVE_ZLIB 1)
set(HAVE_OPENSSL 1)
set(HAVE_STRERROR 1)
set(PACKAGE "rsync")
set(POPT_SYSCONFDIR "/etc")

set(SIZEOF_INT 4)
set(SIZEOF_LONG 4)
set(SIZEOF_SHORT 2)
set(SIZEOF_INT32_T 4)
set(SIZEOF_UINT32_T 4)
set(SIZEOF_INT64_T 8)
set(SIZEOF_UINT64_T 8)
set(SIZEOF_OFF_T 4)
set(SIZEOF_TIME_T 8)
set(SIZEOF_CHARP 8)

set(HAVE_SIZE_T 1)
set(HAVE_OFF_T 1)
set(HAVE_TIME_T 1)
set(HAVE_PID_T 1)
set(HAVE_DIRENT_H 1)
set(HAVE_UTIME 1)
set(HAVE_UTIMES 1)
set(HAVE_STRPBRK 1)
set(HAVE_GETCWD 1)

set(HAVE_STRUCT_ADDRINFO 1)
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
set(HAVE_GETADDRINFO 1)
set(HAVE_GETNAMEINFO 1)
set(HAVE_SOCKADDR_IN6 1)
set(HAVE_MEMMOVE 1)
set(HAVE_GETTIMEOFDAY_TZ 1)
set(HAVE_READLINK 1)

set(SIGUSR1 10)
set(SIGUSR2 12)
set(SIGHUP 1)
set(SIGALRM 14)
set(WNOHANG 1)
set(O_NOFOLLOW 0)
set(O_DIRECTORY 0)
set(AT_REMOVEDIR 0x200)

set(RSYNC_RSH "ssh")
set(NOBODY_USER "nobody")
set(NOBODY_GROUP "nobody")
set(RSYNCD_SYSCONF "/etc/rsyncd.conf")

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)

# Use the pre-generated headers that are committed to the repo
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/proto.h ${CMAKE_CURRENT_BINARY_DIR}/proto.h COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/daemon-parm.h ${CMAKE_CURRENT_BINARY_DIR}/daemon-parm.h COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/help-rsync.h ${CMAKE_CURRENT_BINARY_DIR}/help-rsync.h COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/help-rsyncd.h ${CMAKE_CURRENT_BINARY_DIR}/help-rsyncd.h COPYONLY)

file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/default-cvsignore.h "#define DEFAULT_CVSIGNORE \".svn .git .hg .bzr .cvs\"\n")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/default-dont-compress.h "#define DEFAULT_DONT_COMPRESS \"*.gz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tgz *.tbz *.rar *.jar *.pdf *.7z *.xz *.lzma\"\n")

add_executable(rsync ${RSYNC_SOURCES})

# Target include directories
get_filename_component(AUTO_WIN_MSVC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../auto-win-msvc" ABSOLUTE)
file(GLOB POSIX_INCLUDES "${AUTO_WIN_MSVC_DIR}/posix-*/include")
file(GLOB LINUX_INCLUDES "${AUTO_WIN_MSVC_DIR}/linux-*/include")
file(GLOB POSIX_SOURCES "${AUTO_WIN_MSVC_DIR}/posix-*/src/*.c")
target_include_directories(rsync PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_library(posix_shims STATIC ${POSIX_SOURCES})
target_include_directories(posix_shims PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

# Link libraries
target_link_libraries(rsync PRIVATE
posix_shims
ws2_32
netapi32
ZLIB::ZLIB
zstd::libzstd
lz4::lz4
xxHash::xxhash
OpenSSL::Crypto
OpenSSL::SSL
)

if(POPT_INCLUDE_DIR AND POPT_LIBRARY)
target_link_libraries(rsync PRIVATE ${POPT_LIBRARY})
target_include_directories(rsync PRIVATE ${POPT_INCLUDE_DIR})
else()
# Build included popt as fallback
add_library(popt STATIC
popt/popt.c popt/poptconfig.c popt/popthelp.c popt/poptparse.c popt/poptint.c
)
# Exclude CMAKE_CURRENT_SOURCE_DIR to avoid io.h clash
target_include_directories(popt PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/popt ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})
target_link_libraries(rsync PRIVATE popt)
target_include_directories(rsync PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/popt)
endif()

# Test Helpers
add_executable(tls tls.c syscall.c util2.c t_stub.c lib/compat.c lib/snprintf.c lib/permstring.c lib/sysxattrs.c)
target_link_libraries(tls PRIVATE posix_shims ws2_32 netapi32 popt)
target_include_directories(tls PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(trimslash trimslash.c syscall.c util2.c t_stub.c lib/compat.c lib/snprintf.c)
target_link_libraries(trimslash PRIVATE posix_shims ws2_32 netapi32)
target_include_directories(trimslash PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(t_unsafe t_unsafe.c syscall.c util1.c util2.c t_stub.c lib/compat.c lib/snprintf.c lib/wildmatch.c)
target_link_libraries(t_unsafe PRIVATE posix_shims ws2_32 netapi32)
target_include_directories(t_unsafe PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(t_chmod_secure t_chmod_secure.c syscall.c util1.c util2.c t_stub.c lib/compat.c lib/snprintf.c lib/wildmatch.c lib/permstring.c)
target_link_libraries(t_chmod_secure PRIVATE posix_shims ws2_32 netapi32)
target_include_directories(t_chmod_secure PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(t_secure_relpath t_secure_relpath.c syscall.c util1.c util2.c t_stub.c lib/compat.c lib/snprintf.c lib/wildmatch.c lib/permstring.c)
target_link_libraries(t_secure_relpath PRIVATE posix_shims ws2_32 netapi32)
target_include_directories(t_secure_relpath PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(wildtest wildtest.c t_stub.c lib/compat.c lib/snprintf.c)
target_link_libraries(wildtest PRIVATE posix_shims ws2_32 netapi32 popt)
target_include_directories(wildtest PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(getgroups getgroups.c)
target_link_libraries(getgroups PRIVATE posix_shims ws2_32 netapi32)
target_include_directories(getgroups PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

add_executable(getfsdev getfsdev.c)
target_link_libraries(getfsdev PRIVATE posix_shims ws2_32 netapi32)
target_include_directories(getfsdev PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/popt ${AUTO_WIN_MSVC_DIR} ${POSIX_INCLUDES} ${LINUX_INCLUDES})

# Tests
enable_testing()
find_program(PYTHON_EXECUTABLE python)
if(PYTHON_EXECUTABLE)
file(GLOB TEST_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/testsuite/*_test.py")
foreach(TEST_SCRIPT IN LISTS TEST_SCRIPTS)
get_filename_component(TEST_NAME ${TEST_SCRIPT} NAME)
add_test(
NAME ${TEST_NAME}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runtests.py --rsync-bin $<TARGET_FILE:rsync> ${TEST_SCRIPT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
# Ensure test uses the helpers built here
set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "TOOLDIR=$<TARGET_FILE_DIR:tls>")
endforeach()
endif()
115 changes: 115 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#ifndef CONFIG_H
#define CONFIG_H

#ifdef _MSC_VER
#include <stdint.h>
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
typedef int16_t int16;
typedef uint16_t uint16;

#include "../auto-win-msvc/namespace_win_shim.h"

// Interpolated config variables from CMake
#cmakedefine HAVE_CONFIG_H 1
#define RSYNC_VERSION "@RSYNC_VERSION@"
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_OPENSSL 1
#cmakedefine HAVE_STRERROR 1
#define PACKAGE "@PACKAGE@"
#define POPT_SYSCONFDIR "@POPT_SYSCONFDIR@"

#ifndef __builtin_expect
#define __builtin_expect(exp, c) (exp)
#endif

// Some extra missing types/macros for rsync
#define PATH_MAX MAX_PATH

#define SIZEOF_INT @SIZEOF_INT@
#define SIZEOF_LONG @SIZEOF_LONG@
#define SIZEOF_SHORT @SIZEOF_SHORT@
#define SIZEOF_INT32_T @SIZEOF_INT32_T@
#define SIZEOF_UINT32_T @SIZEOF_UINT32_T@
#define SIZEOF_INT64_T @SIZEOF_INT64_T@
#define SIZEOF_UINT64_T @SIZEOF_UINT64_T@
#define SIZEOF_OFF_T @SIZEOF_OFF_T@
#define SIZEOF_TIME_T @SIZEOF_TIME_T@
#define SIZEOF_CHARP @SIZEOF_CHARP@

#cmakedefine HAVE_SIZE_T 1
#cmakedefine HAVE_OFF_T 1
#cmakedefine HAVE_TIME_T 1
#cmakedefine HAVE_PID_T 1
#cmakedefine HAVE_DIRENT_H 1
#cmakedefine HAVE_UTIME 1
#cmakedefine HAVE_UTIMES 1
#cmakedefine HAVE_STRPBRK 1
#cmakedefine HAVE_GETCWD 1
#cmakedefine HAVE_STRUCT_ADDRINFO 1
#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1
#cmakedefine HAVE_GETADDRINFO 1
#cmakedefine HAVE_GETNAMEINFO 1
#cmakedefine HAVE_SOCKADDR_IN6 1
#cmakedefine HAVE_MEMMOVE 1
#cmakedefine HAVE_GETTIMEOFDAY_TZ 1
#cmakedefine HAVE_READLINK 1

#define direct dirent

#ifndef S_ISUID
#define S_ISUID 04000
#endif
#ifndef S_ISGID
#define S_ISGID 02000
#endif
#ifndef S_ISVTX
#define S_ISVTX 01000
#endif

#cmakedefine SIGUSR1 @SIGUSR1@
#cmakedefine SIGUSR2 @SIGUSR2@
#cmakedefine SIGHUP @SIGHUP@
#cmakedefine SIGALRM @SIGALRM@
#cmakedefine WNOHANG @WNOHANG@
#cmakedefine O_NOFOLLOW @O_NOFOLLOW@
#cmakedefine O_DIRECTORY @O_DIRECTORY@
#cmakedefine AT_REMOVEDIR @AT_REMOVEDIR@

#define RSYNC_RSH "@RSYNC_RSH@"
#define NOBODY_USER "@NOBODY_USER@"
#define NOBODY_GROUP "@NOBODY_GROUP@"
#define RSYNCD_SYSCONF "@RSYNCD_SYSCONF@"

#define index strchr
#define rindex strrchr

#ifndef major
#define major(dev) 0
#define minor(dev) 0
#define makedev(maj, min) 0
#endif

static inline int do_chmod_at(int a, const char* b, int c) { return 0; }
static inline int fchdir(int a) { return 0; }
#define WIFSIGNALED(x) 0
#define SIGACTMASK(a,b) 0
static inline int unlinkat(int a, const char* b, int c) { return 0; }
static inline int renameat(int a, const char* b, int c, const char* d) { return 0; }
static inline int mkdirat(int a, const char* b, int c) { return 0; }
static inline int chroot(const char* a) { return 0; }
static inline char* getpass(const char* a) { return ""; }
static inline char* getwd(char* a) { return ""; }
static inline int wait3(int* a, int b, void* c) { return 0; }
static inline struct tm *gmtime_r(const time_t *timep, struct tm *result) { return gmtime_s(result, timep) == 0 ? result : NULL; }

#include <corecrt_io.h>

#define socketpair posix_socketpair
extern int posix_socketpair(int domain, int type, int protocol, int socket_vector[2]);

#endif

#endif // CONFIG_H
2 changes: 2 additions & 0 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ def main():
required_helpers = ['tls', 'trimslash', 't_unsafe', 't_chmod_secure',
't_secure_relpath',
'wildtest', 'getgroups', 'getfsdev']
if sys.platform == 'win32':
required_helpers = [h + '.exe' for h in required_helpers]
missing = [h for h in required_helpers
if not os.path.isfile(os.path.join(tooldir, h))]
if missing:
Expand Down
20 changes: 16 additions & 4 deletions testsuite/rsyncfns.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
from __future__ import annotations

import atexit
import fcntl
try:
import fcntl
except ImportError:
fcntl = None
import msvcrt
import filecmp
import os
import platform
Expand Down Expand Up @@ -196,9 +200,17 @@ def claim_ports(*ports: int) -> 'None':
if _port_lock_fd is None:
_port_lock_fd = _open_lock_file()
for port in sorted(ports):
# F_SETLKW via fcntl.lockf(LOCK_EX, length, start): exclusive
# byte-range lock on byte `port`, blocking until acquired.
fcntl.lockf(_port_lock_fd, fcntl.LOCK_EX, 1, port)
# exclusive byte-range lock on byte `port`, blocking until acquired.
if fcntl:
fcntl.lockf(_port_lock_fd, fcntl.LOCK_EX, 1, port)
else:
os.lseek(_port_lock_fd, port, os.SEEK_SET)
while True:
try:
msvcrt.locking(_port_lock_fd, msvcrt.LK_LOCK, 1)
break
except OSError:
time.sleep(0.1)


# --- standalone rsyncd helpers ---------------------------------------------
Expand Down
Loading
Loading