Ignore:
Timestamp:
Sep 14, 2010, 2:30:30 AM (15 years ago)
Author:
bird
Message:

kash: implemented opendir/readdir/closedir for windows (NT). Fixed windows forking.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kash/shfile.c

    r2413 r2416  
    3939#  define PIPE_BUF 512
    4040# endif
     41# include <ntstatus.h>
     42# define WIN32_NO_STATUS
    4143# include <Windows.h>
     44# if !defined(_WIN32_WINNT)
     45#  define _WIN32_WINNT 0x0502 /* Windows Server 2003 */
     46# endif
     47# include <winternl.h> //NTSTATUS
    4248#else
    4349# include <unistd.h>
     
    8692
    8793# define MY_ObjectBasicInformation 0
    88 typedef LONG (NTAPI * PFN_NtQueryObject)(HANDLE, int, void *, size_t, size_t *);
    89 
    90 typedef struct MY_OBJECT_BASIC_INFORMATION
     94# define MY_FileNamesInformation 12
     95
     96typedef struct
    9197{
    9298    ULONG           Attributes;
     
    103109} MY_OBJECT_BASIC_INFORMATION;
    104110
     111#if 0
     112typedef struct
     113{
     114    union
     115    {
     116        LONG    Status;
     117        PVOID   Pointer;
     118    };
     119    ULONG_PTR   Information;
     120} MY_IO_STATUS_BLOCK;
     121#else
     122typedef IO_STATUS_BLOCK MY_IO_STATUS_BLOCK;
     123#endif
     124typedef MY_IO_STATUS_BLOCK *PMY_IO_STATUS_BLOCK;
     125
     126typedef struct
     127{
     128    ULONG   NextEntryOffset;
     129    ULONG   FileIndex;
     130    ULONG   FileNameLength;
     131    WCHAR   FileName[1];
     132} MY_FILE_NAMES_INFORMATION, *PMY_FILE_NAMES_INFORMATION;
     133
     134typedef NTSTATUS (NTAPI * PFN_NtQueryObject)(HANDLE, int, void *, size_t, size_t *);
     135typedef NTSTATUS (NTAPI * PFN_NtQueryDirectoryFile)(HANDLE, HANDLE, void *,  void *, PMY_IO_STATUS_BLOCK, void *,
     136                                                    ULONG, int, int, PUNICODE_STRING, int);
     137typedef NTSTATUS (NTAPI * PFN_RtlUnicodeStringToAnsiString)(PANSI_STRING, PCUNICODE_STRING, int);
     138
     139
     140#endif /* K_OS_WINDOWS */
     141
     142
     143/*******************************************************************************
     144*   Global Variables                                                           *
     145*******************************************************************************/
     146#if K_OS == K_OS_WINDOWS
     147static int                              g_shfile_globals_initialized = 0;
     148static PFN_NtQueryObject                g_pfnNtQueryObject = NULL;
     149static PFN_NtQueryDirectoryFile         g_pfnNtQueryDirectoryFile = NULL;
     150static PFN_RtlUnicodeStringToAnsiString g_pfnRtlUnicodeStringToAnsiString = NULL;
    105151#endif /* K_OS_WINDOWS */
    106152
     
    387433}
    388434
     435/**
     436 * Converts an NT status code to errno,
     437 * assigning it to errno.
     438 *
     439 * @returns -1
     440 * @param   rcNt        The NT status code.
     441 */
     442static int shfile_nt2errno(NTSTATUS rcNt)
     443{
     444    switch (rcNt)
     445    {
     446        default:                            errno = EINVAL; break;
     447    }
     448    return -1;
     449}
     450
    389451DWORD shfile_query_handle_access_mask(HANDLE h, PACCESS_MASK pMask)
    390452{
    391     static PFN_NtQueryObject        s_pfnNtQueryObject = NULL;
    392453    MY_OBJECT_BASIC_INFORMATION     BasicInfo;
    393     LONG                            Status;
    394 
    395     if (!s_pfnNtQueryObject)
    396     {
    397         s_pfnNtQueryObject = (PFN_NtQueryObject)GetProcAddress(GetModuleHandle("NTDLL"), "NtQueryObject");
    398         if (!s_pfnNtQueryObject)
    399             return ERROR_NOT_SUPPORTED;
    400     }
    401 
    402     Status = s_pfnNtQueryObject(h, MY_ObjectBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
    403     if (Status >= 0)
     454    NTSTATUS                        rcNt;
     455
     456    if (!g_pfnNtQueryObject)
     457        return ERROR_NOT_SUPPORTED;
     458
     459    rcNt = g_pfnNtQueryObject(h, MY_ObjectBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
     460    if (rcNt >= 0)
    404461    {
    405462        *pMask = BasicInfo.GrantedAccess;
    406463        return NO_ERROR;
    407464    }
    408     if (Status != STATUS_INVALID_HANDLE)
     465    if (rcNt != STATUS_INVALID_HANDLE)
    409466        return ERROR_GEN_FAILURE;
    410467    return ERROR_INVALID_HANDLE;
     
    414471
    415472#endif /* SHFILE_IN_USE */
     473
     474/**
     475 * Initializes the global variables in this file.
     476 */
     477static void shfile_init_globals(void)
     478{
     479#if K_OS == K_OS_WINDOWS
     480    if (!g_shfile_globals_initialized)
     481    {
     482        HMODULE hNtDll = GetModuleHandle("NTDLL");
     483        g_pfnNtQueryObject                = (PFN_NtQueryObject)       GetProcAddress(hNtDll, "NtQueryObject");
     484        g_pfnNtQueryDirectoryFile         = (PFN_NtQueryDirectoryFile)GetProcAddress(hNtDll, "NtQueryDirectoryFile");
     485        g_pfnRtlUnicodeStringToAnsiString = (PFN_RtlUnicodeStringToAnsiString)GetProcAddress(hNtDll, "RtlUnicodeStringToAnsiString");
     486        if (   !g_pfnRtlUnicodeStringToAnsiString
     487            || !g_pfnNtQueryDirectoryFile)
     488        {
     489            /* fatal error */
     490        }
     491        g_shfile_globals_initialized = 1;
     492    }
     493#endif
     494}
    416495
    417496/**
     
    426505{
    427506    int rc;
     507
     508    shfile_init_globals();
    428509
    429510    pfdtab->cwd  = NULL;
     
    14171498
    14181499
     1500
    14191501shdir *shfile_opendir(shfdtab *pfdtab, const char *dir)
    14201502{
    14211503#ifdef SHFILE_IN_USE
    1422     errno = ENOSYS;
    1423     return NULL;
     1504    shdir  *pdir = NULL;
     1505
     1506    if (g_pfnNtQueryDirectoryFile)
     1507    {
     1508        char abspath[SHFILE_MAX_PATH];
     1509        if (shfile_make_path(pfdtab, dir, &abspath[0]) == 0)
     1510        {
     1511            HANDLE              hFile;
     1512            SECURITY_ATTRIBUTES SecurityAttributes;
     1513
     1514            SecurityAttributes.nLength = sizeof(SecurityAttributes);
     1515            SecurityAttributes.lpSecurityDescriptor = NULL;
     1516            SecurityAttributes.bInheritHandle = FALSE;
     1517
     1518            hFile = CreateFileA(abspath,
     1519                                GENERIC_READ,
     1520                                FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
     1521                                &SecurityAttributes,
     1522                                OPEN_ALWAYS,
     1523                                FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_BACKUP_SEMANTICS,
     1524                                NULL /* hTemplateFile */);
     1525            if (hFile != INVALID_HANDLE_VALUE)
     1526            {
     1527                pdir = (shdir *)sh_malloc(shthread_get_shell(), sizeof(*pdir));
     1528                if (pdir)
     1529                {
     1530                    pdir->pfdtab = pfdtab;
     1531                    pdir->native = hFile;
     1532                    pdir->off    = ~(size_t)0;
     1533                }
     1534                else
     1535                    CloseHandle(hFile);
     1536            }
     1537            else
     1538                shfile_dos2errno(GetLastError());
     1539        }
     1540    }
     1541    else
     1542        errno = ENOSYS;
     1543    return pdir;
    14241544#else
    14251545    return (shdir *)opendir(dir);
     
    14301550{
    14311551#ifdef SHFILE_IN_USE
    1432     errno = ENOSYS;
     1552    if (pdir)
     1553    {
     1554        NTSTATUS rcNt;
     1555
     1556        if (   pdir->off == ~(size_t)0
     1557            || pdir->off + sizeof(MY_FILE_NAMES_INFORMATION) >= pdir->cb)
     1558        {
     1559            MY_IO_STATUS_BLOCK Ios;
     1560
     1561            memset(&Ios, 0, sizeof(Ios));
     1562            rcNt = g_pfnNtQueryDirectoryFile(pdir->native,
     1563                                             NULL /*Event*/,
     1564                                             NULL /*ApcRoutine*/,
     1565                                             NULL /*ApcContext*/,
     1566                                             &Ios,
     1567                                             &pdir->buf[0],
     1568                                             sizeof(pdir->buf),
     1569                                             MY_FileNamesInformation,
     1570                                             FALSE /*ReturnSingleEntry*/,
     1571                                             NULL /*FileName*/,
     1572                                             pdir->off == ~(size_t)0 /*RestartScan*/);
     1573            if (rcNt >= 0 && rcNt != STATUS_PENDING)
     1574            {
     1575                pdir->cb  = Ios.Information;
     1576                pdir->off = 0;
     1577            }
     1578            else if (rcNt == STATUS_NO_MORE_FILES)
     1579                errno = 0; /* wrong? */
     1580            else
     1581                shfile_nt2errno(rcNt);
     1582        }
     1583
     1584        if (   pdir->off != ~(size_t)0
     1585            && pdir->off + sizeof(MY_FILE_NAMES_INFORMATION) <= pdir->cb)
     1586        {
     1587            PMY_FILE_NAMES_INFORMATION  pcur = (PMY_FILE_NAMES_INFORMATION)&pdir->buf[pdir->off];
     1588            ANSI_STRING                 astr;
     1589            UNICODE_STRING              ustr;
     1590
     1591            astr.Length = astr.MaximumLength = sizeof(pdir->ent.name);
     1592            astr.Buffer = &pdir->ent.name[0];
     1593
     1594            ustr.Length = ustr.MaximumLength = pcur->FileNameLength < ~(USHORT)0 ? (USHORT)pcur->FileNameLength : ~(USHORT)0;
     1595            ustr.Buffer = &pcur->FileName[0];
     1596
     1597            rcNt = g_pfnRtlUnicodeStringToAnsiString(&astr, &ustr, 0/*AllocateDestinationString*/);
     1598            if (rcNt < 0)
     1599                sprintf(pdir->ent.name, "conversion-failed-%08x-rcNt=%08x-len=%u",
     1600                        pcur->FileIndex, rcNt, pcur->FileNameLength);
     1601            if (pcur->NextEntryOffset)
     1602                pdir->off += pcur->NextEntryOffset;
     1603            else
     1604                pdir->off = pdir->cb;
     1605            return &pdir->ent;
     1606        }
     1607    }
     1608    else
     1609        errno = EINVAL;
    14331610    return NULL;
    14341611#else
     
    14411618{
    14421619#ifdef SHFILE_IN_USE
    1443     errno = ENOSYS;
     1620    if (pdir)
     1621    {
     1622        CloseHandle(pdir->native);
     1623        pdir->pfdtab = NULL;
     1624        pdir->native = INVALID_HANDLE_VALUE;
     1625        sh_free(shthread_get_shell(), pdir);
     1626    }
     1627    else
     1628        errno = EINVAL;
    14441629#else
    14451630    closedir((DIR *)pdir);
Note: See TracChangeset for help on using the changeset viewer.