Keywords: rsync | file synchronization | permission error | timestamp setting | NFS filesystem
Abstract: This paper provides a comprehensive analysis of the 'failed to set times' error encountered during rsync file synchronization operations. It explores the root causes in special filesystems like NFS and FUSE, examines underlying permission mechanisms through code examples, and presents practical solutions using --omit-dir-times parameter, while discussing supplementary approaches for file ownership and system permissions.
Error Phenomenon and Background Analysis
When using rsync for file synchronization, users frequently encounter the following error message:
rsync: failed to set times on "/foo/bar": Operation not permitted (1)
rsync error: some files could not be transferred (code 23)
at /SourceCache/rsync/rsync-35.2/rsync/main.c(992) [sender=2.6.9]
While this error doesn't completely halt the file transfer process, it generates distracting messages in logs and affects operational cleanliness. The error indicates that permission was denied when attempting to set directory timestamps.
Root Cause Investigation
The core issue lies in the characteristics and permission restrictions of the target filesystem. When the target directory resides on NFS (Network File System) or certain FUSE (Filesystem in Userspace) implementations, these filesystems may impose additional restrictions on timestamp modification operations.
In Unix-like systems, setting file timestamps is typically accomplished through utime() or utimes() system calls. These system calls require the calling process to have appropriate privileges: either be the file owner or possess superuser privileges. Here's a simplified permission checking code example:
int set_file_times(const char *path, struct timespec *times) {
struct stat st;
// Retrieve file status information
if (stat(path, &st) == -1) {
return -1;
}
// Check permissions: current user must be file owner or root
if (geteuid() != st.st_uid && geteuid() != 0) {
errno = EPERM; // Operation not permitted
return -1;
}
// Execute timestamp setting
return utimensat(AT_FDCWD, path, times, 0);
}
Solution Implementation
The most direct and effective solution for this problem is using rsync's --omit-dir-times option (or its shorthand -O). This option instructs rsync to skip setting directory timestamps, thereby avoiding permission checks.
Here's an example command using this option:
rsync -av --omit-dir-times /source/path/ user@remotehost:/target/path/
From the perspective of rsync source code, the implementation logic for this option大致如下:
// Relevant logic in timestamp setting function
void set_file_attrs(const char *path, struct file_struct *file, int flags) {
// Check if omit_dir_times option is enabled
if ((flags & ATTRS_SKIP_MTIME) ||
(S_ISDIR(file->mode) && omit_dir_times)) {
// Skip directory timestamp setting
return;
}
// Normal timestamp setting logic
if (set_modtime(path, file->modtime) < 0) {
// Handle setting failure
rprintf(FERROR, "failed to set times on %s: %s\n",
path, strerror(errno));
}
}
Supplementary Analysis and Alternative Approaches
Beyond the primary solution, file ownership issues are another common cause of this error. Particularly on remote Darwin (macOS) systems, if the target directory ownership doesn't match the user executing the rsync process, permission errors will occur.
In such cases, file ownership can be checked and corrected as follows:
# Check file ownership
ls -la /foo/bar
# Correct ownership (if needed)
chown username:groupname /foo/bar
From a system call perspective, Darwin's utime() function implementation follows POSIX standards, requiring the calling process's effective user ID to match the file's owner ID or be the superuser. This design ensures system security but can sometimes inconvenience file synchronization operations.
Practical Application Recommendations
In actual production environments, it's recommended to choose appropriate solutions based on specific use cases:
- For NFS or FUSE filesystems: Prioritize using the
--omit-dir-timesoption, as it's the safest and most reliable solution. - For ownership issues: Ensure remote directories have correct ownership settings, or execute rsync operations with users possessing appropriate privileges.
- For automated scripts: Add error handling logic to properly log and ignore such non-fatal errors.
Here's a complete rsync wrapper script example demonstrating graceful handling of such errors:
#!/bin/bash
SOURCE_DIR="$1"
TARGET_DIR="$2"
# Execute rsync, ignoring directory timestamp errors
rsync -av --omit-dir-times "$SOURCE_DIR" "$TARGET_DIR" 2>&1 | \
grep -v "failed to set times"
# Check exit status
if [ ${PIPESTATUS[0]} -eq 0 ] || [ ${PIPESTATUS[0]} -eq 23 ]; then
echo "Synchronization completed (timestamp errors ignored)"
exit 0
else
echo "Synchronization failed"
exit 1
fi
By deeply understanding rsync's working principles and system permission mechanisms, we can more effectively diagnose and resolve such permission issues in file synchronization, ensuring smooth data transfer operations.