phoenix-rtos / phoenix-rtos/phoenix-rtos-project
readdir() returns . after rmdir() and rewinddir() [on arm targets]
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 66
- Forks
- 49
- Avg merge
- 20h 25m
- Merged PRs (30d)
- 12
Description
Description
Calling rmdir() on an open directory successfully unlinks it (returns 0). However, after calling rewinddir() to reset the directory stream, a subsequent readdir() call returns the . entry.
POSIX specifies that rmdir() must immediately remove the . and .. entries before the function returns, even if a process still holds an open file descriptor to the directory.
Expected Behavior
mkdir()andopendir()successfully create and open the directory.rmdir()succeeds (returns 0) while the directory is held open.rewinddir()resets the directory stream to the beginning.- A subsequent
readdir()returnsNULL(indicating the.and..entries were removed).
Actual Behavior
mkdir()andopendir()successfully create and open the directory.rmdir()succeeds (returns 0).rewinddir()resets the directory stream.- A subsequent
readdir()returns a valid directory entry for., indicating the standard entries were not removed upon unlinking.
POSIX Requirement
- "If one or more processes have the directory open when the last link is removed, the dot and dot-dot entries, if present, shall be removed before rmdir() returns and no new entries may be created in the directory, but the directory shall not be removed until all references to the directory are closed." — POSIX.1-2017 (IEEE Std 1003.1),
rmdir()specification.
Minimal Reproduction (confirmed on target)
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
const char *dir_name = "ghostdir_repro";
DIR *dp;
struct dirent *entry;
if (mkdir(dir_name, 0700) != 0) {
perror("mkdir failed");
return 1;
}
dp = opendir(dir_name);
if (dp == NULL) {
perror("opendir failed");
rmdir(dir_name);
return 1;
}
if (rmdir(dir_name) != 0) {
perror("rmdir failed");
closedir(dp);
return 1;
}
/* Drain the stream until we hit End-Of-File */
while (readdir(dp) != NULL) {}
/* Rewind to the beginning of the now-deleted directory */
rewinddir(dp);
entry = readdir(dp);
if (entry == NULL) {
printf("PASS: readdir() returned NULL. Filesystem is POSIX compliant.\n");
} else {
printf("FAIL: FS BUG TRIGGERED! Expected NULL, but read: '%s'\n", entry->d_name);
}
closedir(dp);
return 0;
}
Output on aarch64a53-zynqmp-qemu
FAIL: FS BUG TRIGGERED! Expected NULL, but read: '.'
Output on ia32-generic-qemu
PASS: readdir() returned NULL. Filesystem is POSIX compliant.
Revision
62b46f93f586ebbadf352b1d35eb3ae580543ac0
Affected targets
Reproduced on aarch64a53-zynqmp-qemu but also affects:
- armv7a9-zynq7000-qemu,
- armv7r5f-zynqmp-qemu,
- armv7a7-imx6ull-evk,
- armv7m7-imxrt106x-evk,
- armv7m7-imxrt117x-evk,
- armv7a9-zynq7000-zedboard,
- armv7m4-stm32l4x6-nucleo
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the minimal C reproduction on an affected ARM target and compare it with ia32-generic-qemu. Then trace the filesystem implementations of rmdir(), rewinddir(), and readdir() to determine why '.' remains after unlinking an open directory. Done means the reproduction returns NULL after rewinddir() on the listed affected targets without regressing the passing target.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100