ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

direntry.c
Go to the documentation of this file.
00001 /*
00002  * FILE:             DirEntry.c
00003  * PURPOSE:          Routines to manipulate directory entries.
00004  * COPYRIGHT:        See COPYING in the top level directory
00005  * PROJECT:          ReactOS kernel
00006  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
00007  *                   Rex Jolliff (rex@lvcablemodem.com)
00008  *                   Herve Poussineau (reactos@poussine.freesurf.fr)
00009  */
00010 
00011 /*  -------------------------------------------------------  INCLUDES  */
00012 
00013 #define NDEBUG
00014 #include "vfat.h"
00015 
00016 ULONG
00017 vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION  pDeviceExt,
00018                              PDIR_ENTRY  pFatDirEntry)
00019 {
00020     ULONG cluster;
00021 
00022     if (pDeviceExt->FatInfo.FatType == FAT32)
00023     {
00024         cluster = pFatDirEntry->Fat.FirstCluster |
00025                  (pFatDirEntry->Fat.FirstClusterHigh << 16);
00026     }
00027     else if (pDeviceExt->Flags & VCB_IS_FATX)
00028     {
00029         cluster = pFatDirEntry->FatX.FirstCluster;
00030     }
00031     else
00032     {
00033         cluster = pFatDirEntry->Fat.FirstCluster;
00034     }
00035 
00036     return  cluster;
00037 }
00038 
00039 static
00040 BOOLEAN
00041 FATIsDirectoryEmpty(PVFATFCB Fcb)
00042 {
00043     LARGE_INTEGER FileOffset;
00044     PVOID Context = NULL;
00045     PFAT_DIR_ENTRY FatDirEntry;
00046     ULONG Index, MaxIndex;
00047 
00048     if (vfatFCBIsRoot(Fcb))
00049     {
00050         Index = 0;
00051     }
00052     else
00053     {
00054         Index = 2;
00055     }
00056 
00057     FileOffset.QuadPart = 0;
00058     MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FAT_DIR_ENTRY);
00059 
00060     while (Index < MaxIndex)
00061     {
00062         if (Context == NULL || (Index % FAT_ENTRIES_PER_PAGE) == 0)
00063         {
00064             if (Context != NULL)
00065             {
00066                 CcUnpinData(Context);
00067             }
00068 
00069             if (!CcMapData(Fcb->FileObject, &FileOffset, sizeof(FAT_DIR_ENTRY), TRUE, &Context, (PVOID*)&FatDirEntry))
00070             {
00071                 return TRUE;
00072             }
00073 
00074             FatDirEntry += Index % FAT_ENTRIES_PER_PAGE;
00075             FileOffset.QuadPart += PAGE_SIZE;
00076         }
00077 
00078         if (FAT_ENTRY_END(FatDirEntry))
00079         {
00080             CcUnpinData(Context);
00081             return TRUE;
00082         }
00083 
00084         if (!FAT_ENTRY_DELETED(FatDirEntry))
00085         {
00086             CcUnpinData(Context);
00087             return FALSE;
00088         }
00089 
00090         Index++;
00091         FatDirEntry++;
00092     }
00093 
00094     if (Context)
00095     {
00096         CcUnpinData(Context);
00097     }
00098 
00099     return TRUE;
00100 }
00101 
00102 static
00103 BOOLEAN
00104 FATXIsDirectoryEmpty(PVFATFCB Fcb)
00105 {
00106     LARGE_INTEGER FileOffset;
00107     PVOID Context = NULL;
00108     PFATX_DIR_ENTRY FatXDirEntry;
00109     ULONG Index = 0, MaxIndex;
00110 
00111     FileOffset.QuadPart = 0;
00112     MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FATX_DIR_ENTRY);
00113 
00114     while (Index < MaxIndex)
00115     {
00116         if (Context == NULL || (Index % FATX_ENTRIES_PER_PAGE) == 0)
00117         {
00118             if (Context != NULL)
00119             {
00120                 CcUnpinData(Context);
00121             }
00122 
00123             if (!CcMapData(Fcb->FileObject, &FileOffset, sizeof(FATX_DIR_ENTRY), TRUE, &Context, (PVOID*)&FatXDirEntry))
00124             {
00125                 return TRUE;
00126             }
00127 
00128             FatXDirEntry += Index % FATX_ENTRIES_PER_PAGE;
00129             FileOffset.QuadPart += PAGE_SIZE;
00130         }
00131 
00132         if (FATX_ENTRY_END(FatXDirEntry))
00133         {
00134             CcUnpinData(Context);
00135             return TRUE;
00136         }
00137 
00138         if (!FATX_ENTRY_DELETED(FatXDirEntry))
00139         {
00140             CcUnpinData(Context);
00141             return FALSE;
00142         }
00143 
00144         Index++;
00145         FatXDirEntry++;
00146     }
00147 
00148     if (Context)
00149     {
00150         CcUnpinData(Context);
00151     }
00152 
00153     return TRUE;
00154 }
00155 
00156 BOOLEAN
00157 VfatIsDirectoryEmpty(PVFATFCB Fcb)
00158 {
00159     if (Fcb->Flags & FCB_IS_FATX_ENTRY)
00160         return FATXIsDirectoryEmpty(Fcb);
00161     else
00162         return FATIsDirectoryEmpty(Fcb);
00163 }
00164 
00165 NTSTATUS
00166 FATGetNextDirEntry(PVOID *pContext,
00167                    PVOID *pPage,
00168                    IN PVFATFCB pDirFcb,
00169                    PVFAT_DIRENTRY_CONTEXT DirContext,
00170                    BOOLEAN First)
00171 {
00172     ULONG dirMap;
00173     PWCHAR pName;
00174     LARGE_INTEGER FileOffset;
00175     PFAT_DIR_ENTRY fatDirEntry;
00176     slot * longNameEntry;
00177     ULONG index;
00178 
00179     UCHAR CheckSum, shortCheckSum;
00180     USHORT i;
00181     BOOLEAN Valid = TRUE;
00182     BOOLEAN Back = FALSE;
00183 
00184     DirContext->LongNameU.Length = 0;
00185     DirContext->LongNameU.Buffer[0] = UNICODE_NULL;
00186 
00187     FileOffset.u.HighPart = 0;
00188     FileOffset.u.LowPart = ROUND_DOWN(DirContext->DirIndex * sizeof(FAT_DIR_ENTRY), PAGE_SIZE);
00189 
00190     if (*pContext == NULL || (DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
00191     {
00192         if (*pContext != NULL)
00193         {
00194             CcUnpinData(*pContext);
00195         }
00196 
00197         if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
00198             !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
00199         {
00200             *pContext = NULL;
00201             return STATUS_NO_MORE_ENTRIES;
00202         }
00203     }
00204 
00205     fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE;
00206     longNameEntry = (slot*) fatDirEntry;
00207     dirMap = 0;
00208 
00209     if (First)
00210     {
00211         /* This is the first call to vfatGetNextDirEntry. Possible the start index points
00212          * into a long name or points to a short name with an assigned long name.
00213          * We must go back to the real start of the entry */
00214         while (DirContext->DirIndex > 0 &&
00215                !FAT_ENTRY_END(fatDirEntry) &&
00216                !FAT_ENTRY_DELETED(fatDirEntry) &&
00217                ((!FAT_ENTRY_LONG(fatDirEntry) && !Back) ||
00218                (FAT_ENTRY_LONG(fatDirEntry) && !(longNameEntry->id & 0x40))))
00219         {
00220             DirContext->DirIndex--;
00221             Back = TRUE;
00222 
00223             if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == FAT_ENTRIES_PER_PAGE - 1)
00224             {
00225                 CcUnpinData(*pContext);
00226                 FileOffset.u.LowPart -= PAGE_SIZE;
00227 
00228                 if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
00229                     !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
00230                 {
00231                     *pContext = NULL;
00232                     return STATUS_NO_MORE_ENTRIES;
00233                 }
00234 
00235                 fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE;
00236                 longNameEntry = (slot*) fatDirEntry;
00237             }
00238             else
00239             {
00240                 fatDirEntry--;
00241                 longNameEntry--;
00242             }
00243         }
00244 
00245         if (Back && !FAT_ENTRY_END(fatDirEntry) &&
00246            (FAT_ENTRY_DELETED(fatDirEntry) || !FAT_ENTRY_LONG(fatDirEntry)))
00247         {
00248             DirContext->DirIndex++;
00249 
00250             if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
00251             {
00252                 CcUnpinData(*pContext);
00253                 FileOffset.u.LowPart += PAGE_SIZE;
00254 
00255                 if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
00256                    !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
00257                 {
00258                     *pContext = NULL;
00259                     return STATUS_NO_MORE_ENTRIES;
00260                 }
00261 
00262                 fatDirEntry = (PFAT_DIR_ENTRY)*pPage;
00263                 longNameEntry = (slot*) *pPage;
00264             }
00265             else
00266             {
00267                 fatDirEntry++;
00268                 longNameEntry++;
00269             }
00270         }
00271     }
00272 
00273     DirContext->StartIndex = DirContext->DirIndex;
00274     CheckSum = 0;
00275 
00276     while (TRUE)
00277     {
00278         if (FAT_ENTRY_END(fatDirEntry))
00279         {
00280             CcUnpinData(*pContext);
00281             *pContext = NULL;
00282             return STATUS_NO_MORE_ENTRIES;
00283         }
00284     
00285         if (FAT_ENTRY_DELETED(fatDirEntry))
00286         {
00287             dirMap = 0;
00288             DirContext->LongNameU.Buffer[0] = 0;
00289             DirContext->StartIndex = DirContext->DirIndex + 1;
00290         }
00291         else
00292         {
00293             if (FAT_ENTRY_LONG(fatDirEntry))
00294             {
00295                 if (dirMap == 0)
00296                 {
00297                     DPRINT ("  long name entry found at %d\n", DirContext->DirIndex);
00298                     RtlZeroMemory(DirContext->LongNameU.Buffer, DirContext->LongNameU.MaximumLength);
00299                     CheckSum = longNameEntry->alias_checksum;
00300                     Valid = TRUE;
00301                 }
00302 
00303                 DPRINT("  name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
00304                     5, longNameEntry->name0_4,
00305                     6, longNameEntry->name5_10,
00306                     2, longNameEntry->name11_12);
00307 
00308                 index = longNameEntry->id & 0x3f; // Note: it can be 0 for corrupted FS
00309                 
00310                 /* Make sure index is valid and we have enaugh space in buffer
00311                   (we count one char for \0) */
00312                 if (index > 0 &&
00313                     index * 13 < DirContext->LongNameU.MaximumLength / sizeof(WCHAR))
00314                 {
00315                     index--; // make index 0 based
00316                     dirMap |= 1 << index;
00317 
00318                     pName = DirContext->LongNameU.Buffer + index * 13;
00319                     RtlCopyMemory(pName, longNameEntry->name0_4, 5 * sizeof(WCHAR));
00320                     RtlCopyMemory(pName + 5, longNameEntry->name5_10, 6 * sizeof(WCHAR));
00321                     RtlCopyMemory(pName + 11, longNameEntry->name11_12, 2 * sizeof(WCHAR));
00322 
00323                     if (longNameEntry->id & 0x40)
00324                     {
00325                         /* It's last LFN entry. Terminate filename with \0 */
00326                         pName[13] = UNICODE_NULL;
00327                     }
00328                 }
00329                 else
00330                     DPRINT1("Long name entry has invalid index: %x!\n", longNameEntry->id);
00331 
00332                 DPRINT ("  longName: [%S]\n", DirContext->LongNameU.Buffer);
00333 
00334                 if (CheckSum != longNameEntry->alias_checksum)
00335                 {
00336                      DPRINT1("Found wrong alias checksum in long name entry (first %x, current %x, %S)\n",
00337                              CheckSum, longNameEntry->alias_checksum, DirContext->LongNameU.Buffer);
00338                 Valid = FALSE;
00339                 }
00340             }
00341             else
00342             {
00343                 shortCheckSum = 0;
00344                 for (i = 0; i < 11; i++)
00345                 {
00346                     shortCheckSum = (((shortCheckSum & 1) << 7)
00347                                   | ((shortCheckSum & 0xfe) >> 1))
00348                                   + fatDirEntry->ShortName[i];
00349                 }
00350 
00351                 if (shortCheckSum != CheckSum && DirContext->LongNameU.Buffer[0])
00352                 {
00353                     DPRINT1("Checksum from long and short name is not equal (short: %x, long: %x, %S)\n",
00354                         shortCheckSum, CheckSum, DirContext->LongNameU.Buffer);
00355                     DirContext->LongNameU.Buffer[0] = 0;
00356                 }
00357 
00358                 if (Valid == FALSE)
00359                 {
00360                     DirContext->LongNameU.Buffer[0] = 0;
00361                 }
00362 
00363             RtlCopyMemory (&DirContext->DirEntry.Fat, fatDirEntry, sizeof (FAT_DIR_ENTRY));
00364             break;
00365             }
00366         }
00367 
00368         DirContext->DirIndex++;
00369 
00370         if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0)
00371         {
00372             CcUnpinData(*pContext);
00373             FileOffset.u.LowPart += PAGE_SIZE;
00374 
00375             if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
00376                 !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
00377             {
00378                 *pContext = NULL;
00379                 return STATUS_NO_MORE_ENTRIES;
00380             }
00381 
00382             fatDirEntry = (PFAT_DIR_ENTRY)*pPage;
00383             longNameEntry = (slot*) *pPage;
00384         }
00385         else
00386         {
00387             fatDirEntry++;
00388             longNameEntry++;
00389         }
00390     }
00391 
00392     /* Make sure filename is NULL terminate and calculate length */
00393     DirContext->LongNameU.Buffer[DirContext->LongNameU.MaximumLength / sizeof(WCHAR) - 1]
00394         = UNICODE_NULL;
00395     DirContext->LongNameU.Length = wcslen(DirContext->LongNameU.Buffer) * sizeof(WCHAR);
00396     
00397     /* Init short name */
00398     vfat8Dot3ToString(&DirContext->DirEntry.Fat, &DirContext->ShortNameU);
00399 
00400     /* If we found no LFN, use short name as long */
00401     if (DirContext->LongNameU.Length == 0)
00402         RtlCopyUnicodeString(&DirContext->LongNameU, &DirContext->ShortNameU);
00403 
00404     return STATUS_SUCCESS;
00405 }
00406 
00407 NTSTATUS FATXGetNextDirEntry(PVOID * pContext,
00408                              PVOID * pPage,
00409                              IN PVFATFCB pDirFcb,
00410                              PVFAT_DIRENTRY_CONTEXT DirContext,
00411                              BOOLEAN First)
00412 {
00413    LARGE_INTEGER FileOffset;
00414    PFATX_DIR_ENTRY fatxDirEntry;
00415    OEM_STRING StringO;
00416    ULONG DirIndex = DirContext->DirIndex;
00417 
00418    FileOffset.u.HighPart = 0;
00419 
00420    if (!vfatFCBIsRoot(pDirFcb))
00421    {
00422       /* need to add . and .. entries */
00423       switch (DirContext->DirIndex)
00424       {
00425          case 0: /* entry . */
00426          {
00427             DirContext->ShortNameU.Buffer[0] = 0;
00428             DirContext->ShortNameU.Length = 0;
00429             wcscpy(DirContext->LongNameU.Buffer, L".");
00430             DirContext->LongNameU.Length = sizeof(WCHAR);
00431             RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
00432             DirContext->DirEntry.FatX.Filename[0] = '.';
00433             DirContext->DirEntry.FatX.FilenameLength = 1;
00434             DirContext->StartIndex = 0;
00435             return STATUS_SUCCESS;
00436          }
00437          case 1: /* entry .. */
00438          {
00439             DirContext->ShortNameU.Buffer[0] = 0;
00440             DirContext->ShortNameU.Length = 0;
00441             wcscpy(DirContext->LongNameU.Buffer, L"..");
00442             DirContext->LongNameU.Length = 2 * sizeof(WCHAR);
00443             RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY));
00444             DirContext->DirEntry.FatX.Filename[0] = DirContext->DirEntry.FatX.Filename[1] = '.';
00445             DirContext->DirEntry.FatX.FilenameLength = 2;
00446             DirContext->StartIndex = 1;
00447             return STATUS_SUCCESS;
00448          }
00449          default:
00450             DirIndex -= 2;
00451       }
00452    }
00453 
00454    if (*pContext == NULL || (DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
00455    {
00456       if (*pContext != NULL)
00457       {
00458          CcUnpinData(*pContext);
00459       }
00460       FileOffset.u.LowPart = ROUND_DOWN(DirIndex * sizeof(FATX_DIR_ENTRY), PAGE_SIZE);
00461       if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
00462           !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
00463       {
00464          *pContext = NULL;
00465          return STATUS_NO_MORE_ENTRIES;
00466       }
00467    }
00468 
00469    fatxDirEntry = (PFATX_DIR_ENTRY)(*pPage) + DirIndex % FATX_ENTRIES_PER_PAGE;
00470 
00471    DirContext->StartIndex = DirContext->DirIndex;
00472 
00473    while (TRUE)
00474    {
00475       if (FATX_ENTRY_END(fatxDirEntry))
00476       {
00477           CcUnpinData(*pContext);
00478           *pContext = NULL;
00479           return STATUS_NO_MORE_ENTRIES;
00480       }
00481 
00482       if (!FATX_ENTRY_DELETED(fatxDirEntry))
00483       {
00484           RtlCopyMemory(&DirContext->DirEntry.FatX, fatxDirEntry, sizeof(FATX_DIR_ENTRY));
00485           break;
00486       }
00487       DirContext->DirIndex++;
00488       DirContext->StartIndex++;
00489       DirIndex++;
00490       if ((DirIndex % FATX_ENTRIES_PER_PAGE) == 0)
00491       {
00492          CcUnpinData(*pContext);
00493          FileOffset.u.LowPart += PAGE_SIZE;
00494          if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart ||
00495              !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage))
00496          {
00497             *pContext = NULL;
00498         return STATUS_NO_MORE_ENTRIES;
00499          }
00500          fatxDirEntry = (PFATX_DIR_ENTRY)*pPage;
00501       }
00502       else
00503       {
00504          fatxDirEntry++;
00505       }
00506    }
00507    DirContext->ShortNameU.Buffer[0] = 0;
00508    DirContext->ShortNameU.Length = 0;
00509    StringO.Buffer = (PCHAR)fatxDirEntry->Filename;
00510    StringO.Length = StringO.MaximumLength = fatxDirEntry->FilenameLength;
00511    RtlOemStringToUnicodeString(&DirContext->LongNameU, &StringO, FALSE);
00512    return STATUS_SUCCESS;
00513 }

Generated on Sun May 27 2012 04:27:45 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.