diff options
author | Ron Yorston <rmy@pobox.com> | 2025-03-17 08:59:56 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2025-03-17 08:59:56 +0000 |
commit | 3de63bc1739354df946c0b6dddd96058d8952bb7 (patch) | |
tree | 8472b44365c30e91ccf2d40397f510df3dcf3fd5 | |
parent | 5749feb35f44869643445b244ace1d62a7faf65c (diff) | |
download | busybox-w32-3de63bc1739354df946c0b6dddd96058d8952bb7.tar.gz busybox-w32-3de63bc1739354df946c0b6dddd96058d8952bb7.tar.bz2 busybox-w32-3de63bc1739354df946c0b6dddd96058d8952bb7.zip |
The emulation of readdir(2) didn't include the '.' and '..'
directories in the root of a logical drive. This resulted in
the 'ls' applet (and others) not matching the expected Unix
behaviour.
Alter the emulation of readdir(2) to include fake '.' and '..'
directories if necessary.
Adds 88-112 bytes.
(GitHub issue #487)
-rw-r--r-- | win32/dirent.c | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/win32/dirent.c b/win32/dirent.c index 795fc779c..f0e8deae2 100644 --- a/win32/dirent.c +++ b/win32/dirent.c | |||
@@ -3,7 +3,9 @@ | |||
3 | struct DIR { | 3 | struct DIR { |
4 | struct dirent dd_dir; | 4 | struct dirent dd_dir; |
5 | HANDLE dd_handle; /* FindFirstFile handle */ | 5 | HANDLE dd_handle; /* FindFirstFile handle */ |
6 | int dd_stat; /* 0-based index */ | 6 | int not_first; |
7 | int got_dot; | ||
8 | int got_dotdot; | ||
7 | }; | 9 | }; |
8 | 10 | ||
9 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) | 11 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) |
@@ -59,9 +61,11 @@ DIR *opendir(const char *name) | |||
59 | } | 61 | } |
60 | 62 | ||
61 | /* initialize DIR structure and copy first dir entry */ | 63 | /* initialize DIR structure and copy first dir entry */ |
62 | dir = xmalloc(sizeof(DIR)); | 64 | dir = xzalloc(sizeof(DIR)); |
63 | dir->dd_handle = h; | 65 | dir->dd_handle = h; |
64 | dir->dd_stat = 0; | 66 | /* dir->not_first = 0; */ |
67 | /* dir->got_dot = 0; */ | ||
68 | /* dir->got_dotdot = 0; */ | ||
65 | finddata2dirent(&dir->dd_dir, &fdata); | 69 | finddata2dirent(&dir->dd_dir, &fdata); |
66 | return dir; | 70 | return dir; |
67 | } | 71 | } |
@@ -74,11 +78,17 @@ struct dirent *readdir(DIR *dir) | |||
74 | } | 78 | } |
75 | 79 | ||
76 | /* if first entry, dirent has already been set up by opendir */ | 80 | /* if first entry, dirent has already been set up by opendir */ |
77 | if (dir->dd_stat) { | 81 | if (dir->not_first) { |
78 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ | 82 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ |
79 | WIN32_FIND_DATAA fdata; | 83 | WIN32_FIND_DATAA fdata; |
80 | if (FindNextFileA(dir->dd_handle, &fdata)) { | 84 | if (FindNextFileA(dir->dd_handle, &fdata)) { |
81 | finddata2dirent(&dir->dd_dir, &fdata); | 85 | finddata2dirent(&dir->dd_dir, &fdata); |
86 | } else if (!dir->got_dot) { | ||
87 | strcpy(dir->dd_dir.d_name, "."); | ||
88 | dir->dd_dir.d_type = DT_DIR; | ||
89 | } else if (!dir->got_dotdot) { | ||
90 | strcpy(dir->dd_dir.d_name, ".."); | ||
91 | dir->dd_dir.d_type = DT_DIR; | ||
82 | } else { | 92 | } else { |
83 | DWORD lasterr = GetLastError(); | 93 | DWORD lasterr = GetLastError(); |
84 | /* POSIX says you shouldn't set errno when readdir can't | 94 | /* POSIX says you shouldn't set errno when readdir can't |
@@ -89,7 +99,15 @@ struct dirent *readdir(DIR *dir) | |||
89 | } | 99 | } |
90 | } | 100 | } |
91 | 101 | ||
92 | ++dir->dd_stat; | 102 | /* Have we seen '.' or '..'? */ |
103 | if (dir->dd_dir.d_name[0] == '.') { | ||
104 | if (dir->dd_dir.d_name[1] == '\0') | ||
105 | dir->got_dot = TRUE; | ||
106 | else if (dir->dd_dir.d_name[1] == '.' && dir->dd_dir.d_name[2] == '\0') | ||
107 | dir->got_dotdot = TRUE; | ||
108 | } | ||
109 | |||
110 | dir->not_first = TRUE; | ||
93 | return &dir->dd_dir; | 111 | return &dir->dd_dir; |
94 | } | 112 | } |
95 | 113 | ||