Ignore:
Timestamp:
Nov 6, 2016, 5:46:43 PM (9 years ago)
Author:
bird
Message:

lib/nt: Deal better with NTFS mount points.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/lib/nt/ntstat.c

    r3003 r3007  
    148148
    149149
    150 static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
    151                                          const wchar_t *pwszName, size_t cbNameW, __int16 *pfIsDirSymlink)
     150static unsigned short birdFileInfoToMode(ULONG fAttribs, ULONG uReparseTag,
     151                                         const char *pszName, const wchar_t *pwszName, size_t cbNameW,
     152                                         unsigned __int8 *pfIsDirSymlink, unsigned __int8 *pfIsMountPoint)
    152153{
    153154    unsigned short fMode;
    154155
    155156    /* File type. */
    156     if (  (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
    157         && hFile != INVALID_HANDLE_VALUE)
    158     {
    159         MY_FILE_ATTRIBUTE_TAG_INFORMATION   TagInfo;
    160         MY_IO_STATUS_BLOCK                  Ios;
    161         MY_NTSTATUS                         rcNt;
    162         Ios.Information = 0;
    163         Ios.u.Status    = -1;
    164         rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
    165         if (   !MY_NT_SUCCESS(rcNt)
    166             || !MY_NT_SUCCESS(Ios.u.Status)
    167             || TagInfo.ReparseTag != IO_REPARSE_TAG_SYMLINK)
    168             fAttribs &= ~FILE_ATTRIBUTE_REPARSE_POINT;
    169     }
    170 
    171     if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
    172     {
    173         *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
    174         fMode = S_IFLNK;
    175     }
    176     else
    177     {
    178         *pfIsDirSymlink = 0;
     157    *pfIsDirSymlink = 0;
     158    *pfIsMountPoint = 0;
     159    if (!(fAttribs & FILE_ATTRIBUTE_REPARSE_POINT))
     160    {
    179161        if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
    180162            fMode = S_IFDIR;
    181163        else
    182164            fMode = S_IFREG;
     165    }
     166    else
     167    {
     168        switch (uReparseTag)
     169        {
     170            case IO_REPARSE_TAG_SYMLINK:
     171                *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
     172                fMode = S_IFLNK;
     173                break;
     174
     175            case IO_REPARSE_TAG_MOUNT_POINT:
     176                *pfIsMountPoint = 1;
     177            default:
     178                if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
     179                    fMode = S_IFDIR;
     180                else
     181                    fMode = S_IFREG;
     182                break;
     183        }
    183184    }
    184185
     
    202203 * @param   pStat               The stat structure.
    203204 * @param   pBuf                The MY_FILE_ID_FULL_DIR_INFORMATION entry.
    204  * @param   pszPath             Optionally, the path for X bit checks.
    205205 * @remarks Caller sets st_dev.
    206206 */
    207 void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
    208 {
    209     pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
    210                                                  pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
     207void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf)
     208{
     209    pStat->st_mode          = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName,
     210                                                 pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint);
    211211    pStat->st_padding0[0]   = 0;
    212212    pStat->st_padding0[1]   = 0;
     
    234234 * @param   pStat               The stat structure.
    235235 * @param   pBuf                The MY_FILE_ID_BOTH_DIR_INFORMATION entry.
    236  * @param   pszPath             Optionally, the path for X bit checks.
    237236 * @remarks Caller sets st_dev.
    238237 */
    239 void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
    240 {
    241     pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
    242                                                  pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
     238void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf)
     239{
     240    pStat->st_mode          = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName,
     241                                                 pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint);
    243242    pStat->st_padding0[0]   = 0;
    244243    pStat->st_padding0[1]   = 0;
     
    266265 * @param   pStat               The stat structure.
    267266 * @param   pBuf                The MY_FILE_BOTH_DIR_INFORMATION entry.
    268  * @param   pszPath             Optionally, the path for X bit checks.
    269267 * @remarks Caller sets st_dev.
    270268 */
    271 void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
    272 {
    273     pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
    274                                                  pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
     269void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf)
     270{
     271    pStat->st_mode          = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName,
     272                                                 pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint);
    275273    pStat->st_padding0[0]   = 0;
    276274    pStat->st_padding0[1]   = 0;
     
    310308        if (MY_NT_SUCCESS(rcNt))
    311309        {
    312             pStat->st_mode          = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
     310            pStat->st_mode          = birdFileInfoToMode(pAll->BasicInformation.FileAttributes, pszPath,
    313311                                                         pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength,
    314                                                          &pStat->st_dirsymlink);
     312                                                         hFile, &pStat->st_isdirsymlink, &pStat->st_ismountpoint);
    315313            pStat->st_padding0[0]   = 0;
    316314            pStat->st_padding0[1]   = 0;
     
    354352        rc = birdSetErrnoToNoMem();
    355353#else
    356     ULONG                           cbNameInfo = 0;
    357     MY_FILE_NAME_INFORMATION       *pNameInfo  = NULL;
    358     MY_FILE_STANDARD_INFORMATION    StdInfo;
    359     MY_FILE_BASIC_INFORMATION       BasicInfo;
    360     MY_FILE_INTERNAL_INFORMATION    InternalInfo;
    361     MY_IO_STATUS_BLOCK              Ios;
     354    ULONG                               cbNameInfo = 0;
     355    MY_FILE_NAME_INFORMATION           *pNameInfo  = NULL;
     356    MY_FILE_STANDARD_INFORMATION        StdInfo;
     357    MY_FILE_BASIC_INFORMATION           BasicInfo;
     358    MY_FILE_INTERNAL_INFORMATION        InternalInfo;
     359    MY_FILE_ATTRIBUTE_TAG_INFORMATION   TagInfo;
     360    MY_IO_STATUS_BLOCK                  Ios;
    362361
    363362    Ios.Information = 0;
     
    366365    if (MY_NT_SUCCESS(rcNt))
    367366        rcNt = Ios.u.Status;
     367
    368368    if (MY_NT_SUCCESS(rcNt))
    369369        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
    370370    if (MY_NT_SUCCESS(rcNt))
    371371        rcNt = Ios.u.Status;
     372
    372373    if (MY_NT_SUCCESS(rcNt))
    373374        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
    374375    if (MY_NT_SUCCESS(rcNt))
    375376        rcNt = Ios.u.Status;
     377
     378    if (MY_NT_SUCCESS(rcNt))
     379    {
     380        if (!(BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
     381            TagInfo.ReparseTag = 0;
     382        else
     383        {
     384            MY_NTSTATUS rcNt2 = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
     385            if (   !MY_NT_SUCCESS(rcNt2)
     386                || !MY_NT_SUCCESS(Ios.u.Status))
     387                TagInfo.ReparseTag = 0;
     388        }
     389    }
     390
    376391    if (MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath)
    377392    {
     
    385400    if (MY_NT_SUCCESS(rcNt))
    386401    {
    387         pStat->st_mode          = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
     402        pStat->st_mode          = birdFileInfoToMode(BasicInfo.FileAttributes, TagInfo.ReparseTag, pszPath,
    388403                                                     pNameInfo ? pNameInfo->FileName : pwszPath,
    389404                                                     pNameInfo ? pNameInfo->FileNameLength
    390405                                                     : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0,
    391                                                      &pStat->st_dirsymlink);
     406                                                     &pStat->st_isdirsymlink, &pStat->st_ismountpoint);
    392407        pStat->st_padding0[0]   = 0;
    393408        pStat->st_padding0[1]   = 0;
     
    506521        birdCloseFile(hFile);
    507522
     523        if (rc || !pStat->st_ismountpoint)
     524        { /* very likely */ }
     525        else
     526        {
     527            /*
     528             * If we hit a mount point (NTFS volume mounted under an empty NTFS directory),
     529             * we should return information about what's mounted there rather than the
     530             * directory it is mounted at as this is what UNIX does.
     531             */
     532            hFile = birdOpenFileEx(hRoot, pszPath,
     533                                   FILE_READ_ATTRIBUTES,
     534                                   FILE_ATTRIBUTE_NORMAL,
     535                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     536                                   FILE_OPEN,
     537                                   FILE_OPEN_FOR_BACKUP_INTENT,
     538                                   OBJ_CASE_INSENSITIVE);
     539            if (hFile != INVALID_HANDLE_VALUE)
     540            {
     541                rc = birdStatHandle2(hFile, pStat, pszPath, NULL);
     542                pStat->st_ismountpoint = 2;
     543                birdCloseFile(hFile);
     544            }
     545        }
     546
    508547#if 0
    509548        {
     
    558597                     * Convert the data.
    559598                     */
    560                     birdStatFillFromFileIdFullDirInfo(pStat, pBuf, pszPath);
     599                    birdStatFillFromFileIdFullDirInfo(pStat, pBuf);
    561600
    562601                    /* Get the serial number, reusing the buffer from above. */
     
    597636        rc = birdStatHandle2(hFile, pStat, NULL, pwszPath);
    598637        birdCloseFile(hFile);
     638
     639        /*
     640         * If we hit a mount point (NTFS volume mounted under an empty NTFS directory),
     641         * we should return information about what's mounted there rather than the
     642         * directory it is mounted at as this is what UNIX does.
     643         */
     644        hFile = birdOpenFileExW(hRoot, pwszPath,
     645                                FILE_READ_ATTRIBUTES,
     646                                FILE_ATTRIBUTE_NORMAL,
     647                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     648                                FILE_OPEN,
     649                                FILE_OPEN_FOR_BACKUP_INTENT,
     650                                OBJ_CASE_INSENSITIVE);
     651        if (hFile != INVALID_HANDLE_VALUE)
     652        {
     653            rc = birdStatHandle2(hFile, pStat, NULL, pwszPath);
     654            pStat->st_ismountpoint = 2;
     655            birdCloseFile(hFile);
     656        }
    599657    }
    600658    else
     
    636694                     * Convert the data.
    637695                     */
    638                     birdStatFillFromFileIdFullDirInfo(pStat, pBuf, NULL);
     696                    birdStatFillFromFileIdFullDirInfo(pStat, pBuf);
    639697
    640698                    /* Get the serial number, reusing the buffer from above. */
Note: See TracChangeset for help on using the changeset viewer.