Commit Graph

6 Commits

Author SHA1 Message Date
Stepan Ulyanin be8fdc13c0 Allow to copy files and symlinks while overwriting the destination (#3508)
Adds capability to NIOFS to copy regular files and symlink, allowing to
overwrite the destination.

### Motivation:

Per https://github.com/apple/swift-nio/issues/3403 and
https://github.com/apple/swift-nio/pull/3470 we want to add
`replaceExisting: bool` to `FileSystem.copyItem`.

### Modifications:

1. Adds `replaceExisting: bool` parameter to
`FileSystemProtocol.copyItem`.
2. Adds `replaceExisting: bool` parameter to `FileSystem.copyItem` and
implementation for regular files and symbolic links.
3. Adds tests.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2026-02-18 08:57:33 +00:00
Stepan Ulyanin db01d87942 Add symlinkat, renameatx_np, and unlinkat system call wrappers (#3505)
Adds three new system call wrappers for the `symlinkat`, `renameatx_np`,
and `unlinkat` system calls.

### Motivation:

Related to https://github.com/apple/swift-nio/issues/3403 and
https://github.com/apple/swift-nio/pull/3470. This PR adds syscall
wrappers needed to atomically overwrite existing files or symlinks at
the destination during copy operations. On Linux, atomic overwrites
require a "copy to temp file, then rename" strategy. We use the `*at`
family of syscalls (which operate relative to directory file
descriptors) to avoid TOCTOU race conditions.

### Modifications:

1. Adds three system call wrappers for the `symlinkat`, `renameatx_np`,
and `unlinkat` system calls.
2. Adds related tests
3. Updates the `FileSystemError` for `symlink` and `unlink` to take in
the system call name to allow for the `*at` names to be passed.
2026-02-09 08:38:25 +00:00
Karan Lokchandani 608e511d7a Add homeDirectory accessor to FileSystem (#3471)
Add homeDirectory accessor to FileSystem

### Motivation:
Addresses #3381 by adding a `homeDirectory` property to FileSystem,
equivalent to `FileManager.default.homeDirectoryForCurrentUser`.

### Modifications:
- Added `homeDirectory` property to `FileSystemProtocol` and implemented
in `FileSystem`
- Implementation checks `HOME` environment variable first, falls back to
`USERPROFILE` on Windows, or uses `getpwuid_r(3)` on POSIX systems
- Added system call wrappers (`system_getuid`, `libc_getpwuid_r`) with
proper platform guards
- Added `FileSystemError.getpwuid_r()` error helper

### Result:
Users can now access the home directory via `FileSystem.homeDirectory`,
returning a `FilePath` asynchronously. Follows the same pattern as
`currentWorkingDirectory` and `temporaryDirectory`.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2026-01-12 15:10:25 +00:00
George Barnett d963335ba0 Fail on early errors in parallel copy (#3435)
Motivation:

'copyItem' can be used to copy files/directories from a source to a
destination address and fails if the destination already exists. The
parallel version of it can wedge if a directory is being copied and the
directory can't be created at the destination path (for example, if a
file already exists at the destination).

The parallel copy works by feeding tasks (e.g. "copy this item from here
to there") into an async sequence and processing each task in a separate
child task within a task group. When copying directories a new directory
is created at the destination path and then each file within the source
directory is emitted as a separate item to process. Another item is sent
on the async sequence to indicate when the source directory is finished
with which may result in finishing the async sequence.

However, if creating the destination directory fails then that event
isn't sent. This results in the calling code never terminating the async
sequence and causes 'copyItem' to wedge.

Modifications:

- Use non-idempotent directory creation (copy item should fail if the
destination already exists, this was a regression introduced in
7124f096).
- Check whether to continue when a dir can't be created but always emit
the end of dir event
- If terminating when the task group hasn't reached its width limit then
check child tasks for errors

Result:

Parallel copy doesn't wedge
2025-11-05 08:47:05 +00:00
Hamza Hassanain 7124f0963a feat(NIOFileSystem): Add idempotent directory creation behavior (#3404) (#3410)
The createDirectory function will succeed without error if the target
directory already exists.

###  Motivation

This change addresses issue #3404. Currently,
`fileSystem.createDirectory` fails if the target directory already
exists, forcing users to write boilerplate try/catch blocks to handle
this common and expected case.

The goal is to make this function's behavior idempotent.

### Modifications

To achieve this, I've made the following changes:

**(Implementation)** A new private helper function,
`_handleCreateDirectoryFileExists`, was introduced. This function is
responsible for:

1. Performing a `stat` call on the path that failed.
2. Checking if the existing item is a directory (`S_IFDIR`).
3. Returning a success result if it's a directory, or re-throwing the
original `.fileExists` error if it's a file or another type of entity.

**(Logic)** The core `_createDirectory` function was updated to call
this new helper function whenever `Syscall.mkdir` fails with an `EEXIST`
(`.fileExists`) error. This check is applied in both internal loops to
correctly handle cases where either an intermediate directory or the
final target directory already exists.

### Result
With this change, users can now call the function
`fileSystem.createDirectory` and the operation will succeed even if the
directory is already present, leading to cleaner and more predictable
code.
2025-10-20 15:49:26 +01:00
George Barnett a18bddb0ac Add back NIOFileSystem (#3380)
Motivation:

We accidentally removed the 'NIOFileSystem' module from the
'_NIOFileSystem' product in the last release.

Modifications:

- Rename 'NIOFileSystem' and 'NIOFileSystemFoundationCompat' to 'NIOFS'
  and 'NIOFSFoundationCompat'
- Add back 'NIOFileSystem' which re-exports '_NIOFileSystem' (there was
  no publicly available 'NIOFileSystemFoundationCompat' module to
  remove, only '_NIOFileSystemFoundationCompat').

Result:

Fewer breaks
2025-09-23 17:29:01 +01:00