Sync with trunk r58740.
[reactos.git] / 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: services/fs/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 VOID
38 CdfsSwapString(PWCHAR Out,
39 PUCHAR In,
40 ULONG Count)
41 {
42 PUCHAR t = (PUCHAR)Out;
43 ULONG i;
44
45 for (i = 0; i < Count; i += 2)
46 {
47 t[i] = In[i+1];
48 t[i+1] = In[i];
49 if (t[i+1] == 0 && t[i] == ';')
50 break;
51 }
52 if ((i>2)&&(t[i-2] == '.'))
53 {
54 t[i-2] = 0;
55 t[i-1] = 0;
56 }
57 t[i] = 0;
58 t[i+1] = 0;
59 }
60
61
62 VOID
63 CdfsDateTimeToSystemTime(PFCB Fcb,
64 PLARGE_INTEGER SystemTime)
65 {
66 TIME_FIELDS TimeFields;
67 LARGE_INTEGER LocalTime;
68
69 TimeFields.Milliseconds = 0;
70 TimeFields.Second = Fcb->Entry.Second;
71 TimeFields.Minute = Fcb->Entry.Minute;
72 TimeFields.Hour = Fcb->Entry.Hour;
73
74 TimeFields.Day = Fcb->Entry.Day;
75 TimeFields.Month = Fcb->Entry.Month;
76 TimeFields.Year = Fcb->Entry.Year + 1900;
77
78 RtlTimeFieldsToTime(&TimeFields,
79 &LocalTime);
80 ExLocalTimeToSystemTime(&LocalTime, SystemTime);
81 }
82
83
84 VOID
85 CdfsFileFlagsToAttributes(PFCB Fcb,
86 PULONG FileAttributes)
87 {
88 /* FIXME: Fix attributes */
89
90 *FileAttributes = // FILE_ATTRIBUTE_READONLY |
91 ((Fcb->Entry.FileFlags & FILE_FLAG_HIDDEN) ? FILE_ATTRIBUTE_HIDDEN : 0) |
92 ((Fcb->Entry.FileFlags & FILE_FLAG_DIRECTORY) ? FILE_ATTRIBUTE_DIRECTORY : 0) |
93 ((Fcb->Entry.FileFlags & FILE_FLAG_SYSTEM) ? FILE_ATTRIBUTE_SYSTEM : 0) |
94 ((Fcb->Entry.FileFlags & FILE_FLAG_READONLY) ? FILE_ATTRIBUTE_READONLY : 0);
95 }
96
97 BOOLEAN
98 CdfsIsNameLegalDOS8Dot3(IN UNICODE_STRING FileName
99 )
100 {
101 ULONG i;
102 STRING DbcsName;
103 CHAR DbcsNameBuffer[12];
104
105 /* 8dot3 filename is max 12 length */
106 if (FileName.Length / sizeof(WCHAR) > 12)
107 {
108 return FALSE;
109 }
110
111 for (i = 0; i < FileName.Length / sizeof(WCHAR) ; i++)
112 {
113 /* Don't allow spaces in FileName */
114 if (FileName.Buffer[i] == L' ')
115 return FALSE;
116 }
117
118 /* If FileName is finishing with a dot, remove it */
119 if (FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == '.')
120 {
121 FileName.Length -= sizeof(WCHAR);
122 }
123
124 /* Finally, convert the string to call the FsRtl function */
125 DbcsName.MaximumLength = 12;
126 DbcsName.Buffer = DbcsNameBuffer;
127 if (!NT_SUCCESS(RtlUnicodeStringToCountedOemString(&DbcsName,
128 &FileName,
129 FALSE )))
130 {
131
132 return FALSE;
133 }
134 return FsRtlIsFatDbcsLegal(DbcsName, FALSE, FALSE, FALSE);
135 }
136
137 VOID
138 CdfsShortNameCacheGet
139 (PFCB DirectoryFcb,
140 PLARGE_INTEGER StreamOffset,
141 PUNICODE_STRING LongName,
142 PUNICODE_STRING ShortName)
143 {
144 PLIST_ENTRY Entry;
145 PCDFS_SHORT_NAME ShortNameEntry;
146 GENERATE_NAME_CONTEXT Context = { 0 };
147
148 DPRINT("CdfsShortNameCacheGet(%I64u,%wZ)\n", StreamOffset->QuadPart, LongName);
149
150 /* Get the name list resource */
151 ExAcquireResourceExclusiveLite(&DirectoryFcb->NameListResource, TRUE);
152
153 /* Try to find the name in our cache */
154 for (Entry = DirectoryFcb->ShortNameList.Flink;
155 Entry != &DirectoryFcb->ShortNameList;
156 Entry = Entry->Flink)
157 {
158 ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
159 if (ShortNameEntry->StreamOffset.QuadPart == StreamOffset->QuadPart)
160 {
161 /* Cache hit */
162 RtlCopyMemory
163 (ShortName->Buffer, ShortNameEntry->Name.Buffer,
164 ShortNameEntry->Name.Length);
165 ShortName->Length = ShortNameEntry->Name.Length;
166 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
167 DPRINT("Yield short name %wZ from cache\n", ShortName);
168 return;
169 }
170 }
171
172 /* Cache miss */
173 if (!CdfsIsNameLegalDOS8Dot3(*LongName))
174 {
175 RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
176 }
177 else
178 {
179 /* copy short name */
180 RtlUpcaseUnicodeString
181 (ShortName,
182 LongName,
183 FALSE);
184 }
185
186 DPRINT("Initial Guess %wZ\n", ShortName);
187
188 /* Make it unique by scanning the cache and bumping */
189 /* Note that incrementing the ambiguous name is enough, since we add new
190 * entries at the tail. We'll scan over all collisions. */
191 /* XXX could perform better. */
192 for (Entry = DirectoryFcb->ShortNameList.Flink;
193 Entry != &DirectoryFcb->ShortNameList;
194 Entry = Entry->Flink)
195 {
196 ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
197 if (RtlCompareUnicodeString
198 (ShortName,
199 &ShortNameEntry->Name,
200 TRUE) == 0) /* Match */
201 {
202 RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
203 DPRINT("Collide; try %wZ\n", ShortName);
204 }
205 }
206
207 /* We've scanned over all entries and now have a unique one. Cache it. */
208 ShortNameEntry = ExAllocatePoolWithTag(PagedPool, sizeof(CDFS_SHORT_NAME), TAG_FCB);
209 if (!ShortNameEntry)
210 {
211 /* We couldn't cache it, but we can return it. We run the risk of
212 * generating a non-unique name later. */
213 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
214 DPRINT1("Couldn't cache potentially clashing 8.3 name %wZ\n", ShortName);
215 return;
216 }
217
218 ShortNameEntry->StreamOffset = *StreamOffset;
219 ShortNameEntry->Name.Buffer = ShortNameEntry->NameBuffer;
220 ShortNameEntry->Name.Length = ShortName->Length;
221 ShortNameEntry->Name.MaximumLength = sizeof(ShortNameEntry->NameBuffer);
222 RtlCopyMemory
223 (ShortNameEntry->NameBuffer,
224 ShortName->Buffer,
225 ShortName->Length);
226 InsertTailList(&DirectoryFcb->ShortNameList, &ShortNameEntry->Entry);
227 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
228
229 DPRINT("Returning short name %wZ for long name %wZ\n", ShortName, LongName);
230 }
231
232 /* EOF */