Whamcloud - gitweb
b=17167 libcfs: ensure all libcfs exported symbols to have cfs_ prefix
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-fs.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
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  2008 Sun Microsystems, Inc. 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 #include <libcfs/libcfs.h>
40
41 const CHAR *dos_file_prefix[] = {
42             "\\??\\", "\\DosDevices\\",
43             "\\SystemRoot\\", NULL};
44
45 /*
46  * cfs_filp_open
47  *     To open or create a file in kernel mode
48  *
49  * Arguments:
50  *   name:  name of the file to be opened or created, no dos path prefix
51  *   flags: open/creation attribute options
52  *   mode:  access mode/permission to open or create
53  *   err:   error code
54  *
55  * Return Value:
56  *   the pointer to the cfs_file_t or NULL if it fails
57  *
58  * Notes: 
59  *   N/A
60  */
61
62 #define is_drv_letter_valid(x) (((x) >= 0 && (x) <= 9) || \
63                 ( ((x)|0x20) <= 'z' && ((x)|0x20) >= 'a'))
64
65 cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
66 {
67     cfs_file_t *        fp = NULL;
68
69     NTSTATUS            Status;
70
71     OBJECT_ATTRIBUTES   ObjectAttributes;
72     HANDLE              FileHandle;
73     IO_STATUS_BLOCK     IoStatus;
74     ACCESS_MASK         DesiredAccess;
75     ULONG               CreateDisposition;
76     ULONG               ShareAccess;
77     ULONG               CreateOptions;
78
79     USHORT              NameLength = 0;
80     USHORT              PrefixLength = 0;
81
82     UNICODE_STRING      UnicodeName;
83     PWCHAR              UnicodeString = NULL;
84
85     ANSI_STRING         AnsiName;
86     PUCHAR              AnsiString = NULL;
87
88     /* Analyze the flags settings */
89     if (cfs_is_flag_set(flags, O_WRONLY)) {
90         DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
91         ShareAccess = 0;
92     }  else if (cfs_is_flag_set(flags, O_RDWR)) {
93         DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
94         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
95     } else {
96         DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
97         ShareAccess = FILE_SHARE_READ;
98     }
99
100     if (cfs_is_flag_set(flags, O_CREAT)) {
101         if (cfs_is_flag_set(flags, O_EXCL)) {
102             CreateDisposition = FILE_CREATE;
103         } else {
104             CreateDisposition = FILE_OPEN_IF;
105         }
106     } else {
107         CreateDisposition = FILE_OPEN;
108     }
109
110     if (cfs_is_flag_set(flags, O_TRUNC)) {
111         if (cfs_is_flag_set(flags, O_EXCL)) {
112             CreateDisposition = FILE_OVERWRITE;
113         } else {
114             CreateDisposition = FILE_OVERWRITE_IF;
115         }
116     }
117
118     CreateOptions = 0;
119
120     if (cfs_is_flag_set(flags, O_DIRECTORY)) {
121         cfs_set_flag(CreateOptions,  FILE_DIRECTORY_FILE);
122     }
123
124     if (cfs_is_flag_set(flags, O_SYNC)) {
125          cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
126     }
127
128     if (cfs_is_flag_set(flags, O_DIRECT)) {
129          cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
130     }
131
132     /* Initialize the unicode path name for the specified file */
133     NameLength = (USHORT)strlen(name);
134
135     /* Check file & path name */
136     if (name[0] != '\\') {
137         if (NameLength < 1 || name[1] != ':' || !is_drv_letter_valid(name[0])) {
138             /* invalid file path name */
139             if (err) *err = -EINVAL;
140             return NULL;
141         }
142         PrefixLength = (USHORT)strlen(dos_file_prefix[0]);
143     } else {
144         int i, j;
145         for (i=0; i < 3 && dos_file_prefix[i] != NULL; i++) {
146             j = strlen(dos_file_prefix[i]);
147             if (NameLength > j && _strnicmp(dos_file_prefix[i], name, j) == 0) {
148                 break;
149             }
150         }
151         if (i >= 3) {
152             if (err) *err = -EINVAL;
153             return NULL;
154         }
155     }
156
157     AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
158                             CFS_ALLOC_ZERO);
159     if (NULL == AnsiString) {
160         if (err) *err = -ENOMEM;
161         return NULL;
162     }
163
164     UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
165                                CFS_ALLOC_ZERO);
166     if (NULL == UnicodeString) {
167         if (err) *err = -ENOMEM;
168         cfs_free(AnsiString);
169         return NULL;
170     }
171
172     if (PrefixLength) {
173         RtlCopyMemory(&AnsiString[0], dos_file_prefix[0], PrefixLength);
174     }
175
176     RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
177     NameLength += PrefixLength;
178
179     AnsiName.MaximumLength = NameLength + 1;
180     AnsiName.Length = NameLength;
181     AnsiName.Buffer = AnsiString;
182
183     UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
184     UnicodeName.Length = 0;
185     UnicodeName.Buffer = (PWSTR)UnicodeString;
186
187     RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
188
189     /* Setup the object attributes structure for the file. */
190     InitializeObjectAttributes(
191             &ObjectAttributes,
192             &UnicodeName,
193             OBJ_CASE_INSENSITIVE |
194             OBJ_KERNEL_HANDLE,
195             NULL,
196             NULL );
197
198     /* Now to open or create the file now */
199     Status = ZwCreateFile(
200             &FileHandle,
201             DesiredAccess,
202             &ObjectAttributes,
203             &IoStatus,
204             0,
205             FILE_ATTRIBUTE_NORMAL,
206             ShareAccess,
207             CreateDisposition,
208             CreateOptions,
209             NULL,
210             0 );
211
212     /* Check the returned status of IoStatus... */
213     if (!NT_SUCCESS(IoStatus.Status)) {
214         if (err) {
215             *err = cfs_error_code(IoStatus.Status);
216         }
217         cfs_free(UnicodeString);
218         cfs_free(AnsiString);
219         return NULL;
220     }
221
222     /* Allocate the cfs_file_t: libcfs file object */
223     fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
224
225     if (NULL == fp) {
226         Status = ZwClose(FileHandle);
227         ASSERT(NT_SUCCESS(Status));
228         if (err) {
229             *err = -ENOMEM;
230         }
231         cfs_free(UnicodeString);
232         cfs_free(AnsiString);
233         return NULL;
234     }
235
236     fp->f_handle = FileHandle;
237     strcpy(fp->f_name, name);
238     fp->f_flags = flags;
239     fp->f_mode  = (mode_t)mode;
240     fp->f_count = 1;
241     if (err) {
242         *err = 0;
243     }
244
245     /* free the memory of temporary name strings */
246     cfs_free(UnicodeString);
247     cfs_free(AnsiString);
248
249     return fp;
250 }
251
252
253 /*
254  * cfs_filp_close
255  *     To close the opened file and release the filp structure
256  *
257  * Arguments:
258  *   fp:   the pointer of the cfs_file_t strcture
259  *
260  * Return Value:
261  *   ZERO: on success
262  *   Non-Zero: on failure
263  *
264  * Notes: 
265  *   N/A
266  */
267
268 int cfs_filp_close(cfs_file_t *fp)
269 {
270     NTSTATUS    Status;
271
272     ASSERT(fp != NULL);
273     ASSERT(fp->f_handle != NULL);
274
275     /* release the file handle */
276     Status = ZwClose(fp->f_handle);
277     ASSERT(NT_SUCCESS(Status));
278
279     /* free the file flip structure */
280     cfs_free(fp);
281     return 0;
282 }
283
284
285 NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
286 {
287     /* copy the IoStatus result */
288     if (Irp->UserIosb)
289         *Irp->UserIosb = Irp->IoStatus;
290     
291     /* singal the event we set */
292     KeSetEvent((PKEVENT) Context, 0, FALSE);
293    
294     /* free the Irp we allocated */
295     IoFreeIrp(Irp);
296     
297     return STATUS_MORE_PROCESSING_REQUIRED;
298 }
299
300
301 NTSTATUS cfs_nt_filp_io(HANDLE Handle, BOOLEAN Writing, PLARGE_INTEGER Offset,
302                         ULONG Length,  PUCHAR Buffer,   PULONG Bytes)
303 {
304     NTSTATUS                status;
305     IO_STATUS_BLOCK         iosb;
306
307     PIRP                    irp = NULL;
308     PIO_STACK_LOCATION      irpSp = NULL;
309
310     PFILE_OBJECT            fileObject = NULL;
311     PDEVICE_OBJECT          deviceObject;
312
313     KEVENT                  event;
314
315     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
316
317     status = ObReferenceObjectByHandle( Handle,
318                                         Writing ? FILE_WRITE_DATA : 
319                                                   FILE_READ_DATA,
320                                         *IoFileObjectType,
321                                         KernelMode,
322                                         (PVOID *) &fileObject,
323                                         NULL );
324     if (!NT_SUCCESS(status)) {
325         goto errorout;
326     }
327
328     /* query the DeviceObject in case no input */
329     deviceObject = IoGetBaseFileSystemDeviceObject(fileObject);
330
331
332     /* allocate our own irp */
333     irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
334     if (NULL == irp) {
335         status = STATUS_INSUFFICIENT_RESOURCES;
336         goto errorout;
337     }
338
339     irp->Tail.Overlay.OriginalFileObject = fileObject;
340     irp->Tail.Overlay.Thread = PsGetCurrentThread();
341     irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
342     irp->PendingReturned = FALSE;
343     irp->Cancel = FALSE;
344     irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
345     irp->RequestorMode = KernelMode;
346     irp->UserIosb = &iosb;
347
348     /* set up the next I/O stack location. */
349     irpSp = (PIO_STACK_LOCATION)IoGetNextIrpStackLocation(irp);
350     irpSp->MajorFunction = Writing ? IRP_MJ_WRITE : IRP_MJ_READ;
351     irpSp->FileObject = fileObject;
352     irpSp->DeviceObject = deviceObject;
353
354     if (deviceObject->Flags & DO_BUFFERED_IO) {
355         irp->AssociatedIrp.SystemBuffer = Buffer;
356         irp->UserBuffer = Buffer;
357         irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
358                                IRP_INPUT_OPERATION);
359     } else if (deviceObject->Flags & DO_DIRECT_IO) {
360
361         PMDL mdl = NULL;
362
363         mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, irp);
364         if (mdl == NULL) {
365             KsPrint((0, "cfs_nt_filp_io: failed to allocate MDL for %wZ .\n",
366                         &fileObject->FileName));
367             status = STATUS_INSUFFICIENT_RESOURCES;
368             goto errorout;
369         }
370
371         __try {
372             MmProbeAndLockPages(mdl, KernelMode, Writing ? IoReadAccess : IoWriteAccess );
373         } __except(EXCEPTION_EXECUTE_HANDLER) {
374             KsPrint((0, "cfs_nt_filp_io: failed to lock buffer %p for %wZ .\n",
375                         Buffer, &fileObject->FileName));
376             IoFreeMdl(irp->MdlAddress);
377             irp->MdlAddress = NULL;
378             status = STATUS_INSUFFICIENT_RESOURCES;
379         }
380     } else {
381         irp->UserBuffer = Buffer;
382         irp->Flags = 0;
383     }
384
385     if (Writing) {
386         irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
387         irpSp->Parameters.Write.Length = Length;
388         irpSp->Parameters.Write.ByteOffset = *Offset;
389     } else {
390         irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
391         irpSp->Parameters.Read.Length = Length;
392         irpSp->Parameters.Read.ByteOffset = *Offset;
393     }
394
395     /* set the Irp completion routine */
396     IoSetCompletionRoutine( irp, CompletionRoutine, 
397                             &event, TRUE, TRUE, TRUE);
398
399
400     /* issue the irp to the lower layer device */
401     status = IoCallDriver(deviceObject, irp);
402
403     /* Irp is to be cleaned up in the compleiton routine */
404     irp = NULL;
405
406     if (status == STATUS_PENDING) {
407
408         /* we need wait until operation is completed, then we can
409            get the returned status and information length */
410
411         status = KeWaitForSingleObject(
412                     &event,
413                     Executive,
414                     KernelMode,
415                     FALSE,
416                     NULL
417                     );
418         if (NT_SUCCESS(status)) {
419             status = iosb.Status;
420         }
421     }
422
423     if (NT_SUCCESS(status)) {
424         *Bytes = (ULONG)iosb.Information;
425     } else {
426         *Bytes = 0;
427     }
428
429 errorout:
430
431     if (fileObject) {
432         ObDereferenceObject(fileObject);
433     }
434
435     /* free the Irp in error case */
436     if (irp) {
437         IoFreeIrp(irp);
438     }
439
440     return status;
441 }
442
443 /*
444  * cfs_filp_read
445  *     To read data from the opened file
446  *
447  * Arguments:
448  *   fp:   the pointer of the cfs_file_t strcture
449  *   buf:  pointer to the buffer to contain the data
450  *   nbytes: size in bytes to be read from the file
451  *   pos:  offset in file where reading starts, if pos
452  *         NULL, then read from current file offset
453  *
454  * Return Value:
455  *   Actual size read into the buffer in success case
456  *   Error code in failure case
457  *
458  * Notes: 
459  *   N/A
460  */
461
462 int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
463 {
464     LARGE_INTEGER   offset;
465     NTSTATUS        status;
466     int             rc = 0;
467
468     /* Read data from the file into the specified buffer */
469     if (pos != NULL) {
470         offset.QuadPart = *pos;
471     } else {
472         offset.QuadPart = fp->f_pos;
473     }
474
475     status = cfs_nt_filp_io(fp->f_handle, 0, &offset,
476                             nbytes, buf, &rc);
477
478     if (!NT_SUCCESS(status)) {
479         rc = cfs_error_code(status);
480     }
481
482     if (rc > 0) {
483         fp->f_pos = offset.QuadPart + rc;
484         if (pos != NULL)
485             *pos = fp->f_pos;
486     }
487
488     return rc;
489 }
490
491 /*
492  * cfs_filp_wrtie
493  *     To write specified data to the opened file
494  *
495  * Arguments:
496  *   fp:   the pointer of the cfs_file_t strcture
497  *   buf:  pointer to the buffer containing the data
498  *   nbytes: size in bytes to be written to the file
499  *   pos:  offset in file where writing starts, if pos
500  *         NULL, then write to current file offset
501  *
502  * Return Value:
503  *   Actual size written into the buffer in success case
504  *   Error code in failure case
505  *
506  * Notes: 
507  *   N/A
508  */
509
510 int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
511 {
512     LARGE_INTEGER   offset;
513     NTSTATUS        status;
514     int             rc = 0;
515
516     /* Read data from the file into the specified buffer */
517     if (pos != NULL) {
518         offset.QuadPart = *pos;
519     } else {
520         offset.QuadPart = fp->f_pos;
521     }
522
523     status = cfs_nt_filp_io(fp->f_handle, 1, &offset,
524                             nbytes, buf, &rc);
525
526     if (!NT_SUCCESS(status)) {
527         rc = cfs_error_code(status);
528     }
529
530     if (rc > 0) {
531         fp->f_pos = offset.QuadPart + rc;
532         if (pos != NULL)
533             *pos = fp->f_pos;
534     }
535
536     return rc;
537 }
538
539 /*
540  * cfs_filp_fsync
541  *     To sync the dirty data of the file to disk
542  *
543  * Arguments:
544  *   fp: the pointer of the cfs_file_t strcture
545  *
546  * Return Value:
547  *   Zero:  in success case
548  *   Error code: in failure case
549  *
550  * Notes: 
551  *   Nt kernel doesn't export such a routine to flush a file,
552  *   we must allocate our own Irp and issue it to the file
553  *   system driver.
554  */
555
556 int cfs_filp_fsync(cfs_file_t *fp)
557 {
558
559     PFILE_OBJECT            FileObject;
560     PDEVICE_OBJECT          DeviceObject;
561
562     NTSTATUS                Status;
563     PIRP                    Irp;
564     KEVENT                  Event;
565     IO_STATUS_BLOCK         IoSb;
566     PIO_STACK_LOCATION      IrpSp;
567
568     /* get the FileObject and the DeviceObject */
569     Status = ObReferenceObjectByHandle(
570                 fp->f_handle,
571                 FILE_WRITE_DATA,
572                 NULL,
573                 KernelMode,
574                 (PVOID*)&FileObject,
575                 NULL );
576
577     if (!NT_SUCCESS(Status)) {
578         return cfs_error_code(Status);
579     }
580
581     DeviceObject = IoGetRelatedDeviceObject(FileObject);
582
583     /* allocate a new Irp */
584     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
585     if (!Irp) {
586         ObDereferenceObject(FileObject);
587         return -ENOMEM;
588     }
589
590     /* intialize the event */
591     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
592
593     /* setup the Irp */
594     Irp->UserIosb = &IoSb;
595     Irp->RequestorMode = KernelMode;
596
597     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
598     Irp->Tail.Overlay.OriginalFileObject = FileObject;
599
600     /* setup the Irp stack location */
601     IrpSp = IoGetNextIrpStackLocation(Irp);
602
603     IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
604     IrpSp->DeviceObject = DeviceObject;
605     IrpSp->FileObject = FileObject;
606
607     IoSetCompletionRoutine( Irp, CompletionRoutine,
608                             &Event, TRUE, TRUE, TRUE);
609
610
611     /* issue the Irp to the underlying file system driver */
612     IoCallDriver(DeviceObject, Irp);
613
614     /* wait until it is finished */
615     KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
616
617     /* cleanup our reference on it */
618     ObDereferenceObject(FileObject);
619
620     Status = IoSb.Status;
621
622     return cfs_error_code(Status);
623 }
624
625 /*
626  * cfs_get_file
627  *     To increase the reference of the file object
628  *
629  * Arguments:
630  *   fp:   the pointer of the cfs_file_t strcture
631  *
632  * Return Value:
633  *   Zero:  in success case
634  *   Non-Zero: in failure case
635  *
636  * Notes: 
637  *   N/A
638  */
639
640 int cfs_get_file(cfs_file_t *fp)
641 {
642     InterlockedIncrement(&(fp->f_count));
643     return 0;
644 }
645
646
647 /*
648  * cfs_put_file
649  *     To decrease the reference of the file object
650  *
651  * Arguments:
652  *   fp:   the pointer of the cfs_file_t strcture
653  *
654  * Return Value:
655  *   Zero:  in success case
656  *   Non-Zero: in failure case
657  *
658  * Notes: 
659  *   N/A
660  */
661
662 int cfs_put_file(cfs_file_t *fp)
663 {
664     if (InterlockedDecrement(&(fp->f_count)) == 0) {
665         cfs_filp_close(fp);
666     }
667
668     return 0;
669 }
670
671
672 /*
673  * cfs_file_count
674  *   To query the reference count of the file object
675  *
676  * Arguments:
677  *   fp:   the pointer of the cfs_file_t strcture
678  *
679  * Return Value:
680  *   the reference count of the file object
681  *
682  * Notes: 
683  *   N/A
684  */
685
686 int cfs_file_count(cfs_file_t *fp)
687 {
688     return (int)(fp->f_count);
689 }
690
691 struct dentry *dget(struct dentry *de)
692 {
693     if (de) {
694         cfs_atomic_inc(&de->d_count);
695     }
696     return de;
697 }
698
699 void dput(struct dentry *de)
700 {
701     if (!de || cfs_atomic_read(&de->d_count) == 0) {
702         return;
703     }
704     if (cfs_atomic_dec_and_test(&de->d_count)) {
705         cfs_free(de);
706     }
707 }