aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2025-03-17 08:59:56 +0000
committerRon Yorston <rmy@pobox.com>2025-03-17 08:59:56 +0000
commit3de63bc1739354df946c0b6dddd96058d8952bb7 (patch)
tree8472b44365c30e91ccf2d40397f510df3dcf3fd5
parent5749feb35f44869643445b244ace1d62a7faf65c (diff)
downloadbusybox-w32-3de63bc1739354df946c0b6dddd96058d8952bb7.tar.gz
busybox-w32-3de63bc1739354df946c0b6dddd96058d8952bb7.tar.bz2
busybox-w32-3de63bc1739354df946c0b6dddd96058d8952bb7.zip
win32: fake directories in readdir(2)HEADmaster
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.c28
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 @@
3struct DIR { 3struct 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
9static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) 11static 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