Skip to content

fix: MemMapFs.Remove returns error for non-empty directories#587

Open
Yanhu007 wants to merge 1 commit intospf13:masterfrom
Yanhu007:fix/remove-nonempty-dir
Open

fix: MemMapFs.Remove returns error for non-empty directories#587
Yanhu007 wants to merge 1 commit intospf13:masterfrom
Yanhu007:fix/remove-nonempty-dir

Conversation

@Yanhu007
Copy link
Copy Markdown

Fixes #232

Problem

MemMapFs.Remove() silently removes a non-empty directory and all its contents. This violates the os.Remove contract, which returns ENOTEMPTY for non-empty directories.

fs := afero.NewMemMapFs()
fs.MkdirAll("/dirname", 0755)
afero.WriteFile(fs, "/dirname/file", []byte("data"), 0644)
fs.Remove("/dirname") // succeeds, should fail with ENOTEMPTY

Fix

Before removing a directory, check if any entries have the directory path as a prefix. If children exist, return &os.PathError{Op: "remove", Path: name, Err: syscall.ENOTEMPTY}.

This matches the behavior of os.Remove on real filesystems.

os.Remove on real filesystems returns ENOTEMPTY when removing
a non-empty directory. MemMapFs.Remove silently removes the
directory and all its contents, which violates the os.Remove
contract.

Add a check for child entries before removing a directory.
If any children exist, return os.PathError with syscall.ENOTEMPTY.

Fixes spf13#232
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@afurm
Copy link
Copy Markdown

afurm commented Apr 13, 2026

The prefix check strings.HasPrefix(p, prefix) with prefix = name + FilePathSeparator correctly identifies children at one level. However, does the in-memory file system also support deep nesting like /dir/subdir/file.txt? If so, the check would also need to handle that the child path itself could have arbitrary depth. For a MemMapFs, the key question is whether a child at any depth under name should cause the remove to fail, or only direct children. The POSIX ENOTEMPTY typically applies to direct children only — but the current check also catches grandchildren since strings.HasPrefix("/dir/subdir", "/dir/") is true. Is that the intended behavior, or should the check be more precise?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MemMapFs Remove with directory name will remove non-empty directories

3 participants