ntdll / kernel32: #47

Eric Pouech pouech-eric at wanadoo.fr
Wed Feb 4 14:55:40 CST 2004


Moved directory browsing to ntdll
- Added NtQueryDirectoryFile
- Implemented FindFile{First|Next} on top of NtQueryDirectoryFile
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel46/file.c dlls/kernel/file.c
--- dlls/kernel46/file.c	2004-01-23 22:35:52.000000000 +0100
+++ dlls/kernel/file.c	2004-01-23 22:37:39.000000000 +0100
@@ -42,8 +42,12 @@
 
 #include "wine/unicode.h"
 #include "wine/debug.h"
+#include "wine/exception.h"
+#include "excpt.h"
 #include "async.h"
 
+#include "../files/smb.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(file);
 
 HANDLE dos_handles[DOS_TABLE_SIZE];
@@ -556,3 +560,395 @@
     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
     return FALSE;
 }
+
+/**************************************************************************
+ *                      Operations on file search                         *
+ **************************************************************************/
+
+/* Info structure for FindFirstFile handle */
+typedef struct
+{
+    CRITICAL_SECTION cs;
+    union
+    {
+        void*           nt_data;
+        SMB_DIR*        smb_dir;
+    } u;
+    BOOL   is_smb;
+    PFILE_BOTH_DIR_INFORMATION dir_info;
+} FIND_FIRST_INFO;
+
+
+static WINE_EXCEPTION_FILTER(page_fault)
+{
+    if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
+        return EXCEPTION_EXECUTE_HANDLER;
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+
+/***********************************************************************
+ *           DOSFS_FindNextEx
+ */
+static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
+{
+    /* FIXME UINT flags = DRIVE_GetFlags( info->drive ); */
+
+    while (info->dir_info)
+    {
+        /* FIXME: should we let the following code here, or shall we move it
+         * to ntdll
+         */
+#if 0        
+        /* Don't return '.' and '..' in the root of the drive */
+        if (drive_root && (long_name[0] == '.') &&
+            (!long_name[1] || ((long_name[1] == '.') && !long_name[2])))
+            continue;
+#endif
+        /* We have a matching entry; fill the result and return */
+        entry->dwFileAttributes = info->dir_info->FileAttributes;
+        /* FIXME: take endianness into account */
+        memcpy(&entry->ftCreationTime  , &info->dir_info->CreationTime,   sizeof(FILETIME));
+        memcpy(&entry->ftLastAccessTime, &info->dir_info->LastAccessTime, sizeof(FILETIME));
+        memcpy(&entry->ftLastWriteTime , &info->dir_info->LastWriteTime,  sizeof(FILETIME));
+        entry->nFileSizeHigh    = (DWORD)(info->dir_info->EndOfFile.QuadPart >> 32);
+        entry->nFileSizeLow     = (DWORD)(info->dir_info->EndOfFile.QuadPart & 0xffffffff);
+
+        memcpy(entry->cFileName, info->dir_info->FileName, 
+               info->dir_info->FileNameLength);
+        entry->cFileName[info->dir_info->FileNameLength / sizeof(WCHAR)] = 0;
+        memcpy(entry->cAlternateFileName, info->dir_info->ShortName, info->dir_info->ShortNameLength + sizeof(WCHAR));
+        entry->cAlternateFileName[info->dir_info->ShortNameLength / sizeof(WCHAR)] = 0;
+
+        /* FIXME */
+        /* if (!(flags & DRIVE_CASE_PRESERVING)) strlwrW( entry->cFileName ); */
+        TRACE("returning %s (%s) %02lx %ld\n",
+              debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName),
+              entry->dwFileAttributes, entry->nFileSizeLow );
+        info->dir_info = (info->dir_info->NextEntryOffset) ?
+            (PFILE_BOTH_DIR_INFORMATION)((char*)info->dir_info + 
+                                         info->dir_info->NextEntryOffset) : NULL;
+        return 1;
+    }
+    return 0;  /* End of directory */
+}
+
+/*************************************************************************
+ *           FindFirstFileExW  (KERNEL32.@)
+ */
+HANDLE WINAPI FindFirstFileExW(
+	LPCWSTR lpFileName,
+	FINDEX_INFO_LEVELS fInfoLevelId,
+	LPVOID lpFindFileData,
+	FINDEX_SEARCH_OPS fSearchOp,
+	LPVOID lpSearchFilter,
+	DWORD dwAdditionalFlags)
+{
+    FIND_FIRST_INFO *info;
+
+    if (!lpFileName)
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0))
+    {
+        FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags );
+        return INVALID_HANDLE_VALUE;
+    }
+
+    switch (fInfoLevelId)
+    {
+        case FindExInfoStandard:
+        {
+            WIN32_FIND_DATAW * data = (WIN32_FIND_DATAW *) lpFindFileData;
+
+            data->dwReserved0 = data->dwReserved1 = 0x0;
+            if (lpFileName[0] == '\\' && lpFileName[1] == '\\')
+            {
+                ERR("UNC path name\n");
+                if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(FIND_FIRST_INFO)))) break;
+                info->u.smb_dir = SMB_FindFirst(lpFileName);
+                if(!info->u.smb_dir)
+                {
+                    HeapFree(GetProcessHeap(), 0, info);
+                    break;
+                }
+                info->is_smb = TRUE;
+                RtlInitializeCriticalSection( &info->cs );
+            }
+            else
+            {
+                UNICODE_STRING      uname, umask;
+                OBJECT_ATTRIBUTES   oa;
+                HANDLE              h;
+                IO_STATUS_BLOCK     iosb;
+                LPCWSTR             pw;
+                ULONG               data_size;
+                WCHAR               tmp[MAX_PATH], fn[MAX_PATH];
+
+                TRACE("[%s]\n", debugstr_w(lpFileName));
+                oa.Length = sizeof(oa);
+                oa.RootDirectory = NULL;
+                oa.ObjectName = &uname;
+                oa.Attributes = 0;
+                oa.SecurityDescriptor = NULL;
+                oa.SecurityQualityOfService = NULL;
+
+                if (lpFileName[0] && lpFileName[1] == ':')
+                {
+                    /* FIXME: this cannot be tested unless we have a full path ? */
+                    /* don't allow root directories */
+                    if (!lpFileName[2] ||
+                        ((lpFileName[2] == '/' || lpFileName[2] == '\\') && !lpFileName[3]))
+                    {
+                        SetLastError(ERROR_FILE_NOT_FOUND);
+                        return INVALID_HANDLE_VALUE;
+                    }
+                }
+                for (pw = lpFileName + strlenW(lpFileName) - 2; pw >= lpFileName; pw--)
+                    if (*pw == '/' || *pw == '\\') break;
+                if (pw > lpFileName)
+                {
+                    memcpy(tmp, lpFileName, (pw - lpFileName + 1) * sizeof(WCHAR));
+                    tmp[pw - lpFileName + 1] = '\0';
+                    strcpyW(fn, pw + 1);
+                }
+                else if (pw == lpFileName)
+                {
+                    tmp[0] = '/'; tmp[1] = '\0';
+                    strcpyW(fn, pw + 1);
+                }
+                else
+                {
+                    tmp[0] = '.'; tmp[1] = '\0';
+                    strcpyW(fn, lpFileName);
+                }
+                RtlInitUnicodeString(&uname, tmp);
+                switch (fn[strlenW(fn) - 1])
+                {
+                case '/':
+                case '\\':
+                    fn[strlenW(fn) - 1] = '\0';
+                }
+                RtlInitUnicodeString(&umask, fn);
+                NtCreateFile(&h, GENERIC_READ /* | FILE_LIST_DIRECTORY */, &oa, &iosb,  
+                             NULL, 0, FILE_SHARE_READ, FILE_OPEN, 
+                             FILE_SYNCHRONOUS_IO_ALERT|FILE_DIRECTORY_FILE|FILE_OPEN_FOR_BACKUP_INTENT, 
+                             NULL, 0);
+                if (iosb.u.Status)
+                {
+                    SetLastError( RtlNtStatusToDosError(iosb.u.Status) );
+                    break;
+                }
+                if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(FIND_FIRST_INFO))))
+                {
+                    CloseHandle(h);
+                    break;
+                }
+                RtlInitializeCriticalSection( &info->cs );
+
+                /* FIXME: don't do it that way: use a static buf, and if it's too small allocate a bigger one */
+                NtQueryDirectoryFile(h, NULL, NULL, NULL, &iosb, 
+                                     NULL, 0, FileBothDirectoryInformation, 
+                                     FALSE, &umask, TRUE);
+                if (iosb.u.Status != STATUS_BUFFER_TOO_SMALL)
+                {       
+                    CloseHandle(h);
+                    SetLastError( RtlNtStatusToDosError(iosb.u.Status) );
+                    break;
+                }
+                data_size = iosb.Information;
+                info->u.nt_data = HeapAlloc(GetProcessHeap(), 0, data_size);
+
+                NtQueryDirectoryFile(h, NULL, NULL, NULL, &iosb, 
+                                     info->u.nt_data, data_size, 
+                                     FileBothDirectoryInformation, 
+                                     FALSE, &umask, TRUE);
+                CloseHandle(h);
+                if (iosb.u.Status)
+                {
+                    SetLastError( RtlNtStatusToDosError(iosb.u.Status) );
+                    break;
+                }
+                info->is_smb = FALSE;
+                info->dir_info = (PFILE_BOTH_DIR_INFORMATION)info->u.nt_data;
+            }
+            if (!FindNextFileW( (HANDLE) info, data ))
+            {
+                FindClose( (HANDLE) info );
+                SetLastError( ERROR_FILE_NOT_FOUND );
+                break;
+            }
+            return (HANDLE)info;
+        }
+        break;
+    default:
+        FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId );
+    }
+    return INVALID_HANDLE_VALUE;
+}
+
+/*************************************************************************
+ *           FindFirstFileA   (KERNEL32.@)
+ */
+HANDLE WINAPI FindFirstFileA(
+	LPCSTR lpFileName,
+	WIN32_FIND_DATAA *lpFindData )
+{
+    return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
+                            FindExSearchNameMatch, NULL, 0);
+}
+
+/*************************************************************************
+ *           FindFirstFileExA   (KERNEL32.@)
+ */
+HANDLE WINAPI FindFirstFileExA(
+	LPCSTR lpFileName,
+	FINDEX_INFO_LEVELS fInfoLevelId,
+	LPVOID lpFindFileData,
+	FINDEX_SEARCH_OPS fSearchOp,
+	LPVOID lpSearchFilter,
+	DWORD dwAdditionalFlags)
+{
+    HANDLE handle;
+    WIN32_FIND_DATAA *dataA;
+    WIN32_FIND_DATAW dataW;
+    UNICODE_STRING pathW;
+
+    if (!lpFileName)
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
+    RtlFreeUnicodeString(&pathW);
+    if (handle == INVALID_HANDLE_VALUE) return handle;
+
+    dataA = (WIN32_FIND_DATAA *) lpFindFileData;
+    dataA->dwFileAttributes = dataW.dwFileAttributes;
+    dataA->ftCreationTime   = dataW.ftCreationTime;
+    dataA->ftLastAccessTime = dataW.ftLastAccessTime;
+    dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
+    dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
+    dataA->nFileSizeLow     = dataW.nFileSizeLow;
+    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
+                         dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
+    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
+                         dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
+    return handle;
+}
+
+/*************************************************************************
+ *           FindFirstFileW   (KERNEL32.@)
+ */
+HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
+{
+    return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
+                            FindExSearchNameMatch, NULL, 0);
+}
+
+/*************************************************************************
+ *           FindNextFileW   (KERNEL32.@)
+ */
+BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
+{
+    FIND_FIRST_INFO *info;
+    BOOL ret = FALSE;
+    DWORD gle = ERROR_NO_MORE_FILES;
+
+    TRACE("(%p, %p)\n", handle, data);
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return ret;
+    }
+    info = (FIND_FIRST_INFO*) handle;
+    RtlEnterCriticalSection( &info->cs );
+    if (info->is_smb)
+    {
+        ret = SMB_FindNext( info->u.smb_dir, data );
+        if(!ret)
+        {
+            SMB_CloseDir( info->u.smb_dir );
+        }
+        goto done;
+    }
+    else if (!info->u.nt_data)
+    {
+        goto done;
+    }
+    else if (!DOSFS_FindNextEx( info, data ))
+    {
+        HeapFree(GetProcessHeap(), 0, info->u.nt_data ); info->u.nt_data = NULL;
+        goto done;
+    }
+    TRACE("=> %s %s\n", debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName));
+    ret = TRUE;
+done:
+    RtlLeaveCriticalSection( &info->cs );
+    if( !ret ) SetLastError( gle );
+    return ret;
+}
+
+
+/*************************************************************************
+ *           FindNextFileA   (KERNEL32.@)
+ */
+BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
+{
+    WIN32_FIND_DATAW dataW;
+    if (!FindNextFileW( handle, &dataW )) return FALSE;
+    data->dwFileAttributes = dataW.dwFileAttributes;
+    data->ftCreationTime   = dataW.ftCreationTime;
+    data->ftLastAccessTime = dataW.ftLastAccessTime;
+    data->ftLastWriteTime  = dataW.ftLastWriteTime;
+    data->nFileSizeHigh    = dataW.nFileSizeHigh;
+    data->nFileSizeLow     = dataW.nFileSizeLow;
+    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
+                         data->cFileName, sizeof(data->cFileName), NULL, NULL );
+    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
+                         data->cAlternateFileName,
+                         sizeof(data->cAlternateFileName), NULL, NULL );
+    return TRUE;
+}
+
+/*************************************************************************
+ *           FindClose   (KERNEL32.@)
+ */
+BOOL WINAPI FindClose( HANDLE handle )
+{
+    FIND_FIRST_INFO *info = (FIND_FIRST_INFO*) handle;
+
+    if (handle == INVALID_HANDLE_VALUE) goto error;
+
+    __TRY
+    {
+        RtlEnterCriticalSection( &info->cs );
+        if (info && info->u.nt_data)
+            HeapFree(GetProcessHeap(), 0, info->u.nt_data );
+    }
+    __EXCEPT(page_fault)
+    {
+        WARN("Illegal handle %p\n", handle);
+        SetLastError( ERROR_INVALID_HANDLE );
+        return FALSE;
+    }
+    __ENDTRY
+    if (!info) goto error;
+    RtlLeaveCriticalSection( &info->cs );
+    RtlDeleteCriticalSection( &info->cs );
+    HeapFree(GetProcessHeap(), 0, info);
+    return TRUE;
+
+ error:
+    SetLastError( ERROR_INVALID_HANDLE );
+    return FALSE;
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll46/dos_fs.c dlls/ntdll/dos_fs.c
--- dlls/ntdll46/dos_fs.c	2004-02-01 17:06:09.000000000 +0100
+++ dlls/ntdll/dos_fs.c	2004-02-01 17:06:21.000000000 +0100
@@ -60,6 +60,48 @@
 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
 
 /***********************************************************************
+ *           get_show_dir_symlinks_option
+ */
+static BOOL get_show_dir_symlinks_option(void)
+{
+    static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
+                                  'S','o','f','t','w','a','r','e','\\',
+                                  'W','i','n','e','\\','W','i','n','e','\\',
+                                  'C','o','n','f','i','g','\\','W','i','n','e',0};
+    static const WCHAR ShowDirSymlinksW[] = {'S','h','o','w','D','i','r','S','y','m','l','i','n','k','s',0};
+    static int show_dir_symlinks = -1;
+    
+    if (show_dir_symlinks == -1)
+    {
+        char tmp[80];
+        HKEY hkey;
+        DWORD dummy;
+        OBJECT_ATTRIBUTES attr;
+        UNICODE_STRING nameW;
+
+        attr.Length = sizeof(attr);
+        attr.RootDirectory = 0;
+        attr.ObjectName = &nameW;
+        attr.Attributes = 0;
+        attr.SecurityDescriptor = NULL;
+        attr.SecurityQualityOfService = NULL;
+        RtlInitUnicodeString( &nameW, WineW );
+
+        if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
+        {
+            RtlInitUnicodeString( &nameW, ShowDirSymlinksW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                show_dir_symlinks = IS_OPTION_TRUE( str[0] );
+            }
+            NtClose( hkey );
+        }
+    }
+    return show_dir_symlinks;
+}
+
+/***********************************************************************
  *           DOSFS_ValidDOSName
  *
  * Return 1 if Unix file 'name' is also a valid MS-DOS name
@@ -202,6 +244,29 @@
 }
 
 /***********************************************************************
+ *           DOSFS_ToDosDTAFormat
+ *
+ * Convert a file name from FCB to DTA format (name.ext, null-terminated)
+ * converting to upper-case in the process.
+ * File name can be terminated by '\0', '\\' or '/'.
+ * 'buffer' must be at least 13 characters long.
+ */
+static void DOSFS_ToDosDTAFormat(LPCWSTR name, LPWSTR dst)
+{
+    LPWSTR p;
+    
+    memcpy(dst, name, 8 * sizeof(WCHAR));
+    p = dst + 8;
+    while ((p > dst) && (p[-1] == ' ')) p--;
+    *p++ = '.';
+    memcpy(p, name + 8, 3 * sizeof(WCHAR));
+    p += 3;
+    while (p[-1] == ' ') p--;
+    if (p[-1] == '.') p--;
+    *p = '\0';
+}
+
+/***********************************************************************
  *           DOSFS_Hash
  *
  * Transform a Unix file name into a hashed DOS name. If the name is a valid
@@ -841,3 +906,220 @@
     }
     return status == STATUS_SUCCESS;
 }
+
+/******************************************************************
+ *		match_filename
+ *
+ * Helper for NtQueryDirectoryFile
+ */
+static BOOL match_filename(LPCWSTR mask, LPCWSTR name, BOOL case_sensitive)
+{
+    LPCWSTR lastjoker = NULL;
+    LPCWSTR next_to_retry = NULL;
+    static const WCHAR asterisk_dot_asterisk[] = {'*','.','*',0};
+    
+    TRACE("(%s, %s, %x)\n", debugstr_w(mask), debugstr_w(name), case_sensitive);
+
+    if (!strcmpW( mask, asterisk_dot_asterisk )) return TRUE;
+    while (*name && *mask)
+    {
+        if (*mask == '*')
+        {
+            while (*++mask == '*');  /* Skip consecutive '*' */
+            lastjoker = mask;
+            if (!*mask) return TRUE; /* end of mask is all '*', so match */
+
+            /* skip to the next match after the joker(s) */
+            if (case_sensitive) while (*name && (*name != *mask)) name++;
+            else while (*name && (toupperW(*name) != toupperW(*mask))) name++;
+
+            if (!*name) break;
+            next_to_retry = name;
+        }
+        else if (*mask == '?')
+        {
+            mask++;
+            name++;
+        }
+        else
+        {
+            int mismatch = 0;
+            if (case_sensitive)
+            {
+                if (*mask != *name) mismatch = 1;
+            }
+            else
+            {
+                if (toupperW(*mask) != toupperW(*name)) mismatch = 1;
+            }
+            if (!mismatch)
+            {
+                mask++;
+                name++;
+                if (*mask == '\0')
+                {
+                    if (*name == '\0') return TRUE;
+                    if (lastjoker) mask = lastjoker;
+                }
+            }
+            else /* mismatch ! */
+            {
+                if (lastjoker) /* we had an '*', so we can try unlimitedly */
+                {
+                    mask = lastjoker;
+
+                    /* this scan sequence was a mismatch, so restart
+                     * 1 char after the first char we checked last time */
+                    next_to_retry++;
+                    name = next_to_retry;
+                }
+                else return FALSE; /* bad luck */
+            }
+        }
+    }
+    while ((*mask == '.') || (*mask == '*'))
+        mask++;  /* Ignore trailing '.' or '*' in mask */
+    return (!*name && !*mask);
+}
+
+/******************************************************************************
+ *  NtQueryDirectoryFile	[NTDLL.@]
+ *  ZwQueryDirectoryFile	[NTDLL.@]
+ */
+NTSTATUS WINAPI NtQueryDirectoryFile(IN HANDLE FileHandle,
+                                     IN HANDLE Event OPTIONAL,
+                                     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+                                     IN PVOID ApcContext OPTIONAL,
+                                     OUT PIO_STATUS_BLOCK IoStatusBlock,
+                                     OUT PVOID FileInformation,
+                                     IN ULONG Length,
+                                     IN FILE_INFORMATION_CLASS FileInformationClass,
+                                     IN BOOLEAN ReturnSingleEntry,
+                                     IN PUNICODE_STRING FileName OPTIONAL,
+                                     IN BOOLEAN RestartScan)
+{
+    TRACE("(%p %p %p %p %p %p 0x%08lx 0x%08x 0x%08x %s 0x%08x\n",
+          FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation,
+          Length, FileInformationClass, ReturnSingleEntry,
+          debugstr_us(FileName),RestartScan);
+
+    if (ReturnSingleEntry || !RestartScan || Event || ApcRoutine)
+    {
+        FIXME("Unsupported yet option\n");
+        return IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+    }
+    if (FileName && FileName->Buffer[FileName->Length / sizeof(WCHAR)])
+    {
+        FIXME("Unterminated string: NIY\n");
+        return IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+    }
+        
+    IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+    IoStatusBlock->Information = 0;
+
+    switch (FileInformationClass)
+    {
+    case FileBothDirectoryInformation:
+        {
+            int         cd, fd, idx = 0, len;
+            LPCWSTR     long_name, short_name;
+            DOS_DIR*    dir;
+            PFILE_BOTH_DIR_INFORMATION lfi = NULL, 
+                fi = (FILE_BOTH_DIR_INFORMATION*)FileInformation;
+            char        name[MAX_PATH];
+            struct stat st;
+            WCHAR       shortW[13];
+            BOOL        is_link;
+
+            wine_server_handle_to_fd( FileHandle, GENERIC_READ, &fd, NULL, NULL );
+            if (fd == -1) return IoStatusBlock->u.Status = STATUS_INVALID_PARAMETER;
+
+            if ((IoStatusBlock->u.Status = DOSFS_OpenDir(fd, &dir)) != STATUS_SUCCESS)
+            {
+                WARN("Can't open dir\n");
+                wine_server_release_fd(FileHandle, fd);
+                return IoStatusBlock->u.Status;
+            }
+
+            /* FIXME: is there a better way to do lookup a directory content from its fd ??? */
+            if ((cd = open(".", O_RDONLY|O_DIRECTORY)) == -1 || fchdir(fd) == -1)
+                return IoStatusBlock->u.Status = FILE_GetNtStatus();
+
+            while ((IoStatusBlock->u.Status = DOSFS_ReadDir(dir, &long_name, &short_name)) == STATUS_SUCCESS)
+            {
+                if (short_name)
+                    DOSFS_ToDosDTAFormat(short_name, shortW);
+                else
+                    DOSFS_Hash(long_name, shortW, FALSE);
+                if (FileName && (!match_filename(FileName->Buffer, long_name, FALSE) && 
+                                 !match_filename(FileName->Buffer, shortW, FALSE)))
+                    continue;
+
+                ntdll_wcstoumbs(0, long_name, strlenW(long_name) + 1, 
+                                name, sizeof(name), NULL, NULL);
+                /* this happens, for example, on broken symlinks */
+                if (lstat(name, &st) == -1) continue;
+                is_link = S_ISLNK(st.st_mode);
+                if (stat(name, &st) == -1) continue;
+                if (S_ISDIR(st.st_mode) && is_link && get_show_dir_symlinks_option())
+                    continue;
+
+                len = strlenW(long_name) * sizeof(WCHAR);
+                if (Length >= IoStatusBlock->Information + sizeof(*fi) + len)
+                {
+                    fi->NextEntryOffset = sizeof(*fi) + len;
+                    fi->FileIndex = idx++;
+
+                    RtlSecondsSince1970ToTime( st.st_mtime, &fi->CreationTime );
+                    RtlSecondsSince1970ToTime( st.st_mtime, &fi->LastWriteTime );
+                    RtlSecondsSince1970ToTime( st.st_atime, &fi->LastAccessTime );
+                    RtlSecondsSince1970ToTime( st.st_ctime, &fi->ChangeTime );
+                    if (S_ISDIR(st.st_mode))
+                    {
+                        fi->EndOfFile.QuadPart = fi->AllocationSize.QuadPart = 0;
+                        fi->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+                    }
+                    else
+                    {
+                        fi->EndOfFile.QuadPart = st.st_size;
+                        fi->AllocationSize.QuadPart = st.st_blksize;
+                        fi->AllocationSize.QuadPart *= st.st_blocks;
+                        fi->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
+                    }
+
+                    if (!(st.st_mode & S_IWUSR))
+                        fi->FileAttributes |= FILE_ATTRIBUTE_READONLY;
+
+                    fi->EaSize = 0; /* FIXME */
+                    strcpyW(fi->ShortName, shortW);
+                    fi->ShortNameLength = strlenW(fi->ShortName) * sizeof(WCHAR);
+                    memcpy(fi->FileName, long_name, len);
+                    fi->FileNameLength = len;
+                    lfi = fi;
+                    fi = (PFILE_BOTH_DIR_INFORMATION)((char*)fi + fi->NextEntryOffset);
+                }
+                IoStatusBlock->Information += sizeof(*fi) + len;
+            }
+            if (IoStatusBlock->u.Status == STATUS_NO_MORE_ENTRIES)
+            {
+                if (Length < IoStatusBlock->Information)
+                    IoStatusBlock->u.Status = STATUS_BUFFER_TOO_SMALL;
+                else
+                {
+                    if (lfi) lfi->NextEntryOffset = 0;
+                    IoStatusBlock->u.Status = STATUS_SUCCESS;
+                }
+            }
+            DOSFS_CloseDir(dir);
+            wine_server_release_fd(FileHandle, fd);
+            fchdir(cd); /* FIXME error handling */
+            close(cd);
+        }
+        TRACE("=> %lu (%ld)\n", IoStatusBlock->u.Status, IoStatusBlock->Information);
+        return IoStatusBlock->u.Status;
+    default:
+        break;
+    }
+
+    return IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll46/file.c dlls/ntdll/file.c
--- dlls/ntdll46/file.c	2004-02-01 17:25:50.000000000 +0100
+++ dlls/ntdll/file.c	2004-02-01 18:25:38.000000000 +0100
@@ -1104,29 +1104,6 @@
     return status;
 }
 
