|
|
|
@ -2463,66 +2463,16 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) |
|
|
|
d_cache (dir), DIR_BUF_SIZE, |
|
|
|
FileIdBothDirectoryInformation, |
|
|
|
FALSE, NULL, dir->__d_position == 0); |
|
|
|
/* FileIdBothDirectoryInformation isn't supported for remote drives
|
|
|
|
on NT4 and 2K systems. There are also hacked versions of |
|
|
|
Samba 3.0.x out there (Debian-based it seems), which return |
|
|
|
STATUS_NOT_SUPPORTED rather than handling this info class. |
|
|
|
We just fall back to using a standard directory query in |
|
|
|
this case and note this case using the dirent_get_d_ino flag. */ |
|
|
|
if (!NT_SUCCESS (status) && status != STATUS_NO_MORE_FILES |
|
|
|
/* FileIdBothDirectoryInformation isn't supported on some
|
|
|
|
remote drives, but we don't know every system out there. |
|
|
|
Check various status codes indicating this. */ |
|
|
|
if (!NT_SUCCESS (status) |
|
|
|
&& (status == STATUS_INVALID_LEVEL |
|
|
|
|| status == STATUS_NOT_SUPPORTED |
|
|
|
|| status == STATUS_INVALID_PARAMETER |
|
|
|
|| status == STATUS_INVALID_NETWORK_RESPONSE |
|
|
|
|| status == STATUS_INVALID_INFO_CLASS)) |
|
|
|
dir->__flags &= ~dirent_get_d_ino; |
|
|
|
/* Something weird happens on Samba up to version 3.0.21c, which is
|
|
|
|
fixed in 3.0.22. FileIdBothDirectoryInformation seems to work |
|
|
|
nicely, but only up to the 128th entry in the directory. After |
|
|
|
reaching this entry, the next call to NtQueryDirectoryFile |
|
|
|
(FileIdBothDirectoryInformation) returns STATUS_INVALID_LEVEL. |
|
|
|
Why should we care, we can just switch to |
|
|
|
FileBothDirectoryInformation, isn't it? Nope! The next call to |
|
|
|
NtQueryDirectoryFile(FileBothDirectoryInformation) actually |
|
|
|
returns STATUS_NO_MORE_FILES, regardless how many files are left |
|
|
|
unread in the directory. This does not happen when using |
|
|
|
FileBothDirectoryInformation right from the start, but since |
|
|
|
we can't decide whether the server we're talking with has this |
|
|
|
bug or not, we end up serving Samba shares always in the slow |
|
|
|
mode using FileBothDirectoryInformation. So, what we do here is |
|
|
|
to implement the solution suggested by Andrew Tridgell, we just |
|
|
|
reread all entries up to dir->d_position using |
|
|
|
FileBothDirectoryInformation. |
|
|
|
However, We do *not* mark this server as broken and fall back to |
|
|
|
using FileBothDirectoryInformation further on. This would slow |
|
|
|
down every access to such a server, even for directories under |
|
|
|
128 entries. Also, bigger dirs only suffer from one additional |
|
|
|
call per full directory scan, which shouldn't be too big a hit. |
|
|
|
This can easily be changed if necessary. */ |
|
|
|
if (status == STATUS_INVALID_LEVEL && dir->__d_position) |
|
|
|
{ |
|
|
|
d_cachepos (dir) = 0; |
|
|
|
for (int cnt = 0; cnt < dir->__d_position; ++cnt) |
|
|
|
{ |
|
|
|
if (d_cachepos (dir) == 0) |
|
|
|
{ |
|
|
|
status = NtQueryDirectoryFile (get_handle (), NULL, NULL, |
|
|
|
NULL, &io, d_cache (dir), |
|
|
|
DIR_BUF_SIZE, |
|
|
|
FileBothDirectoryInformation, |
|
|
|
FALSE, NULL, cnt == 0); |
|
|
|
if (!NT_SUCCESS (status)) |
|
|
|
goto go_ahead; |
|
|
|
} |
|
|
|
buf = (PFILE_ID_BOTH_DIR_INFORMATION) (d_cache (dir) |
|
|
|
+ d_cachepos (dir)); |
|
|
|
if (buf->NextEntryOffset == 0) |
|
|
|
d_cachepos (dir) = 0; |
|
|
|
else |
|
|
|
d_cachepos (dir) += buf->NextEntryOffset; |
|
|
|
} |
|
|
|
goto go_ahead; |
|
|
|
} |
|
|
|
} |
|
|
|
/* NFS must use FileNamesInformation! Any other information class
|
|
|
|
skips all symlinks. */ |
|
|
|
@ -2535,8 +2485,6 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) |
|
|
|
FALSE, NULL, dir->__d_position == 0); |
|
|
|
} |
|
|
|
|
|
|
|
go_ahead: |
|
|
|
|
|
|
|
if (status == STATUS_NO_MORE_FILES) |
|
|
|
/*nothing*/; |
|
|
|
else if (!NT_SUCCESS (status)) |
|
|
|
|