Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendirentry.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
1.7.6.1
|