-/******************************************************************************
- *  NtQueryDirectoryFile	[NTDLL.@]
- *  ZwQueryDirectoryFile	[NTDLL.@]
- */
-NTSTATUS WINAPI NtQueryDirectoryFile(
-	IN HANDLE FileHandle,
-	IN HANDLE Event OPTIONAL,
-	IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
-	IN PVOID ApcContext OPTIONAL,
-	OUT PIO_STATUS_BLOCK IoStatusBlock,
-	OUT PVOID FileInformation,
-	IN ULONG Length,
-	IN FILE_INFORMATION_CLASS FileInformationClass,
-	IN BOOLEAN ReturnSingleEntry,
-	IN PUNICODE_STRING FileName OPTIONAL,
-	IN BOOLEAN RestartScan)
-{
-	FIXME("(%p %p %p %p %p %p 0x%08lx 0x%08x 0x%08x %p 0x%08x\n",
-	FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation,
-	Length, FileInformationClass, ReturnSingleEntry,
-	debugstr_us(FileName),RestartScan);
-	return 0;
-}
 
 /******************************************************************************
  *  NtQueryVolumeInformationFile		[NTDLL.@]
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll46/path.c dlls/ntdll/path.c
--- dlls/ntdll46/path.c	2004-01-23 22:36:16.000000000 +0100
+++ dlls/ntdll/path.c	2004-01-23 22:38:04.000000000 +0100
@@ -469,7 +469,7 @@
         reqsize += deplen + sizeof(WCHAR);
         goto done;
     }
-    
+
     memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
     if (reqsize) memcpy(buffer, ins_str, reqsize);
     reqsize += deplen;
diff -u -N -r -x '*~' -x '.#*' -x CVS files46/dos_fs.c files/dos_fs.c
--- files46/dos_fs.c	2004-01-23 22:36:21.000000000 +0100
+++ files/dos_fs.c	2004-01-23 22:38:38.000000000 +0100
@@ -105,30 +105,6 @@
     WCHAR names[1];
 } DOS_DIR;
 
-/* Info structure for FindFirstFile handle */
-typedef struct
-{
-    char *path; /* unix path */
-    LPWSTR long_mask;
-    int   drive;
-    int   cur_pos;
-    CRITICAL_SECTION cs;
-    union
-    {
-        DOS_DIR *dos_dir;
-        SMB_DIR *smb_dir;
-    } u;
-} FIND_FIRST_INFO;
-
-
-static WINE_EXCEPTION_FILTER(page_fault)
-{
-    if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
-        return EXCEPTION_EXECUTE_HANDLER;
-    return EXCEPTION_CONTINUE_SEARCH;
-}
-
-
 /***********************************************************************
  *           DOSFS_ValidDOSName
  *
@@ -298,97 +274,6 @@
 
 
 /***********************************************************************
- *           DOSFS_MatchLong
- *
- * Check a long file name against a mask.
- *
- * Tests (done in W95 DOS shell - case insensitive):
- * *.txt			test1.test.txt				*
- * *st1*			test1.txt				*
- * *.t??????.t*			test1.ta.tornado.txt			*
- * *tornado*			test1.ta.tornado.txt			*
- * t*t				test1.ta.tornado.txt			*
- * ?est*			test1.txt				*
- * ?est???			test1.txt				-
- * *test1.txt*			test1.txt				*
- * h?l?o*t.dat			hellothisisatest.dat			*
- */
-static int DOSFS_MatchLong( LPCWSTR mask, LPCWSTR name, int case_sensitive )
-{
-    LPCWSTR lastjoker = NULL;
-    LPCWSTR next_to_retry = NULL;
-    static const WCHAR asterisk_dot_asterisk[] = {'*','.','*',0};
-
-    TRACE("(%s, %s, %x)\n", debugstr_w(mask), debugstr_w(name), case_sensitive);
-
-    if (!strcmpW( mask, asterisk_dot_asterisk )) return 1;
-    while (*name && *mask)
-    {
-        if (*mask == '*')
-        {
-            mask++;
-            while (*mask == '*') mask++;  /* Skip consecutive '*' */
-            lastjoker = mask;
-            if (!*mask) return 1; /* end of mask is all '*', so match */
-
-            /* skip to the next match after the joker(s) */
-            if (case_sensitive) while (*name && (*name != *mask)) name++;
-            else while (*name && (toupperW(*name) != toupperW(*mask))) name++;
-
-            if (!*name) break;
-            next_to_retry = name;
-        }
-        else if (*mask != '?')
-        {
-            int mismatch = 0;
-            if (case_sensitive)
-            {
-                if (*mask != *name) mismatch = 1;
-            }
-            else
-            {
-                if (toupperW(*mask) != toupperW(*name)) mismatch = 1;
-            }
-            if (!mismatch)
-            {
-                mask++;
-                name++;
-                if (*mask == '\0')
-                {
-                    if (*name == '\0')
-                        return 1;
-                    if (lastjoker)
-                        mask = lastjoker;
-                }
-            }
-            else /* mismatch ! */
-            {
-                if (lastjoker) /* we had an '*', so we can try unlimitedly */
-                {
-                    mask = lastjoker;
-
-                    /* this scan sequence was a mismatch, so restart
-                     * 1 char after the first char we checked last time */
-                    next_to_retry++;
-                    name = next_to_retry;
-                }
-                else
-                    return 0; /* bad luck */
-            }
-        }
-        else /* '?' */
-        {
-            mask++;
-            name++;
-        }
-    }
-    while ((*mask == '.') || (*mask == '*'))
-        mask++;  /* Ignore trailing '.' or '*' in mask */
-    return (!*name && !*mask);
-}
-
-
-/***********************************************************************
  *           DOSFS_AddDirEntry
  *
  *  Used to construct an array of filenames in DOSFS_OpenDir
@@ -957,389 +842,6 @@
 
 
 /***********************************************************************
- *           get_show_dir_symlinks_option
- */
-static BOOL get_show_dir_symlinks_option(void)
-{
-    static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
-                                  'S','o','f','t','w','a','r','e','\\',
-                                  'W','i','n','e','\\','W','i','n','e','\\',
-                                  'C','o','n','f','i','g','\\','W','i','n','e',0};
-    static const WCHAR ShowDirSymlinksW[] = {'S','h','o','w','D','i','r','S','y','m','l','i','n','k','s',0};
-
-    char tmp[80];
-    HKEY hkey;
-    DWORD dummy;
-    OBJECT_ATTRIBUTES attr;
-    UNICODE_STRING nameW;
-    BOOL ret = FALSE;
-
-    attr.Length = sizeof(attr);
-    attr.RootDirectory = 0;
-    attr.ObjectName = &nameW;
-    attr.Attributes = 0;
-    attr.SecurityDescriptor = NULL;
-    attr.SecurityQualityOfService = NULL;
-    RtlInitUnicodeString( &nameW, WineW );
-
-    if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
-    {
-        RtlInitUnicodeString( &nameW, ShowDirSymlinksW );
-        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
-        {
-            WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
-            ret = IS_OPTION_TRUE( str[0] );
-        }
-        NtClose( hkey );
-    }
-    return ret;
-}
-
-
-/***********************************************************************
- *           DOSFS_FindNextEx
- */
-static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
-{
-    UINT flags = DRIVE_GetFlags( info->drive );
-    char *p, buffer[MAX_PATHNAME_LEN];
-    const char *drive_path;
-    int drive_root;
-    LPCWSTR long_name, short_name;
-    BY_HANDLE_FILE_INFORMATION fileinfo;
-    BOOL is_symlink;
-
-    drive_path = info->path + strlen(DRIVE_GetRoot( info->drive ));
-    while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++;
-    drive_root = !*drive_path;
-
-    lstrcpynA( buffer, info->path, sizeof(buffer) - 1 );
-    strcat( buffer, "/" );
-    p = buffer + strlen(buffer);
-
-    while (DOSFS_ReadDir( info->u.dos_dir, &long_name, &short_name ))
-    {
-        info->cur_pos++;
-
-        /* Don't return '.' and '..' in the root of the drive */
-        if (drive_root && (long_name[0] == '.') &&
-            (!long_name[1] || ((long_name[1] == '.') && !long_name[2])))
-            continue;
-
-        /* Check the long mask */
-
-        if (info->long_mask && *info->long_mask)
-        {
-            if (!DOSFS_MatchLong( info->long_mask, long_name,
-                                  flags & DRIVE_CASE_SENSITIVE )) continue;
-        }
-
-        /* Check the file attributes */
-        WideCharToMultiByte(CP_UNIXCP, 0, long_name, -1,
-                            p, sizeof(buffer) - (int)(p - buffer), NULL, NULL);
-        if (!FILE_Stat( buffer, &fileinfo, &is_symlink ))
-        {
-            WARN("can't stat %s\n", buffer);
-            continue;
-        }
-        if (is_symlink && (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
-        {
-            static int show_dir_symlinks = -1;
-            if (show_dir_symlinks == -1)
-                show_dir_symlinks = get_show_dir_symlinks_option();
-            if (!show_dir_symlinks) continue;
-        }
-
-        /* We now have a matching entry; fill the result and return */
-
-        entry->dwFileAttributes = fileinfo.dwFileAttributes;
-        entry->ftCreationTime   = fileinfo.ftCreationTime;
-        entry->ftLastAccessTime = fileinfo.ftLastAccessTime;
-        entry->ftLastWriteTime  = fileinfo.ftLastWriteTime;
-        entry->nFileSizeHigh    = fileinfo.nFileSizeHigh;
-        entry->nFileSizeLow     = fileinfo.nFileSizeLow;
-
-        if (short_name)
-            DOSFS_ToDosDTAFormat( short_name, entry->cAlternateFileName );
-        else
-            DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE,
-                        !(flags & DRIVE_CASE_SENSITIVE) );
-
-        lstrcpynW( entry->cFileName, long_name, sizeof(entry->cFileName)/sizeof(entry->cFileName[0]) );
-        if (!(flags & DRIVE_CASE_PRESERVING)) strlwrW( entry->cFileName );
-        TRACE("returning %s (%s) %02lx %ld\n",
-              debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName),
-              entry->dwFileAttributes, entry->nFileSizeLow );
-        return 1;
-    }
-    return 0;  /* End of directory */
-}
-
-/*************************************************************************
- *           FindFirstFileExW  (KERNEL32.@)
- */
-HANDLE WINAPI FindFirstFileExW(
-	LPCWSTR lpFileName,
-	FINDEX_INFO_LEVELS fInfoLevelId,
-	LPVOID lpFindFileData,
-	FINDEX_SEARCH_OPS fSearchOp,
-	LPVOID lpSearchFilter,
-	DWORD dwAdditionalFlags)
-{
-    FIND_FIRST_INFO *info;
-
-    if (!lpFileName)
-    {
-        SetLastError(ERROR_PATH_NOT_FOUND);
-        return INVALID_HANDLE_VALUE;
-    }
-
-    if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0))
-    {
-        FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags );
-        return INVALID_HANDLE_VALUE;
-    }
-
-    switch(fInfoLevelId)
-    {
-      case FindExInfoStandard:
-        {
-          WIN32_FIND_DATAW * data = (WIN32_FIND_DATAW *) lpFindFileData;
-          char *p;
-          INT long_mask_len;
-
-          data->dwReserved0 = data->dwReserved1 = 0x0;
-          if (lpFileName[0] == '\\' && lpFileName[1] == '\\')
-          {
-              ERR("UNC path name\n");
-              if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(FIND_FIRST_INFO)))) break;
-              info->u.smb_dir = SMB_FindFirst(lpFileName);
-              if(!info->u.smb_dir)
-              {
-                 HeapFree(GetProcessHeap(), 0, info);
-                 break;
-              }
-              info->drive = -1;
-              RtlInitializeCriticalSection( &info->cs );
-          }
-          else
-          {
-            DOS_FULL_NAME full_name;
-
-            if (lpFileName[0] && lpFileName[1] == ':')
-            {
-                /* don't allow root directories */
-                if (!lpFileName[2] ||
-                    ((lpFileName[2] == '/' || lpFileName[2] == '\\') && !lpFileName[3]))
-                {
-                    SetLastError(ERROR_FILE_NOT_FOUND);
-                    return INVALID_HANDLE_VALUE;
-                }
-            }
-            if (!DOSFS_GetFullName( lpFileName, FALSE, &full_name )) break;
-            if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(FIND_FIRST_INFO)))) break;
-            RtlInitializeCriticalSection( &info->cs );
-            info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
-            strcpy( info->path, full_name.long_name );
-
-            p = strrchr( info->path, '/' );
-            *p++ = '\0';
-            long_mask_len = MultiByteToWideChar(CP_UNIXCP, 0, p, -1, NULL, 0);
-            info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) );
-            MultiByteToWideChar(CP_UNIXCP, 0, p, -1, info->long_mask, long_mask_len);
-
-            info->drive = full_name.drive;
-            info->cur_pos = 0;
-
-            info->u.dos_dir = DOSFS_OpenDir( info->path );
-          }
-          if (!FindNextFileW( (HANDLE) info, data ))
-          {
-              FindClose( (HANDLE) info );
-              SetLastError( ERROR_FILE_NOT_FOUND );
-              break;
-          }
-          return (HANDLE) info;
-        }
-        break;
-      default:
-        FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId );
-    }
-    return INVALID_HANDLE_VALUE;
-}
-
-/*************************************************************************
- *           FindFirstFileA   (KERNEL32.@)
- */
-HANDLE WINAPI FindFirstFileA(
-	LPCSTR lpFileName,
-	WIN32_FIND_DATAA *lpFindData )
-{
-    return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
-                            FindExSearchNameMatch, NULL, 0);
-}
-
-/*************************************************************************
- *           FindFirstFileExA   (KERNEL32.@)
- */
-HANDLE WINAPI FindFirstFileExA(
-	LPCSTR lpFileName,
-	FINDEX_INFO_LEVELS fInfoLevelId,
-	LPVOID lpFindFileData,
-	FINDEX_SEARCH_OPS fSearchOp,
-	LPVOID lpSearchFilter,
-	DWORD dwAdditionalFlags)
-{
-    HANDLE handle;
-    WIN32_FIND_DATAA *dataA;
-    WIN32_FIND_DATAW dataW;
-    UNICODE_STRING pathW;
-
-    if (!lpFileName)
-    {
-        SetLastError(ERROR_PATH_NOT_FOUND);
-        return INVALID_HANDLE_VALUE;
-    }
-
-    if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return INVALID_HANDLE_VALUE;
-    }
-
-    handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
-    RtlFreeUnicodeString(&pathW);
-    if (handle == INVALID_HANDLE_VALUE) return handle;
-
-    dataA = (WIN32_FIND_DATAA *) lpFindFileData;
-    dataA->dwFileAttributes = dataW.dwFileAttributes;
-    dataA->ftCreationTime   = dataW.ftCreationTime;
-    dataA->ftLastAccessTime = dataW.ftLastAccessTime;
-    dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
-    dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
-    dataA->nFileSizeLow     = dataW.nFileSizeLow;
-    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
-                         dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
-    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
-                         dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
-    return handle;
-}
-
-/*************************************************************************
- *           FindFirstFileW   (KERNEL32.@)
- */
-HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
-{
-    return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
-                            FindExSearchNameMatch, NULL, 0);
-}
-
-/*************************************************************************
- *           FindNextFileW   (KERNEL32.@)
- */
-BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
-{
-    FIND_FIRST_INFO *info;
-    BOOL ret = FALSE;
-    DWORD gle = ERROR_NO_MORE_FILES;
-
-    if (handle == INVALID_HANDLE_VALUE)
-    {
-        SetLastError( ERROR_INVALID_HANDLE );
-        return ret;
-    }
-    info = (FIND_FIRST_INFO*) handle;
-    RtlEnterCriticalSection( &info->cs );
-    if (info->drive == -1)
-    {
-        ret = SMB_FindNext( info->u.smb_dir, data );
-        if(!ret)
-        {
-            SMB_CloseDir( info->u.smb_dir );
-            HeapFree( GetProcessHeap(), 0, info->path );
-        }
-        goto done;
-    }
-    else if (!info->path || !info->u.dos_dir)
-    {
-        goto done;
-    }
-    else if (!DOSFS_FindNextEx( info, data ))
-    {
-        DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL;
-        HeapFree( GetProcessHeap(), 0, info->path );
-        info->path = NULL;
-        HeapFree( GetProcessHeap(), 0, info->long_mask );
-        info->long_mask = NULL;
-        goto done;
-    }
-    ret = TRUE;
-done:
-    RtlLeaveCriticalSection( &info->cs );
-    if( !ret ) SetLastError( gle );
-    return ret;
-}
-
-
-/*************************************************************************
- *           FindNextFileA   (KERNEL32.@)
- */
-BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
-{
-    WIN32_FIND_DATAW dataW;
-    if (!FindNextFileW( handle, &dataW )) return FALSE;
-    data->dwFileAttributes = dataW.dwFileAttributes;
-    data->ftCreationTime   = dataW.ftCreationTime;
-    data->ftLastAccessTime = dataW.ftLastAccessTime;
-    data->ftLastWriteTime  = dataW.ftLastWriteTime;
-    data->nFileSizeHigh    = dataW.nFileSizeHigh;
-    data->nFileSizeLow     = dataW.nFileSizeLow;
-    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
-                         data->cFileName, sizeof(data->cFileName), NULL, NULL );
-    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
-                         data->cAlternateFileName,
-                         sizeof(data->cAlternateFileName), NULL, NULL );
-    return TRUE;
-}
-
-/*************************************************************************
- *           FindClose   (KERNEL32.@)
- */
-BOOL WINAPI FindClose( HANDLE handle )
-{
-    FIND_FIRST_INFO *info = (FIND_FIRST_INFO*) handle;
-
-    if (handle == INVALID_HANDLE_VALUE) goto error;
-
-    __TRY
-    {
-        RtlEnterCriticalSection( &info->cs );
-        if (info)
-        {
-            if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir );
-            if (info->path) HeapFree( GetProcessHeap(), 0, info->path );
-            if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask );
-        }
-    }
-    __EXCEPT(page_fault)
-    {
-        WARN("Illegal handle %p\n", handle);
-        SetLastError( ERROR_INVALID_HANDLE );
-        return FALSE;
-    }
-    __ENDTRY
-    if (!info) goto error;
-    RtlLeaveCriticalSection( &info->cs );
-    RtlDeleteCriticalSection( &info->cs );
-    HeapFree(GetProcessHeap(), 0, info);
-    return TRUE;
-
- error:
-    SetLastError( ERROR_INVALID_HANDLE );
-    return FALSE;
-}
-
-/***********************************************************************
  *           MulDiv   (KERNEL32.@)
  * RETURNS
  *	Result of multiplication and division
diff -u -N -r -x '*~' -x '.#*' -x CVS include46/winternl.h include/winternl.h
--- include46/winternl.h	2004-01-21 21:37:39.000000000 +0100
+++ include/winternl.h	2004-01-21 21:48:53.000000000 +0100
@@ -243,6 +243,54 @@
     FileMaximumInformation
 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
 
+typedef struct _FILE_DIRECTORY_INFORMATION {
+    ULONG               NextEntryOffset;
+    ULONG               FileIndex;
+    LARGE_INTEGER       CreationTime;
+    LARGE_INTEGER       LastAccessTime;
+    LARGE_INTEGER       LastWriteTime;
+    LARGE_INTEGER       ChangeTime;
+    LARGE_INTEGER       EndOfFile;
+    LARGE_INTEGER       AllocationSize;
+    ULONG               FileAttributes;
+    ULONG               FileNameLength;
+    WCHAR               FileName[0];
+} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
+
+typedef struct _FILE_FULL_DIRECTORY_INFORMATION {
+    ULONG               NextEntryOffset;
+    ULONG               FileIndex;
+    LARGE_INTEGER       CreationTime;
+    LARGE_INTEGER       LastAccessTime;
+    LARGE_INTEGER       LastWriteTime;
+    LARGE_INTEGER       ChangeTime;
+    LARGE_INTEGER       EndOfFile;
+    LARGE_INTEGER       AllocationSize;
+    ULONG               FileAttributes;
+    ULONG               FileNameLength;
+    ULONG               EaSize;
+    WCHAR               FileName[0];
+} FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION,
+  FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
+
+typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
+    ULONG               NextEntryOffset;
+    ULONG               FileIndex;
+    LARGE_INTEGER       CreationTime;
+    LARGE_INTEGER       LastAccessTime;
+    LARGE_INTEGER       LastWriteTime;
+    LARGE_INTEGER       ChangeTime;
+    LARGE_INTEGER       EndOfFile;
+    LARGE_INTEGER       AllocationSize;
+    ULONG               FileAttributes;
+    ULONG               FileNameLength;
+    ULONG               EaSize;
+    CHAR                ShortNameLength;
+    WCHAR               ShortName[12];
+    WCHAR               FileName[0];
+} FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION,
+  FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
+
 typedef struct _FILE_BASIC_INFORMATION {
     LARGE_INTEGER CreationTime;
     LARGE_INTEGER LastAccessTime;
@@ -1046,6 +1094,7 @@
 NTSTATUS  WINAPI NtPulseEvent(HANDLE,PULONG);
 NTSTATUS  WINAPI NtQueueApcThread(HANDLE,PNTAPCFUNC,ULONG_PTR,ULONG_PTR,ULONG_PTR);
 NTSTATUS  WINAPI NtQueryDefaultLocale(BOOLEAN,LCID*);
+NTSTATUS  WINAPI NtQueryDirectoryFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
 NTSTATUS  WINAPI NtQueryInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,LONG,FILE_INFORMATION_CLASS);
 NTSTATUS  WINAPI NtQueryInformationProcess(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
 NTSTATUS  WINAPI NtQueryInformationThread(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);


More information about the wine-patches mailing list