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