[EXT2]
[reactos.git] / reactos / drivers / filesystems / ext2 / src / misc.c
1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: misc.c
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
7 * UPDATE HISTORY:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "ext2fs.h"
13
14 /* GLOBALS ***************************************************************/
15
16 extern PEXT2_GLOBAL Ext2Global;
17
18 /* DEFINITIONS *************************************************************/
19
20 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2Sleep)
22 #endif
23
24 ULONG
25 Ext2Log2(ULONG Value)
26 {
27 ULONG Order = 0;
28
29 ASSERT(Value > 0);
30
31 while (Value) {
32 Order++;
33 Value >>= 1;
34 }
35
36 return (Order - 1);
37 }
38
39 LARGE_INTEGER
40 Ext2NtTime (IN ULONG i_time)
41 {
42 LARGE_INTEGER SysTime;
43
44 SysTime.QuadPart = 0;
45 RtlSecondsSince1970ToTime(i_time, &SysTime);
46
47 return SysTime;
48 }
49
50 ULONG
51 Ext2LinuxTime (IN LARGE_INTEGER SysTime)
52 {
53 ULONG Ext2Time = 0;
54
55 if (!RtlTimeToSecondsSince1970(&SysTime, &Ext2Time)) {
56 LARGE_INTEGER NtTime;
57 KeQuerySystemTime(&NtTime);
58 RtlTimeToSecondsSince1970(&NtTime, &Ext2Time);
59 }
60
61 return Ext2Time;
62 }
63
64
65 ULONG
66 Ext2MbsToUnicode(
67 struct nls_table * PageTable,
68 IN OUT PUNICODE_STRING Unicode,
69 IN PANSI_STRING Mbs )
70 {
71 ULONG Length = 0;
72 int i, mbc = 0;
73 WCHAR uc;
74
75 /* Count the length of the resulting Unicode. */
76 for (i = 0; i < Mbs->Length; i += mbc) {
77
78 mbc = PageTable->char2uni(
79 (PUCHAR)&(Mbs->Buffer[i]),
80 Mbs->Length - i,
81 &uc
82 );
83
84 if (mbc <= 0) {
85
86 /* invalid character. */
87 if (mbc == 0 && Length > 0) {
88 break;
89 }
90 return 0;
91 }
92
93 Length += 2;
94 }
95
96 if (Unicode) {
97 if (Unicode->MaximumLength < Length) {
98
99 DbgBreak();
100 return 0;
101 }
102
103 Unicode->Length = 0;
104 mbc = 0;
105
106 for (i = 0; i < Mbs->Length; i += mbc) {
107
108 mbc = PageTable->char2uni(
109 (PUCHAR)&(Mbs->Buffer[i]),
110 Mbs->Length - i,
111 &uc
112 );
113 Unicode->Buffer[Unicode->Length/2] = uc;
114 Unicode->Length += 2;
115 }
116 }
117
118 return Length;
119 }
120
121 ULONG
122 Ext2UnicodeToMbs (
123 struct nls_table * PageTable,
124 IN OUT PANSI_STRING Mbs,
125 IN PUNICODE_STRING Unicode)
126 {
127 ULONG Length = 0;
128 UCHAR mbs[0x10];
129 int i, mbc;
130
131 /* Count the length of the resulting mbc-8. */
132 for (i = 0; i < (Unicode->Length / 2); i++) {
133
134 RtlZeroMemory(mbs, 0x10);
135 mbc = PageTable->uni2char(
136 Unicode->Buffer[i],
137 mbs,
138 0x10
139 );
140
141 if (mbc <= 0) {
142
143 /* Invalid character. */
144 return 0;
145 }
146
147 Length += mbc;
148 }
149
150 if (Mbs) {
151
152 if (Mbs->MaximumLength < Length) {
153
154 DbgBreak();
155 return 0;
156 }
157
158 Mbs->Length = 0;
159
160 for (i = 0; i < (Unicode->Length / 2); i++) {
161
162 mbc = PageTable->uni2char(
163 Unicode->Buffer[i],
164 mbs,
165 0x10
166 );
167
168 RtlCopyMemory(
169 (PUCHAR)&(Mbs->Buffer[Mbs->Length]),
170 &mbs[0],
171 mbc
172 );
173
174 Mbs->Length += (USHORT)mbc;
175 }
176 }
177
178 return Length;
179 }
180
181
182 ULONG
183 Ext2OEMToUnicodeSize(
184 IN PEXT2_VCB Vcb,
185 IN PANSI_STRING Oem
186 )
187 {
188 ULONG Length = 0;
189
190 if (Vcb->Codepage.PageTable) {
191 Length = Ext2MbsToUnicode(Vcb->Codepage.PageTable, NULL, Oem);
192 if (Length > 0) {
193 goto errorout;
194 }
195 }
196
197 Length = RtlOemStringToCountedUnicodeSize(Oem);
198
199 errorout:
200
201 return Length;
202 }
203
204
205 NTSTATUS
206 Ext2OEMToUnicode(
207 IN PEXT2_VCB Vcb,
208 IN OUT PUNICODE_STRING Unicode,
209 IN POEM_STRING Oem
210 )
211 {
212 NTSTATUS Status;
213
214
215 if (Vcb->Codepage.PageTable) {
216 Status = Ext2MbsToUnicode(Vcb->Codepage.PageTable,
217 Unicode, Oem);
218
219 if (Status >0 && Status == Unicode->Length) {
220 Status = STATUS_SUCCESS;
221 goto errorout;
222 }
223 }
224
225 Status = RtlOemStringToUnicodeString(
226 Unicode, Oem, FALSE );
227
228 if (!NT_SUCCESS(Status)) {
229 DbgBreak();
230 goto errorout;
231 }
232
233 errorout:
234
235 return Status;
236 }
237
238 ULONG
239 Ext2UnicodeToOEMSize(
240 IN PEXT2_VCB Vcb,
241 IN PUNICODE_STRING Unicode
242 )
243 {
244 ULONG Length = 0;
245
246 if (Vcb->Codepage.PageTable) {
247 Length = Ext2UnicodeToMbs(Vcb->Codepage.PageTable,
248 NULL, Unicode);
249 if (Length > 0) {
250 return Length;
251 }
252
253 DbgBreak();
254 }
255
256 return RtlxUnicodeStringToOemSize(Unicode);
257 }
258
259
260 NTSTATUS
261 Ext2UnicodeToOEM (
262 IN PEXT2_VCB Vcb,
263 IN OUT POEM_STRING Oem,
264 IN PUNICODE_STRING Unicode)
265 {
266 NTSTATUS Status;
267
268 if (Vcb->Codepage.PageTable) {
269
270 Status = Ext2UnicodeToMbs(Vcb->Codepage.PageTable,
271 Oem, Unicode);
272 if (Status > 0 && Status == Oem->Length) {
273 Status = STATUS_SUCCESS;
274 } else {
275 Status = STATUS_UNSUCCESSFUL;
276 DbgBreak();
277 }
278
279 goto errorout;
280 }
281
282 Status = RtlUnicodeStringToOemString(
283 Oem, Unicode, FALSE );
284
285 if (!NT_SUCCESS(Status))
286 {
287 DbgBreak();
288 goto errorout;
289 }
290
291 errorout:
292
293 return Status;
294 }
295
296 VOID
297 Ext2Sleep(ULONG ms)
298 {
299 LARGE_INTEGER Timeout;
300 Timeout.QuadPart = (LONGLONG)ms*1000*(-10); /* ms/1000 sec*/
301 KeDelayExecutionThread(KernelMode, TRUE, &Timeout);
302 }
303
304 int Ext2LinuxError (NTSTATUS Status)
305 {
306 switch (Status) {
307 case STATUS_ACCESS_DENIED:
308 return (-EACCES);
309
310 case STATUS_ACCESS_VIOLATION:
311 return (-EFAULT);
312
313 case STATUS_BUFFER_TOO_SMALL:
314 return (-ETOOSMALL);
315
316 case STATUS_INVALID_PARAMETER:
317 return (-EINVAL);
318
319 case STATUS_NOT_IMPLEMENTED:
320 case STATUS_NOT_SUPPORTED:
321 return (-EOPNOTSUPP);
322
323 case STATUS_INVALID_ADDRESS:
324 case STATUS_INVALID_ADDRESS_COMPONENT:
325 return (-EADDRNOTAVAIL);
326
327 case STATUS_NO_SUCH_DEVICE:
328 case STATUS_NO_SUCH_FILE:
329 case STATUS_OBJECT_NAME_NOT_FOUND:
330 case STATUS_OBJECT_PATH_NOT_FOUND:
331 case STATUS_NETWORK_BUSY:
332 case STATUS_INVALID_NETWORK_RESPONSE:
333 case STATUS_UNEXPECTED_NETWORK_ERROR:
334 return (-ENETDOWN);
335
336 case STATUS_BAD_NETWORK_PATH:
337 case STATUS_NETWORK_UNREACHABLE:
338 case STATUS_PROTOCOL_UNREACHABLE:
339 return (-ENETUNREACH);
340
341 case STATUS_LOCAL_DISCONNECT:
342 case STATUS_TRANSACTION_ABORTED:
343 case STATUS_CONNECTION_ABORTED:
344 return (-ECONNABORTED);
345
346 case STATUS_REMOTE_DISCONNECT:
347 case STATUS_LINK_FAILED:
348 case STATUS_CONNECTION_DISCONNECTED:
349 case STATUS_CONNECTION_RESET:
350 case STATUS_PORT_UNREACHABLE:
351 return (-ECONNRESET);
352
353 case STATUS_INSUFFICIENT_RESOURCES:
354 return (-ENOMEM);
355
356 case STATUS_PAGEFILE_QUOTA:
357 case STATUS_NO_MEMORY:
358 case STATUS_CONFLICTING_ADDRESSES:
359 case STATUS_QUOTA_EXCEEDED:
360 case STATUS_TOO_MANY_PAGING_FILES:
361 case STATUS_WORKING_SET_QUOTA:
362 case STATUS_COMMITMENT_LIMIT:
363 case STATUS_TOO_MANY_ADDRESSES:
364 case STATUS_REMOTE_RESOURCES:
365 return (-ENOBUFS);
366
367 case STATUS_INVALID_CONNECTION:
368 return (-ENOTCONN);
369
370 case STATUS_PIPE_DISCONNECTED:
371 return (-ESHUTDOWN);
372
373 case STATUS_TIMEOUT:
374 case STATUS_IO_TIMEOUT:
375 case STATUS_LINK_TIMEOUT:
376 return (-ETIMEDOUT);
377
378 case STATUS_REMOTE_NOT_LISTENING:
379 case STATUS_CONNECTION_REFUSED:
380 return (-ECONNREFUSED);
381
382 case STATUS_HOST_UNREACHABLE:
383 return (-EHOSTUNREACH);
384
385 case STATUS_PENDING:
386 case STATUS_DEVICE_NOT_READY:
387 return (-EAGAIN);
388
389 case STATUS_CANCELLED:
390 case STATUS_REQUEST_ABORTED:
391 return (-EINTR);
392
393 case STATUS_BUFFER_OVERFLOW:
394 case STATUS_INVALID_BUFFER_SIZE:
395 return (-EMSGSIZE);
396
397 case STATUS_ADDRESS_ALREADY_EXISTS:
398 return (-EADDRINUSE);
399 }
400
401 if (NT_SUCCESS (Status))
402 return 0;
403
404 return (-EINVAL);
405 }
406
407 NTSTATUS Ext2WinntError(int rc)
408 {
409 switch (rc) {
410
411 case 0:
412 return STATUS_SUCCESS;
413
414 case -EPERM:
415 case -EACCES:
416 return STATUS_ACCESS_DENIED;
417
418 case -ENOENT:
419 return STATUS_OBJECT_NAME_NOT_FOUND;
420
421 case -EFAULT:
422 return STATUS_ACCESS_VIOLATION;
423
424 case -ETOOSMALL:
425 return STATUS_BUFFER_TOO_SMALL;
426
427 case -EBADMSG:
428 case -EBADF:
429 case -EINVAL:
430 case -EFBIG:
431 return STATUS_INVALID_PARAMETER;
432
433 case -EBUSY:
434 return STATUS_DEVICE_BUSY;
435
436 case -ENOSYS:
437 return STATUS_NOT_IMPLEMENTED;
438
439 case -ENOSPC:
440 return STATUS_DISK_FULL;
441
442 case -EOPNOTSUPP:
443 return STATUS_NOT_SUPPORTED;
444
445 case -EDEADLK:
446 return STATUS_POSSIBLE_DEADLOCK;
447
448 case -EEXIST:
449 return STATUS_OBJECT_NAME_COLLISION;
450
451 case -EIO:
452 return STATUS_UNEXPECTED_IO_ERROR;
453
454 case -ENOTDIR:
455 return STATUS_NOT_A_DIRECTORY;
456
457 case -EISDIR:
458 return STATUS_FILE_IS_A_DIRECTORY;
459
460 case -ENOTEMPTY:
461 return STATUS_DIRECTORY_NOT_EMPTY;
462
463 case -ENODEV:
464 return STATUS_NO_SUCH_DEVICE;
465
466 case -ENXIO:
467 return STATUS_INVALID_ADDRESS;
468
469 case -EADDRNOTAVAIL:
470 return STATUS_INVALID_ADDRESS;
471
472 case -ENETDOWN:
473 return STATUS_UNEXPECTED_NETWORK_ERROR;
474
475 case -ENETUNREACH:
476 return STATUS_NETWORK_UNREACHABLE;
477
478 case -ECONNABORTED:
479 return STATUS_CONNECTION_ABORTED;
480
481 case -ECONNRESET:
482 return STATUS_CONNECTION_RESET;
483
484 case -ENOMEM:
485 return STATUS_INSUFFICIENT_RESOURCES;
486
487 case -ENOBUFS:
488 return STATUS_NO_MEMORY;
489
490 case -ENOTCONN:
491 return STATUS_INVALID_CONNECTION;
492
493 case -ESHUTDOWN:
494 return STATUS_CONNECTION_DISCONNECTED;
495
496 case -ETIMEDOUT:
497 return STATUS_TIMEOUT;
498
499 case -ECONNREFUSED:
500 return STATUS_CONNECTION_REFUSED;
501
502 case -EHOSTUNREACH:
503 return STATUS_HOST_UNREACHABLE;
504
505 case -EAGAIN:
506 return STATUS_DEVICE_NOT_READY;
507
508 case -EINTR:
509 return STATUS_CANCELLED;
510
511 case -EMSGSIZE:
512 return STATUS_INVALID_BUFFER_SIZE;
513
514 case -EADDRINUSE:
515 return STATUS_ADDRESS_ALREADY_EXISTS;
516 }
517
518 return STATUS_UNSUCCESSFUL;
519 }
520
521 BOOLEAN Ext2IsDot(PUNICODE_STRING name)
522 {
523 return (name->Length == 2 && name->Buffer[0] == L'.');
524 }
525
526 BOOLEAN Ext2IsDotDot(PUNICODE_STRING name)
527 {
528 return (name->Length == 4 && name->Buffer[0] == L'.' &&
529 name->Buffer[1] == L'.');
530 }