Whamcloud - gitweb
fbc28fa5859f2121b21b8a3316ec33acb816e7b8
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-native.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=4:tabstop=4:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 # define DEBUG_SUBSYSTEM S_LNET
38
39 #ifndef __KERNEL__
40
41 #include <ntddk.h>
42 #include <libcfs/libcfs.h>
43 #include <libcfs/user-bitops.h>
44 #include <lustre_lib.h>
45
46 /*
47  * Native API definitions
48  */
49
50 //
51 //  Disk I/O Routines
52 //
53
54 NTSYSAPI
55 NTSTATUS
56 NTAPI
57 NtReadFile(HANDLE FileHandle,
58     HANDLE Event OPTIONAL,
59     PIO_APC_ROUTINE ApcRoutine OPTIONAL,
60     PVOID ApcContext OPTIONAL,
61     PIO_STATUS_BLOCK IoStatusBlock,
62     PVOID Buffer,
63     ULONG Length,
64     PLARGE_INTEGER ByteOffset OPTIONAL,
65     PULONG Key OPTIONAL);
66
67 NTSYSAPI
68 NTSTATUS
69 NTAPI
70 NtWriteFile(HANDLE FileHandle,
71     HANDLE Event OPTIONAL,
72     PIO_APC_ROUTINE ApcRoutine OPTIONAL,
73     PVOID ApcContext OPTIONAL,
74     PIO_STATUS_BLOCK IoStatusBlock,
75     PVOID Buffer,
76     ULONG Length,
77     PLARGE_INTEGER ByteOffset OPTIONAL,
78     PULONG Key OPTIONAL);
79
80 NTSYSAPI
81 NTSTATUS
82 NTAPI
83 NtClose(HANDLE Handle);
84
85 NTSYSAPI
86 NTSTATUS
87 NTAPI
88 NtCreateFile(PHANDLE FileHandle,
89     ACCESS_MASK DesiredAccess,
90     POBJECT_ATTRIBUTES ObjectAttributes,
91     PIO_STATUS_BLOCK IoStatusBlock,
92     PLARGE_INTEGER AllocationSize OPTIONAL,
93     ULONG FileAttributes,
94     ULONG ShareAccess,
95     ULONG CreateDisposition,
96     ULONG CreateOptions,
97     PVOID EaBuffer OPTIONAL,
98     ULONG EaLength);
99
100
101 NTSYSAPI
102 NTSTATUS
103 NTAPI
104 NtDeviceIoControlFile(
105     IN HANDLE  FileHandle,
106     IN HANDLE  Event,
107     IN PIO_APC_ROUTINE  ApcRoutine,
108     IN PVOID  ApcContext,
109     OUT PIO_STATUS_BLOCK  IoStatusBlock,
110     IN ULONG  IoControlCode,
111     IN PVOID  InputBuffer,
112     IN ULONG  InputBufferLength,
113     OUT PVOID  OutputBuffer,
114     OUT ULONG  OutputBufferLength
115     ); 
116
117 NTSYSAPI
118 NTSTATUS
119 NTAPI
120 NtFsControlFile(
121     IN HANDLE FileHandle,
122     IN HANDLE Event OPTIONAL,
123     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
124     IN PVOID ApcContext OPTIONAL,
125     OUT PIO_STATUS_BLOCK IoStatusBlock,
126     IN ULONG FsControlCode,
127     IN PVOID InputBuffer OPTIONAL,
128     IN ULONG InputBufferLength,
129     OUT PVOID OutputBuffer OPTIONAL,
130     IN ULONG OutputBufferLength
131 );
132
133
134 NTSYSAPI
135 NTSTATUS
136 NTAPI
137 NtQueryInformationFile(
138     IN HANDLE  FileHandle,
139     OUT PIO_STATUS_BLOCK  IoStatusBlock,
140     OUT PVOID  FileInformation,
141     IN ULONG  Length,
142     IN FILE_INFORMATION_CLASS  FileInformationClass
143     );
144
145 //
146 // Random routines ...
147 //
148
149 NTSYSAPI
150 ULONG
151 NTAPI
152 RtlRandom(
153     IN OUT PULONG  Seed
154     ); 
155
156 /*
157  * Time routines ...
158  */
159
160 NTSYSAPI
161 CCHAR
162 NTAPI
163 NtQuerySystemTime(
164     OUT PLARGE_INTEGER  CurrentTime
165     );
166
167
168 NTSYSAPI
169 BOOLEAN
170 NTAPI
171 RtlTimeToSecondsSince1970(
172     IN PLARGE_INTEGER  Time,
173     OUT PULONG  ElapsedSeconds
174     );
175
176
177 NTSYSAPI
178 VOID
179 NTAPI
180 RtlSecondsSince1970ToTime(
181     IN ULONG  ElapsedSeconds,
182     OUT PLARGE_INTEGER  Time
183     );
184
185 NTSYSAPI
186 NTSTATUS
187 NTAPI
188 ZwDelayExecution(
189     IN BOOLEAN Alertable,
190     IN PLARGE_INTEGER Interval
191 );
192
193
194 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
195 {
196     NTSTATUS status;
197     LARGE_INTEGER Interval;
198     Interval.QuadPart = rqtp->tv_sec * 10000000 + rqtp->tv_nsec / 100;
199     status = ZwDelayExecution(TRUE, &Interval);
200     if (rmtp) {
201         rmtp->tv_sec = 0;
202         rmtp->tv_nsec = 0;
203     }
204     if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
205        return -1;
206     }
207     return 0;
208 }
209
210
211 void cfs_gettimeofday(struct timeval *tv)
212 {
213     LARGE_INTEGER Time;
214
215     NtQuerySystemTime(&Time);
216
217     tv->tv_sec  = (long_ptr_t)  (Time.QuadPart / 10000000);
218     tv->tv_usec = (suseconds_t) (Time.QuadPart % 10000000) / 10;
219 }
220
221 int gettimeofday(struct timeval *tv, void * tz)
222 {
223     cfs_gettimeofday(tv);
224     return 0;
225 }
226
227 /*
228  * proc process routines of user space
229  */
230
231 struct idr_context *cfs_proc_idp = NULL;
232
233 int cfs_proc_open (char * filename, int oflag)
234 {
235     NTSTATUS            status;
236     IO_STATUS_BLOCK     iosb;
237     int                 rc = 0;
238
239     HANDLE              Handle = INVALID_HANDLE_VALUE;
240     OBJECT_ATTRIBUTES   ObjectAttributes;
241     ACCESS_MASK         DesiredAccess;
242     ULONG               CreateDisposition;
243     ULONG               ShareAccess;
244     ULONG               CreateOptions;
245     UNICODE_STRING      UnicodeName;
246     USHORT              NameLength;
247
248     PFILE_FULL_EA_INFORMATION Ea = NULL;
249     ULONG               EaLength;
250     PUCHAR              EaBuffer = NULL;
251
252     /* Check the filename: should start with "/proc" or "/dev" */
253     NameLength = (USHORT)strlen(filename);
254     if (NameLength > 0x05) {
255         if (_strnicmp(filename, "/proc/", 6) == 0) {
256             if (NameLength <= 6) {
257                 rc = -EINVAL;
258                 goto errorout;
259             }
260         } else if (_strnicmp(filename, "/dev/", 5) == 0) {
261         } else {
262             rc = -EINVAL;
263             goto errorout;
264         }
265     } else {
266         rc = -EINVAL;
267         goto errorout;
268     }
269
270     /* Analyze the flags settings */
271
272     if (cfs_is_flag_set(oflag, O_WRONLY)) {
273         DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
274         ShareAccess = 0;
275     }  else if (cfs_is_flag_set(oflag, O_RDWR)) {
276         DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
277         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
278     } else {
279         DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
280         ShareAccess = FILE_SHARE_READ;
281     }
282
283     if (cfs_is_flag_set(oflag, O_CREAT)) {
284         if (cfs_is_flag_set(oflag, O_EXCL)) {
285             CreateDisposition = FILE_CREATE;
286             rc = -EINVAL;
287             goto errorout;
288         } else {
289             CreateDisposition = FILE_OPEN_IF;
290         }
291     } else {
292         CreateDisposition = FILE_OPEN;
293     }
294
295     if (cfs_is_flag_set(oflag, O_TRUNC)) {
296         if (cfs_is_flag_set(oflag, O_EXCL)) {
297             CreateDisposition = FILE_OVERWRITE;
298         } else {
299             CreateDisposition = FILE_OVERWRITE_IF;
300         }
301     }
302
303     CreateOptions = 0;
304
305     if (cfs_is_flag_set(oflag, O_DIRECTORY)) {
306         cfs_set_flag(CreateOptions,  FILE_DIRECTORY_FILE);
307     }
308
309     if (cfs_is_flag_set(oflag, O_SYNC)) {
310          cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
311     }
312
313     if (cfs_is_flag_set(oflag, O_DIRECT)) {
314          cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
315     }
316
317     /* Initialize the unicode path name for the specified file */
318     RtlInitUnicodeString(&UnicodeName, LUSTRE_PROC_SYMLNK);
319
320     /* Setup the object attributes structure for the file. */
321     InitializeObjectAttributes(
322             &ObjectAttributes,
323             &UnicodeName,
324             OBJ_CASE_INSENSITIVE,
325             NULL,
326             NULL );
327
328     /* building EA for the proc entry ...  */
329     EaBuffer = malloc(NameLength + sizeof(FILE_FULL_EA_INFORMATION));
330     if (!EaBuffer) {
331         rc = -ENOMEM;
332         goto errorout;
333     }
334     memset(EaBuffer, 0, NameLength + sizeof(FILE_FULL_EA_INFORMATION));
335     Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
336     Ea->NextEntryOffset = 0;
337     Ea->Flags = 0;
338     Ea->EaNameLength = (UCHAR)NameLength;
339     Ea->EaValueLength = 0;
340     RtlCopyMemory(
341         &(Ea->EaName),
342         filename,
343         NameLength + 1
344         );
345     EaLength =  sizeof(FILE_FULL_EA_INFORMATION) - 1 +
346                                 Ea->EaNameLength + 1;
347
348     /* Now to open or create the file now */
349     status = NtCreateFile(
350                 &Handle,
351                 DesiredAccess,
352                 &ObjectAttributes,
353                 &iosb,
354                 0,
355                 FILE_ATTRIBUTE_NORMAL,
356                 ShareAccess,
357                 CreateDisposition,
358                 CreateOptions,
359                 Ea,
360                 EaLength );
361
362     /* Check the returned status of Iosb ... */
363
364     if (!NT_SUCCESS(status)) {
365         rc = cfs_error_code(status);
366         goto errorout;
367     }
368
369 errorout:
370
371     if (Handle) {
372         rc = cfs_idr_get_new(cfs_proc_idp, Handle);
373         if (rc < 0) {
374             NtClose(Handle);
375         }
376     }
377
378     if (EaBuffer) {
379         free(EaBuffer);
380     }
381
382     return rc;
383 }
384
385 int cfs_proc_close(int fd)
386 {
387     HANDLE handle = cfs_idr_find(cfs_proc_idp, fd);
388
389     if (handle) {
390         NtClose(handle);
391     }
392
393     cfs_idr_remove(cfs_proc_idp, fd);
394
395     return 0;
396 }
397
398 int cfs_proc_read_internal(
399     int fd, void *buffer,
400     unsigned int count,
401     unsigned int offlow,
402     unsigned int offhigh
403     )
404 {
405     NTSTATUS            status;
406     IO_STATUS_BLOCK     iosb;
407     LARGE_INTEGER       offset;
408
409     HANDLE handle = cfs_idr_find(cfs_proc_idp, fd);
410     offset.HighPart = offhigh;
411     offset.LowPart  = offlow;
412
413     /* read file data */
414     status = NtReadFile(
415                 handle,
416                 0,
417                 NULL,
418                 NULL,
419                 &iosb,
420                 buffer,
421                 count,
422                 &offset,
423                 NULL);                     
424
425     /* check the return status */
426     if (!NT_SUCCESS(status)) {
427         printf("NtReadFile request failed with status: 0x%0x\n", status);
428         goto errorout;
429     }
430
431 errorout:
432
433     if (NT_SUCCESS(status)) {
434         return (int)(iosb.Information);
435     }
436
437     return cfs_error_code(status);
438 }
439
440 int cfs_proc_read(
441     int fd, void *buffer,
442     unsigned int count
443     )
444 {
445     return cfs_proc_read_internal(fd, buffer, count, 0, 0);
446 }
447
448 int cfs_proc_write_internal(
449     int fd, void *buffer,
450     unsigned int count,
451     unsigned int offlow,
452     unsigned int offhigh
453     )
454 {
455     NTSTATUS            status;
456     IO_STATUS_BLOCK     iosb;
457     LARGE_INTEGER       offset;
458
459     HANDLE handle = cfs_idr_find(cfs_proc_idp, fd);
460     offset.HighPart = offhigh;
461     offset.LowPart = offlow;
462
463     /* write buffer to the opened file */
464     status = NtWriteFile(
465                 handle,
466                 0,
467                 NULL,
468                 NULL,
469                 &iosb,
470                 buffer,
471                 count,
472                 &offset,
473                 NULL);                     
474
475     /* check the return status */
476     if (!NT_SUCCESS(status)) {
477         printf("NtWriteFile request failed 0x%0x\n", status);
478         goto errorout;
479     }
480
481 errorout:
482
483     if (NT_SUCCESS(status)) {
484         return (int)(iosb.Information);
485     }
486
487     return cfs_error_code(status);
488 }
489
490 int cfs_proc_write(
491     int fd, void *buffer,
492     unsigned int count
493     )
494 {
495     return cfs_proc_write_internal(fd, buffer, count, 0, 0);
496 }
497
498 int cfs_proc_ioctl(int fd, int cmd, void *buffer)
499 {
500     PUCHAR          procdat = NULL;
501     CFS_PROC_IOCTL  procctl;
502     ULONG           length = 0;
503     ULONG           extra = 0;
504     int             rc = 0;
505
506     NTSTATUS        status = STATUS_UNSUCCESSFUL;
507     IO_STATUS_BLOCK iosb;
508
509     struct libcfs_ioctl_data * portal = buffer;
510     struct obd_ioctl_data * obd = buffer;
511     struct obd_ioctl_data * data;
512
513     HANDLE handle = cfs_idr_find(cfs_proc_idp, fd);
514 #if defined(_X86_)
515     CLASSERT(sizeof(struct obd_ioctl_data) == 528);
516 #else
517     CLASSERT(sizeof(struct obd_ioctl_data) == 576);
518 #endif
519     memset(&procctl, 0, sizeof(CFS_PROC_IOCTL));
520     procctl.cmd = cmd;
521
522     if(_IOC_TYPE(cmd) == IOC_LIBCFS_TYPE) {
523         length = portal->ioc_len;
524     } else if (_IOC_TYPE(cmd) == 'f') {
525         length = obd->ioc_len;
526         extra = cfs_size_round(obd->ioc_plen1) + cfs_size_round(obd->ioc_plen2);
527     } else if(_IOC_TYPE(cmd) == 'u') {
528         length = 4;
529         extra  = 0;
530     } else if(_IOC_TYPE(cmd) == 'i') {
531         length = obd->ioc_len;
532         extra  = 0;
533     } else {
534         printf("cfs_proc_ioctl: un-supported ioctl type ...\n");
535         cfs_enter_debugger();
536         status = STATUS_INVALID_PARAMETER;
537         goto errorout;
538     }
539
540     procctl.len = length + extra;
541     procdat = malloc(length + extra + sizeof(CFS_PROC_IOCTL));
542
543     if (NULL == procdat) {
544         printf("user:winnt-proc:cfs_proc_ioctl: no enough memory ...\n");
545         status = STATUS_INSUFFICIENT_RESOURCES;
546         cfs_enter_debugger();
547         goto errorout;
548     }
549     memset(procdat, 0, length + extra + sizeof(CFS_PROC_IOCTL));
550     memcpy(procdat, &procctl, sizeof(CFS_PROC_IOCTL));
551     memcpy(&procdat[sizeof(CFS_PROC_IOCTL)], buffer, length);
552     length += sizeof(CFS_PROC_IOCTL);
553
554     if (_IOC_TYPE(cmd) == 'f') {
555
556         data  = (struct obd_ioctl_data *) (procdat + sizeof(CFS_PROC_IOCTL));
557         if ( cmd != (ULONG)OBD_IOC_BRW_WRITE  &&
558              cmd != (ULONG)OBD_IOC_BRW_READ ) {
559
560             if (obd->ioc_pbuf1 && data->ioc_plen1) {
561                 data->ioc_pbuf1 = &procdat[length];
562                 memcpy(data->ioc_pbuf1, obd->ioc_pbuf1, obd->ioc_plen1); 
563                 length += cfs_size_round(obd->ioc_plen1);
564             } else {
565                 data->ioc_plen1 = 0;
566                 data->ioc_pbuf1 = NULL;
567             }
568
569             if (obd->ioc_pbuf2 && obd->ioc_plen2) {
570                 data->ioc_pbuf2 = &procdat[length];
571                 memcpy(data->ioc_pbuf2, obd->ioc_pbuf2, obd->ioc_plen2);
572                 length += cfs_size_round(obd->ioc_plen2);
573             } else {
574                 data->ioc_plen2 = 0;
575                 data->ioc_pbuf2 = NULL;
576             }
577                 } else {
578              extra = 0;
579         }
580
581         ASSERT(length == extra + sizeof(CFS_PROC_IOCTL) + data->ioc_len);
582         if (obd_ioctl_is_invalid(obd)) {
583             cfs_enter_debugger();
584         }
585     }
586
587     status = NtDeviceIoControlFile(
588                 handle, NULL, NULL,
589                 NULL, &iosb,
590                 IOCTL_LIBCFS_ENTRY,
591                 procdat, length,
592                 procdat, length );
593
594
595     if (_IOC_TYPE(cmd) == 'f') {
596
597         length = sizeof(CFS_PROC_IOCTL);
598         ASSERT(data  == (struct obd_ioctl_data *) (procdat + sizeof(CFS_PROC_IOCTL)));
599                 if ( cmd != (ULONG)OBD_IOC_BRW_WRITE  &&
600              cmd != (ULONG)OBD_IOC_BRW_READ ) {
601
602             if (obd->ioc_pbuf1) {
603                 ASSERT(obd->ioc_plen1 == data->ioc_plen1);
604                 data->ioc_pbuf1 = &procdat[length];
605                 memcpy(obd->ioc_pbuf1, data->ioc_pbuf1, obd->ioc_plen1);
606                 length += cfs_size_round(obd->ioc_plen1);
607             }
608             if (obd->ioc_pbuf2) {
609                 ASSERT(obd->ioc_plen2 == data->ioc_plen2);
610                 data->ioc_pbuf2 = &procdat[length];
611                 memcpy(obd->ioc_pbuf2, data->ioc_pbuf2, obd->ioc_plen2);
612                 length += cfs_size_round(obd->ioc_plen2);
613             }
614         }
615         data->ioc_inlbuf1 = obd->ioc_inlbuf1;
616         data->ioc_inlbuf2 = obd->ioc_inlbuf2;
617         data->ioc_inlbuf3 = obd->ioc_inlbuf3;
618         data->ioc_inlbuf4 = obd->ioc_inlbuf4;
619         data->ioc_pbuf1   = obd->ioc_pbuf1;
620         data->ioc_pbuf2   = obd->ioc_pbuf2;
621         memcpy(obd, data, obd->ioc_len);
622
623     } else {
624
625         memcpy(buffer, &procdat[sizeof(CFS_PROC_IOCTL)], procctl.len); 
626     }
627
628 errorout:
629
630     if (STATUS_SUCCESS == status) {
631         rc = ((CFS_PROC_IOCTL *)procdat)->rc;
632     } else {
633         rc = cfs_error_code(status);
634     }
635
636     if (procdat) {
637         free(procdat);
638     }
639
640     return rc;
641 }
642
643
644 int cfs_proc_mknod(const char *path, mode_t mode, dev_t dev)
645 {
646     return 0;
647 }
648
649 FILE *cfs_proc_fopen(char *path, char * mode)
650 {
651     int fp = cfs_proc_open(path, O_RDWR);
652     if (fp > 0) {
653         return (FILE *)(LONG_PTR)fp;
654     }
655
656     return NULL;
657 }
658
659 char *cfs_proc_fgets(char * buf, int len, FILE *fp)
660 {
661     int rc = 0;
662
663     if (fp == NULL) {
664         return NULL;
665     }
666
667     rc = cfs_proc_read_internal((int)(LONG_PTR)fp,
668                                 buf, len, -1, 1);
669     if (rc <= 0) {
670         return NULL;
671     }
672
673     return buf;
674 }
675
676 int cfs_proc_fclose(FILE *fp)
677 {
678     if (fp == NULL) {
679         return -1;
680     }
681
682     return cfs_proc_close((int)(LONG_PTR)fp);
683 }
684
685 void cfs_libc_init();
686
687 int
688 libcfs_arch_init(void)
689 {
690     cfs_libc_init();
691     cfs_proc_idp = cfs_idr_init();
692
693     if (cfs_proc_idp) {
694         return 0;
695     }
696
697     return -ENOMEM;
698 }
699
700 void
701 libcfs_arch_cleanup(void)
702 {
703     if (cfs_proc_idp) {
704         cfs_idr_exit(cfs_proc_idp);
705         cfs_proc_idp = NULL;
706     }
707 }
708
709 #endif /* __KERNEL__ */