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