15
15
16
16
#ifdef WIN32
17
17
18
+ #define UMDF_USING_NTSTATUS
19
+
18
20
#include "c.h"
21
+ #include "port/win32ntdll.h"
22
+
19
23
#include <windows.h>
20
24
21
25
/*
@@ -107,12 +111,10 @@ fileinfo_to_stat(HANDLE hFile, struct stat *buf)
107
111
}
108
112
109
113
/*
110
- * Windows implementation of stat().
111
- *
112
- * This currently also implements lstat(), though perhaps that should change.
114
+ * Windows implementation of lstat().
113
115
*/
114
116
int
115
- _pgstat64 (const char * name , struct stat * buf )
117
+ _pglstat64 (const char * name , struct stat * buf )
116
118
{
117
119
/*
118
120
* Our open wrapper will report STATUS_DELETE_PENDING as ENOENT. We
@@ -129,10 +131,110 @@ _pgstat64(const char *name, struct stat *buf)
129
131
130
132
ret = fileinfo_to_stat (hFile , buf );
131
133
134
+ /*
135
+ * Junction points appear as directories to fileinfo_to_stat(), so we'll
136
+ * need to do a bit more work to distinguish them.
137
+ */
138
+ if (ret == 0 && S_ISDIR (buf -> st_mode ))
139
+ {
140
+ char next [MAXPGPATH ];
141
+ ssize_t size ;
142
+
143
+ /*
144
+ * POSIX says we need to put the length of the target path into
145
+ * st_size. Use readlink() to get it, or learn that this is not a
146
+ * junction point.
147
+ */
148
+ size = readlink (name , next , sizeof (next ));
149
+ if (size < 0 )
150
+ {
151
+ if (errno == EACCES &&
152
+ pg_RtlGetLastNtStatus () == STATUS_DELETE_PENDING )
153
+ {
154
+ /* Unlinked underneath us. */
155
+ errno = ENOENT ;
156
+ ret = -1 ;
157
+ }
158
+ else if (errno == EINVAL )
159
+ {
160
+ /* It's not a junction point, nothing to do. */
161
+ }
162
+ else
163
+ {
164
+ /* Some other failure. */
165
+ ret = -1 ;
166
+ }
167
+ }
168
+ else
169
+ {
170
+ /* It's a junction point, so report it as a symlink. */
171
+ buf -> st_mode &= ~S_IFDIR ;
172
+ buf -> st_mode |= S_IFLNK ;
173
+ buf -> st_size = size ;
174
+ }
175
+ }
176
+
132
177
CloseHandle (hFile );
133
178
return ret ;
134
179
}
135
180
181
+ /*
182
+ * Windows implementation of stat().
183
+ */
184
+ int
185
+ _pgstat64 (const char * name , struct stat * buf )
186
+ {
187
+ int ret ;
188
+
189
+ ret = _pglstat64 (name , buf );
190
+
191
+ /* Do we need to follow a symlink (junction point)? */
192
+ if (ret == 0 && S_ISLNK (buf -> st_mode ))
193
+ {
194
+ char next [MAXPGPATH ];
195
+ ssize_t size ;
196
+
197
+ /*
198
+ * _pglstat64() already called readlink() once to be able to fill in
199
+ * st_size, and now we need to do it again to get the path to follow.
200
+ * That could be optimized, but stat() on symlinks is probably rare
201
+ * and this way is simple.
202
+ */
203
+ size = readlink (name , next , sizeof (next ));
204
+ if (size < 0 )
205
+ {
206
+ if (errno == EACCES &&
207
+ pg_RtlGetLastNtStatus () == STATUS_DELETE_PENDING )
208
+ {
209
+ /* Unlinked underneath us. */
210
+ errno = ENOENT ;
211
+ }
212
+ return -1 ;
213
+ }
214
+ if (size >= sizeof (next ))
215
+ {
216
+ errno = ENAMETOOLONG ;
217
+ return -1 ;
218
+ }
219
+ next [size ] = 0 ;
220
+
221
+ ret = _pglstat64 (next , buf );
222
+ if (ret == 0 && S_ISLNK (buf -> st_mode ))
223
+ {
224
+ /*
225
+ * We're only prepared to go one hop, because we only expect to
226
+ * deal with the simple cases that we create. The error for too
227
+ * many symlinks is supposed to be ELOOP, but Windows hasn't got
228
+ * it.
229
+ */
230
+ errno = EIO ;
231
+ return -1 ;
232
+ }
233
+ }
234
+
235
+ return ret ;
236
+ }
237
+
136
238
/*
137
239
* Windows implementation of fstat().
138
240
*/
0 commit comments