[CDFS] Update the file paths in the header blocks. NFC
[reactos.git] / reactos / drivers / filesystems / cdfs / misc.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/cdfs/misc.c
23 * PURPOSE: CDROM (ISO 9660) filesystem driver
24 * PROGRAMMER: Eric Kohl
25 * UPDATE HISTORY:
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "cdfs.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS ****************************************************************/
36
37 /*
38 * FUNCTION: Used with IRP to set them to TopLevelIrp field
39 * ARGUMENTS:
40 * Irp = The IRP to set
41 * RETURNS: TRUE if top level was null, else FALSE
42 */
43 BOOLEAN
44 CdfsIsIrpTopLevel(
45 PIRP Irp)
46 {
47 BOOLEAN ReturnCode = FALSE;
48
49 DPRINT("CdfsIsIrpTopLevel()\n");
50
51 if (IoGetTopLevelIrp() == NULL)
52 {
53 IoSetTopLevelIrp(Irp);
54 ReturnCode = TRUE;
55 }
56
57 return ReturnCode;
58 }
59
60
61 /*
62 * FUNCTION: Allocate and fill a CDFS_IRP_CONTEXT struct in order to use it for IRP
63 * ARGUMENTS:
64 * DeviceObject = Used to fill in struct
65 * Irp = The IRP that need IRP_CONTEXT struct
66 * RETURNS: NULL or PCDFS_IRP_CONTEXT
67 */
68 PCDFS_IRP_CONTEXT
69 CdfsAllocateIrpContext(
70 PDEVICE_OBJECT DeviceObject,
71 PIRP Irp)
72 {
73 PCDFS_IRP_CONTEXT IrpContext;
74
75 DPRINT("CdfsAllocateIrpContext()\n");
76
77 IrpContext = (PCDFS_IRP_CONTEXT)ExAllocateFromNPagedLookasideList(&CdfsGlobalData->IrpContextLookasideList);
78 if (IrpContext == NULL)
79 return NULL;
80
81 RtlZeroMemory(IrpContext, sizeof(CDFS_IRP_CONTEXT));
82
83 // IrpContext->Identifier.Type = NTFS_TYPE_IRP_CONTEST;
84 // IrpContext->Identifier.Size = sizeof(NTFS_IRP_CONTEXT);
85 IrpContext->Irp = Irp;
86 IrpContext->DeviceObject = DeviceObject;
87 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
88 IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
89 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
90 IrpContext->FileObject = IrpContext->Stack->FileObject;
91 IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp);
92 IrpContext->PriorityBoost = IO_NO_INCREMENT;
93 IrpContext->Flags = IRPCONTEXT_COMPLETE;
94
95 if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
96 IrpContext->MajorFunction == IRP_MJ_DEVICE_CONTROL ||
97 IrpContext->MajorFunction == IRP_MJ_SHUTDOWN ||
98 (IrpContext->MajorFunction != IRP_MJ_CLEANUP &&
99 IrpContext->MajorFunction != IRP_MJ_CLOSE &&
100 IoIsOperationSynchronous(Irp)))
101 {
102 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
103 }
104
105 return IrpContext;
106 }
107
108
109 VOID
110 CdfsSwapString(PWCHAR Out,
111 PUCHAR In,
112 ULONG Count)
113 {
114 PUCHAR t = (PUCHAR)Out;
115 ULONG i;
116
117 for (i = 0; i < Count; i += 2)
118 {
119 t[i] = In[i+1];
120 t[i+1] = In[i];
121 if (t[i+1] == 0 && t[i] == ';')
122 break;
123 }
124 if ((i>2)&&(t[i-2] == '.'))
125 {
126 t[i-2] = 0;
127 t[i-1] = 0;
128 }
129 t[i] = 0;
130 t[i+1] = 0;
131 }
132
133
134 VOID
135 CdfsDateTimeToSystemTime(PFCB Fcb,
136 PLARGE_INTEGER SystemTime)
137 {
138 TIME_FIELDS TimeFields;
139 LARGE_INTEGER LocalTime;
140
141 TimeFields.Milliseconds = 0;
142 TimeFields.Second = Fcb->Entry.Second;
143 TimeFields.Minute = Fcb->Entry.Minute;
144 TimeFields.Hour = Fcb->Entry.Hour;
145
146 TimeFields.Day = Fcb->Entry.Day;
147 TimeFields.Month = Fcb->Entry.Month;
148 TimeFields.Year = Fcb->Entry.Year + 1900;
149
150 RtlTimeFieldsToTime(&TimeFields,
151 &LocalTime);
152 ExLocalTimeToSystemTime(&LocalTime, SystemTime);
153 }
154
155
156 VOID
157 CdfsFileFlagsToAttributes(PFCB Fcb,
158 PULONG FileAttributes)
159 {
160 /* FIXME: Fix attributes */
161
162 *FileAttributes = // FILE_ATTRIBUTE_READONLY |
163 ((Fcb->Entry.FileFlags & FILE_FLAG_HIDDEN) ? FILE_ATTRIBUTE_HIDDEN : 0) |
164 ((Fcb->Entry.FileFlags & FILE_FLAG_DIRECTORY) ? FILE_ATTRIBUTE_DIRECTORY : 0) |
165 ((Fcb->Entry.FileFlags & FILE_FLAG_SYSTEM) ? FILE_ATTRIBUTE_SYSTEM : 0) |
166 ((Fcb->Entry.FileFlags & FILE_FLAG_READONLY) ? FILE_ATTRIBUTE_READONLY : 0);
167 }
168
169 BOOLEAN
170 CdfsIsNameLegalDOS8Dot3(IN UNICODE_STRING FileName
171 )
172 {
173 ULONG i;
174 STRING DbcsName;
175 CHAR DbcsNameBuffer[12];
176
177 /* 8dot3 filename is max 12 length */
178 if (FileName.Length / sizeof(WCHAR) > 12)
179 {
180 return FALSE;
181 }
182
183 ASSERT(FileName.Length >= sizeof(WCHAR));
184 for (i = 0; i < FileName.Length / sizeof(WCHAR) ; i++)
185 {
186 /* Don't allow spaces in FileName */
187 if (FileName.Buffer[i] == L' ')
188 return FALSE;
189 }
190
191 /* If FileName is finishing with a dot, remove it */
192 if (FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == '.')
193 {
194 FileName.Length -= sizeof(WCHAR);
195 }
196
197 /* Finally, convert the string to call the FsRtl function */
198 RtlInitEmptyAnsiString(&DbcsName, DbcsNameBuffer, sizeof(DbcsNameBuffer));
199 if (!NT_SUCCESS(RtlUnicodeStringToCountedOemString(&DbcsName,
200 &FileName,
201 FALSE)))
202 {
203
204 return FALSE;
205 }
206 return FsRtlIsFatDbcsLegal(DbcsName, FALSE, FALSE, FALSE);
207 }
208
209 VOID
210 CdfsShortNameCacheGet
211 (PFCB DirectoryFcb,
212 PLARGE_INTEGER StreamOffset,
213 PUNICODE_STRING LongName,
214 PUNICODE_STRING ShortName)
215 {
216 PLIST_ENTRY Entry;
217 PCDFS_SHORT_NAME ShortNameEntry;
218 GENERATE_NAME_CONTEXT Context = { 0 };
219
220 DPRINT("CdfsShortNameCacheGet(%I64d,%wZ)\n", StreamOffset->QuadPart, LongName);
221
222 /* Get the name list resource */
223 ExAcquireResourceExclusiveLite(&DirectoryFcb->NameListResource, TRUE);
224
225 /* Try to find the name in our cache */
226 for (Entry = DirectoryFcb->ShortNameList.Flink;
227 Entry != &DirectoryFcb->ShortNameList;
228 Entry = Entry->Flink)
229 {
230 ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
231 if (ShortNameEntry->StreamOffset.QuadPart == StreamOffset->QuadPart)
232 {
233 /* Cache hit */
234 RtlCopyUnicodeString(ShortName, &ShortNameEntry->Name);
235 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
236 DPRINT("Yield short name %wZ from cache\n", ShortName);
237 return;
238 }
239 }
240
241 /* Cache miss */
242 if (!CdfsIsNameLegalDOS8Dot3(*LongName))
243 {
244 RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
245 }
246 else
247 {
248 /* copy short name */
249 RtlUpcaseUnicodeString
250 (ShortName,
251 LongName,
252 FALSE);
253 }
254
255 DPRINT("Initial Guess %wZ\n", ShortName);
256
257 /* Make it unique by scanning the cache and bumping */
258 /* Note that incrementing the ambiguous name is enough, since we add new
259 * entries at the tail. We'll scan over all collisions. */
260 /* XXX could perform better. */
261 for (Entry = DirectoryFcb->ShortNameList.Flink;
262 Entry != &DirectoryFcb->ShortNameList;
263 Entry = Entry->Flink)
264 {
265 ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
266 if (RtlCompareUnicodeString
267 (ShortName,
268 &ShortNameEntry->Name,
269 TRUE) == 0) /* Match */
270 {
271 RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
272 DPRINT("Collide; try %wZ\n", ShortName);
273 }
274 }
275
276 /* We've scanned over all entries and now have a unique one. Cache it. */
277 ShortNameEntry = ExAllocatePoolWithTag(PagedPool,
278 sizeof(CDFS_SHORT_NAME),
279 CDFS_SHORT_NAME_TAG);
280 if (!ShortNameEntry)
281 {
282 /* We couldn't cache it, but we can return it. We run the risk of
283 * generating a non-unique name later. */
284 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
285 DPRINT1("Couldn't cache potentially clashing 8.3 name %wZ\n", ShortName);
286 return;
287 }
288
289 ShortNameEntry->StreamOffset = *StreamOffset;
290 RtlInitEmptyUnicodeString(&ShortNameEntry->Name,
291 ShortNameEntry->NameBuffer,
292 sizeof(ShortNameEntry->NameBuffer));
293 RtlCopyUnicodeString(&ShortNameEntry->Name, ShortName);
294 InsertTailList(&DirectoryFcb->ShortNameList, &ShortNameEntry->Entry);
295 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
296
297 DPRINT("Returning short name %wZ for long name %wZ\n", ShortName, LongName);
298 }
299
300 /* EOF */