Added support for FAT16 partition with clustersize greater than page size.
[reactos.git] / reactos / drivers / fs / vfat / direntry.c
1 /* $Id: direntry.c,v 1.2 2001/07/13 10:31:14 ekohl Exp $
2 *
3 *
4 * FILE: DirEntry.c
5 * PURPOSE: Routines to manipulate directory entries.
6 * COPYRIGHT: See COPYING in the top level directory
7 * PROJECT: ReactOS kernel
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 * Rex Jolliff (rex@lvcablemodem.com)
10 */
11
12 /* ------------------------------------------------------- INCLUDES */
13
14 #include <ddk/ntddk.h>
15 #include <wchar.h>
16 #include <limits.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->BytesPerCluster > PAGESIZE ? \
24 (pDeviceExt)->BytesPerCluster : PAGESIZE)
25
26 #define ENTRIES_PER_CACHEPAGE(pDeviceExt) (ENTRIES_PER_SECTOR * \
27 (CACHEPAGESIZE(pDeviceExt) / ((pDeviceExt)->BytesPerSector)))
28
29
30 ULONG
31 vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION pDeviceExt,
32 PFAT_DIR_ENTRY pFatDirEntry)
33 {
34 ULONG cluster;
35
36 if (pDeviceExt->FatType == FAT32)
37 {
38 cluster = pFatDirEntry->FirstCluster +
39 pFatDirEntry->FirstClusterHigh * 65536;
40 }
41 else
42 {
43 cluster = pFatDirEntry->FirstCluster;
44 }
45
46 return cluster;
47 }
48
49 BOOL
50 vfatIsDirEntryDeleted (FATDirEntry * pFatDirEntry)
51 {
52 return pFatDirEntry->Filename [0] == 0xe5;
53 }
54
55 BOOL
56 vfatIsDirEntryEndMarker (FATDirEntry * pFatDirEntry)
57 {
58 return pFatDirEntry->Filename [0] == 0;
59 }
60
61 BOOL
62 vfatIsDirEntryLongName (FATDirEntry * pFatDirEntry)
63 {
64 return pFatDirEntry->Attrib == 0x0f;
65 }
66
67 void
68 vfatGetDirEntryName (PFAT_DIR_ENTRY dirEntry, PWSTR entryName)
69 {
70 vfat8Dot3ToString (dirEntry->Filename, dirEntry->Ext, entryName);
71 }
72
73 NTSTATUS
74 vfatGetNextDirEntry (PDEVICE_EXTENSION pDeviceExt,
75 PVFATFCB pDirectoryFCB,
76 ULONG * pDirectoryIndex,
77 PWSTR pLongFileName,
78 PFAT_DIR_ENTRY pDirEntry)
79 {
80 NTSTATUS status;
81 ULONG indexInPage = *pDirectoryIndex % ENTRIES_PER_CACHEPAGE(pDeviceExt);
82 ULONG pageNumber = *pDirectoryIndex / ENTRIES_PER_CACHEPAGE(pDeviceExt);
83 PVOID currentPage = NULL;
84 PCACHE_SEGMENT cacheSegment = NULL;
85 FATDirEntry * fatDirEntry;
86 slot * longNameEntry;
87 ULONG cpos;
88
89 DPRINT ("vfatGetNextDirEntry (%x,%x,%d,%x,%x)\n",
90 pDeviceExt,
91 pDirectoryFCB,
92 *pDirectoryIndex,
93 pLongFileName,
94 pDirEntry);
95
96 *pLongFileName = 0;
97
98 DPRINT ("Validating current directory page\n");
99 status = vfatRequestAndValidateRegion (pDeviceExt,
100 pDirectoryFCB,
101 pageNumber * CACHEPAGESIZE(pDeviceExt),
102 (PVOID *) &currentPage,
103 &cacheSegment,
104 FALSE);
105 if (!NT_SUCCESS (status))
106 {
107 return status;
108 }
109
110 while (TRUE)
111 {
112 fatDirEntry = (FATDirEntry *) currentPage;
113
114 if (vfatIsDirEntryEndMarker (&fatDirEntry [indexInPage]))
115 {
116 DPRINT ("end of directory, returning no more entries\n");
117 status = vfatReleaseRegion (pDeviceExt,
118 pDirectoryFCB,
119 cacheSegment);
120 return STATUS_NO_MORE_ENTRIES;
121 }
122 else if (vfatIsDirEntryLongName (&fatDirEntry [indexInPage]))
123 {
124 DPRINT (" long name entry found at %d\n", *pDirectoryIndex);
125 longNameEntry = (slot *) currentPage;
126
127 DPRINT (" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
128 5, longNameEntry [indexInPage].name0_4,
129 6, longNameEntry [indexInPage].name5_10,
130 2, longNameEntry [indexInPage].name11_12);
131
132 vfat_initstr (pLongFileName, 256);
133 vfat_wcsncpy (pLongFileName, longNameEntry [indexInPage].name0_4, 5);
134 vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name5_10, 5, 6);
135 vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name11_12, 11, 2);
136
137 DPRINT (" longName: [%S]\n", pLongFileName);
138
139 cpos = 0;
140 while ((longNameEntry [indexInPage].id != 0x41) &&
141 (longNameEntry [indexInPage].id != 0x01) &&
142 (longNameEntry [indexInPage].attr > 0))
143 {
144 (*pDirectoryIndex)++;
145 indexInPage++;
146 if (indexInPage == ENTRIES_PER_CACHEPAGE(pDeviceExt))
147 {
148 indexInPage = 0;
149 pageNumber++;
150
151 status = vfatReleaseRegion (pDeviceExt,
152 pDirectoryFCB,
153 cacheSegment);
154 if (!NT_SUCCESS (status))
155 {
156 return status;
157 }
158 status = vfatRequestAndValidateRegion (pDeviceExt,
159 pDirectoryFCB,
160 pageNumber * CACHEPAGESIZE(pDeviceExt),
161 (PVOID *) &currentPage,
162 &cacheSegment,
163 FALSE);
164 if (!NT_SUCCESS (status))
165 {
166 return status;
167 }
168 longNameEntry = (slot *) currentPage;
169 }
170 DPRINT (" index %d\n", *pDirectoryIndex);
171
172 DPRINT (" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
173 5, longNameEntry [indexInPage].name0_4,
174 6, longNameEntry [indexInPage].name5_10,
175 2, longNameEntry [indexInPage].name11_12);
176
177 cpos++;
178 vfat_movstr (pLongFileName, 13, 0, cpos * 13);
179 vfat_wcsncpy (pLongFileName, longNameEntry [indexInPage].name0_4, 5);
180 vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name5_10, 5, 6);
181 vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name11_12, 11, 2);
182
183 DPRINT (" longName: [%S]\n", pLongFileName);
184
185 }
186 (*pDirectoryIndex)++;
187 indexInPage++;
188 if (indexInPage == ENTRIES_PER_CACHEPAGE(pDeviceExt))
189 {
190 indexInPage = 0;
191 pageNumber++;
192
193 status = vfatReleaseRegion (pDeviceExt,
194 pDirectoryFCB,
195 cacheSegment);
196 if (!NT_SUCCESS (status))
197 {
198 return status;
199 }
200 status = vfatRequestAndValidateRegion (pDeviceExt,
201 pDirectoryFCB,
202 pageNumber * CACHEPAGESIZE(pDeviceExt),
203 (PVOID *) &currentPage,
204 &cacheSegment,
205 FALSE);
206 if (!NT_SUCCESS (status))
207 {
208 return status;
209 }
210 }
211 }
212 else
213 {
214 memcpy (pDirEntry, &fatDirEntry [indexInPage], sizeof (FAT_DIR_ENTRY));
215 (*pDirectoryIndex)++;
216 break;
217 }
218 }
219
220 DPRINT ("Releasing current directory page\n");
221 status = vfatReleaseRegion (pDeviceExt,
222 pDirectoryFCB,
223 cacheSegment);
224
225 return status;
226 }
227
228
229
230
231