xref: /reactos/drivers/filesystems/ext2/src/misc.c (revision c2c66aff)
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
Ext2Log2(ULONG Value)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
Ext2NtTime(IN ULONG i_time)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
Ext2LinuxTime(IN LARGE_INTEGER SysTime)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
Ext2MbsToUnicode(struct nls_table * PageTable,IN OUT PUNICODE_STRING Unicode,IN PANSI_STRING Mbs)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
Ext2UnicodeToMbs(struct nls_table * PageTable,IN OUT PANSI_STRING Mbs,IN PUNICODE_STRING Unicode)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
Ext2OEMToUnicodeSize(IN PEXT2_VCB Vcb,IN PANSI_STRING Oem)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
Ext2OEMToUnicode(IN PEXT2_VCB Vcb,IN OUT PUNICODE_STRING Unicode,IN POEM_STRING Oem)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
Ext2UnicodeToOEMSize(IN PEXT2_VCB Vcb,IN PUNICODE_STRING Unicode)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
Ext2UnicodeToOEM(IN PEXT2_VCB Vcb,IN OUT POEM_STRING Oem,IN PUNICODE_STRING Unicode)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
Ext2Sleep(ULONG ms)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 
Ext2LinuxError(NTSTATUS Status)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_CANT_WAIT:
386     case STATUS_PENDING:
387         return (-EAGAIN);
388 
389     case STATUS_DEVICE_NOT_READY:
390         return (-EIO);
391 
392     case STATUS_CANCELLED:
393     case STATUS_REQUEST_ABORTED:
394         return (-EINTR);
395 
396     case STATUS_BUFFER_OVERFLOW:
397     case STATUS_INVALID_BUFFER_SIZE:
398         return (-EMSGSIZE);
399 
400     case STATUS_ADDRESS_ALREADY_EXISTS:
401         return (-EADDRINUSE);
402     }
403 
404     if (NT_SUCCESS (Status))
405         return 0;
406 
407     return (-EINVAL);
408 }
409 
Ext2WinntError(int rc)410 NTSTATUS Ext2WinntError(int rc)
411 {
412     switch (rc) {
413 
414     case 0:
415         return STATUS_SUCCESS;
416 
417     case -EPERM:
418     case -EACCES:
419         return STATUS_ACCESS_DENIED;
420 
421     case -ENOENT:
422         return  STATUS_OBJECT_NAME_NOT_FOUND;
423 
424     case -EFAULT:
425         return STATUS_ACCESS_VIOLATION;
426 
427     case -ETOOSMALL:
428         return STATUS_BUFFER_TOO_SMALL;
429 
430     case -EBADMSG:
431     case -EBADF:
432     case -EINVAL:
433     case -EFBIG:
434         return STATUS_INVALID_PARAMETER;
435 
436     case -EBUSY:
437         return STATUS_DEVICE_BUSY;
438 
439     case -ENOSYS:
440         return STATUS_NOT_IMPLEMENTED;
441 
442     case -ENOSPC:
443         return STATUS_DISK_FULL;
444 
445     case -EOPNOTSUPP:
446         return STATUS_NOT_SUPPORTED;
447 
448     case -EDEADLK:
449         return STATUS_POSSIBLE_DEADLOCK;
450 
451     case -EEXIST:
452         return STATUS_OBJECT_NAME_COLLISION;
453 
454     case -EIO:
455         return STATUS_UNEXPECTED_IO_ERROR;
456 
457     case -ENOTDIR:
458         return STATUS_NOT_A_DIRECTORY;
459 
460     case -EISDIR:
461         return STATUS_FILE_IS_A_DIRECTORY;
462 
463     case -ENOTEMPTY:
464         return STATUS_DIRECTORY_NOT_EMPTY;
465 
466     case -ENODEV:
467         return STATUS_NO_SUCH_DEVICE;
468 
469     case -ENXIO:
470         return STATUS_INVALID_ADDRESS;
471 
472     case -EADDRNOTAVAIL:
473         return STATUS_INVALID_ADDRESS;
474 
475     case -ENETDOWN:
476         return STATUS_UNEXPECTED_NETWORK_ERROR;
477 
478     case -ENETUNREACH:
479         return STATUS_NETWORK_UNREACHABLE;
480 
481     case -ECONNABORTED:
482         return STATUS_CONNECTION_ABORTED;
483 
484     case -ECONNRESET:
485         return STATUS_CONNECTION_RESET;
486 
487     case -ENOMEM:
488         return STATUS_INSUFFICIENT_RESOURCES;
489 
490     case -ENOBUFS:
491         return STATUS_NO_MEMORY;
492 
493     case -ENOTCONN:
494         return STATUS_INVALID_CONNECTION;
495 
496     case -ESHUTDOWN:
497         return STATUS_CONNECTION_DISCONNECTED;
498 
499     case -ETIMEDOUT:
500         return STATUS_TIMEOUT;
501 
502     case -ECONNREFUSED:
503         return STATUS_CONNECTION_REFUSED;
504 
505     case -EHOSTUNREACH:
506         return STATUS_HOST_UNREACHABLE;
507 
508     case -EAGAIN:
509         return STATUS_CANT_WAIT;
510 
511     case -EINTR:
512         return  STATUS_CANCELLED;
513 
514     case -EMSGSIZE:
515         return STATUS_INVALID_BUFFER_SIZE;
516 
517     case -EADDRINUSE:
518         return STATUS_ADDRESS_ALREADY_EXISTS;
519     }
520 
521     return STATUS_UNSUCCESSFUL;
522 }
523 
Ext2IsDot(PUNICODE_STRING name)524 BOOLEAN Ext2IsDot(PUNICODE_STRING name)
525 {
526     return (name->Length == 2 && name->Buffer[0] == L'.');
527 }
528 
Ext2IsDotDot(PUNICODE_STRING name)529 BOOLEAN Ext2IsDotDot(PUNICODE_STRING name)
530 {
531     return (name->Length == 4 && name->Buffer[0] == L'.' &&
532             name->Buffer[1] == L'.');
533 }
534