Merge r68232 to get Windows' rpcrt4.dll to work under ReactOS.
[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: 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 ASSERT(FileName.Length >= sizeof(WCHAR));
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 RtlInitEmptyAnsiString(&DbcsName, DbcsNameBuffer, sizeof(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(%I64d,%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 RtlCopyUnicodeString(ShortName, &ShortNameEntry->Name);
163 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
164 DPRINT("Yield short name %wZ from cache\n", ShortName);
165 return;
166 }
167 }
168
169 /* Cache miss */
170 if (!CdfsIsNameLegalDOS8Dot3(*LongName))
171 {
172 RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
173 }
174 else
175 {
176 /* copy short name */
177 RtlUpcaseUnicodeString
178 (ShortName,
179 LongName,
180 FALSE);
181 }
182
183 DPRINT("Initial Guess %wZ\n", ShortName);
184
185 /* Make it unique by scanning the cache and bumping */
186 /* Note that incrementing the ambiguous name is enough, since we add new
187 * entries at the tail. We'll scan over all collisions. */
188 /* XXX could perform better. */
189 for (Entry = DirectoryFcb->ShortNameList.Flink;
190 Entry != &DirectoryFcb->ShortNameList;
191 Entry = Entry->Flink)
192 {
193 ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
194 if (RtlCompareUnicodeString
195 (ShortName,
196 &ShortNameEntry->Name,
197 TRUE) == 0) /* Match */
198 {
199 RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
200 DPRINT("Collide; try %wZ\n", ShortName);
201 }
202 }
203
204 /* We've scanned over all entries and now have a unique one. Cache it. */
205 ShortNameEntry = ExAllocatePoolWithTag(PagedPool,
206 sizeof(CDFS_SHORT_NAME),
207 CDFS_SHORT_NAME_TAG);
208 if (!ShortNameEntry)
209 {
210 /* We couldn't cache it, but we can return it. We run the risk of
211 * generating a non-unique name later. */
212 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
213 DPRINT1("Couldn't cache potentially clashing 8.3 name %wZ\n", ShortName);
214 return;
215 }
216
217 ShortNameEntry->StreamOffset = *StreamOffset;
218 RtlInitEmptyUnicodeString(&ShortNameEntry->Name,
219 ShortNameEntry->NameBuffer,
220 sizeof(ShortNameEntry->NameBuffer));
221 RtlCopyUnicodeString(&ShortNameEntry->Name, ShortName);
222 InsertTailList(&DirectoryFcb->ShortNameList, &ShortNameEntry->Entry);
223 ExReleaseResourceLite(&DirectoryFcb->NameListResource);
224
225 DPRINT("Returning short name %wZ for long name %wZ\n", ShortName, LongName);
226 }
227
228 /* EOF */