Whamcloud - gitweb
2270771eb1ebd9b71ae0780c0a3709285442872f
[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
43 /*
44  * cfs_filp_open
45  *     To open or create a file in kernel mode
46  *
47  * Arguments:
48  *   name:  name of the file to be opened or created, no dos path prefix
49  *   flags: open/creation attribute options
50  *   mode:  access mode/permission to open or create
51  *   err:   error code
52  *
53  * Return Value:
54  *   the pointer to the cfs_file_t or NULL if it fails
55  *
56  * Notes: 
57  *   N/A
58  */
59
60 cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
61 {
62     cfs_file_t *        fp = NULL;
63
64     NTSTATUS            Status;
65
66     OBJECT_ATTRIBUTES   ObjectAttributes;
67     HANDLE              FileHandle;
68     IO_STATUS_BLOCK     IoStatus;
69     ACCESS_MASK         DesiredAccess;
70     ULONG               CreateDisposition;
71     ULONG               ShareAccess;
72     ULONG               CreateOptions;
73
74     USHORT              NameLength = 0;
75     USHORT              PrefixLength = 0;
76
77     UNICODE_STRING      UnicodeName;
78     PWCHAR              UnicodeString = NULL;
79
80     ANSI_STRING         AnsiName;
81     PUCHAR              AnsiString = NULL;
82
83     /* Analyze the flags settings */
84
85     if (cfs_is_flag_set(flags, O_WRONLY)) {
86         DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
87         ShareAccess = 0;
88     }  else if (cfs_is_flag_set(flags, O_RDWR)) {
89         DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
90         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
91     } else {
92         DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
93         ShareAccess = FILE_SHARE_READ;
94     }
95
96     if (cfs_is_flag_set(flags, O_CREAT)) {
97         if (cfs_is_flag_set(flags, O_EXCL)) {
98             CreateDisposition = FILE_CREATE;
99         } else {
100             CreateDisposition = FILE_OPEN_IF;
101         }
102     } else {
103         CreateDisposition = FILE_OPEN;
104     }
105
106     if (cfs_is_flag_set(flags, O_TRUNC)) {
107         if (cfs_is_flag_set(flags, O_EXCL)) {
108             CreateDisposition = FILE_OVERWRITE;
109         } else {
110             CreateDisposition = FILE_OVERWRITE_IF;
111         }
112     }
113
114     CreateOptions = 0;
115
116     if (cfs_is_flag_set(flags, O_DIRECTORY)) {
117         cfs_set_flag(CreateOptions,  FILE_DIRECTORY_FILE);
118     }
119
120     if (cfs_is_flag_set(flags, O_SYNC)) {
121          cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
122     }
123
124     if (cfs_is_flag_set(flags, O_DIRECT)) {
125          cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
126     }
127
128     /* Initialize the unicode path name for the specified file */
129
130     NameLength = (USHORT)strlen(name);
131
132     if (name[0] != '\\') {
133         PrefixLength = (USHORT)strlen(dos_file_prefix);
134     }
135
136     AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
137                             CFS_ALLOC_ZERO);
138     if (NULL == AnsiString) {
139         if (err) *err = -ENOMEM;
140         return NULL;
141     }
142
143     UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
144                                CFS_ALLOC_ZERO);
145
146     if (NULL == UnicodeString) {
147         if (err) *err = -ENOMEM;
148         cfs_free(AnsiString);
149         return NULL;
150     }
151
152     if (PrefixLength) {
153         RtlCopyMemory(&AnsiString[0], dos_file_prefix , PrefixLength);
154     }
155
156     RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
157     NameLength += PrefixLength;
158
159     AnsiName.MaximumLength = NameLength + 1;
160     AnsiName.Length = NameLength;
161     AnsiName.Buffer = AnsiString;
162
163     UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
164     UnicodeName.Length = 0;
165     UnicodeName.Buffer = (PWSTR)UnicodeString;
166
167     RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
168
169     /* Setup the object attributes structure for the file. */
170
171     InitializeObjectAttributes(
172             &ObjectAttributes,
173             &UnicodeName,
174             OBJ_CASE_INSENSITIVE |
175             OBJ_KERNEL_HANDLE,
176             NULL,
177             NULL );
178
179     /* Now to open or create the file now */
180
181     Status = ZwCreateFile(
182             &FileHandle,
183             DesiredAccess,
184             &ObjectAttributes,
185             &IoStatus,
186             0,
187             FILE_ATTRIBUTE_NORMAL,
188             ShareAccess,
189             CreateDisposition,
190             CreateOptions,
191             NULL,
192             0 );
193
194     /* Check the returned status of IoStatus... */
195
196     if (!NT_SUCCESS(IoStatus.Status)) {
197         *err = cfs_error_code(IoStatus.Status);
198         cfs_free(UnicodeString);
199         cfs_free(AnsiString);
200         return NULL;
201     }
202
203     /* Allocate the cfs_file_t: libcfs file object */
204
205     fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
206
207     if (NULL == fp) {
208         Status = ZwClose(FileHandle);
209         ASSERT(NT_SUCCESS(Status));
210         *err = -ENOMEM;
211         cfs_free(UnicodeString);
212         cfs_free(AnsiString);
213         return NULL;
214     }
215
216     fp->f_handle = FileHandle;
217     strcpy(fp->f_name, name);
218     fp->f_flags = flags;
219     fp->f_mode  = (mode_t)mode;
220     fp->f_count = 1;
221     *err = 0;
222
223     /* free the memory of temporary name strings */
224     cfs_free(UnicodeString);
225     cfs_free(AnsiString);
226
227     return fp;
228 }
229
230
231 /*
232  * cfs_filp_close
233  *     To close the opened file and release the filp structure
234  *
235  * Arguments:
236  *   fp:   the pointer of the cfs_file_t strcture
237  *
238  * Return Value:
239  *   ZERO: on success
240  *   Non-Zero: on failure
241  *
242  * Notes: 
243  *   N/A
244  */
245
246 int cfs_filp_close(cfs_file_t *fp)
247 {
248     NTSTATUS    Status;
249
250     ASSERT(fp != NULL);
251     ASSERT(fp->f_handle != NULL);
252
253     /* release the file handle */
254     Status = ZwClose(fp->f_handle);
255     ASSERT(NT_SUCCESS(Status));
256
257     /* free the file flip structure */
258     cfs_free(fp);
259     return 0;
260 }
261
262
263 /*
264  * cfs_filp_read
265  *     To read data from the opened file
266  *
267  * Arguments:
268  *   fp:   the pointer of the cfs_file_t strcture
269  *   buf:  pointer to the buffer to contain the data
270  *   nbytes: size in bytes to be read from the file
271  *   pos:  offset in file where reading starts, if pos
272  *         NULL, then read from current file offset
273  *
274  * Return Value:
275  *   Actual size read into the buffer in success case
276  *   Error code in failure case
277  *
278  * Notes: 
279  *   N/A
280  */
281
282 int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
283 {
284     LARGE_INTEGER   address;
285     NTSTATUS        Status;
286     IO_STATUS_BLOCK IoStatus;
287
288     int             rc = 0;
289
290     /* Read data from the file into the specified buffer */
291
292     if (pos != NULL) {
293         address.QuadPart = *pos;
294     } else {
295         address.QuadPart = fp->f_pos;
296     }
297
298     Status = ZwReadFile( fp->f_handle,
299                          0,
300                          NULL,
301                          NULL,
302                          &IoStatus,
303                          buf,
304                          nbytes,
305                          &address,
306                          NULL );
307
308     if (!NT_SUCCESS(IoStatus.Status)) {
309         rc = cfs_error_code(IoStatus.Status);
310     } else {
311         rc = (int)IoStatus.Information;
312         fp->f_pos = address.QuadPart + rc;
313  
314         if (pos != NULL) {
315             *pos = fp->f_pos;
316         }   
317     }
318
319     return rc;     
320 }
321
322
323 /*
324  * cfs_filp_wrtie
325  *     To write specified data to the opened file
326  *
327  * Arguments:
328  *   fp:   the pointer of the cfs_file_t strcture
329  *   buf:  pointer to the buffer containing the data
330  *   nbytes: size in bytes to be written to the file
331  *   pos:  offset in file where writing starts, if pos
332  *         NULL, then write to current file offset
333  *
334  * Return Value:
335  *   Actual size written into the buffer in success case
336  *   Error code in failure case
337  *
338  * Notes: 
339  *   N/A
340  */
341
342 int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
343 {
344     LARGE_INTEGER   address;
345     NTSTATUS        Status;
346     IO_STATUS_BLOCK IoStatus;
347     int             rc = 0;
348
349     /* Write user specified data into the file */
350
351     if (pos != NULL) {
352         address.QuadPart = *pos;
353     } else {
354         address.QuadPart = fp->f_pos;
355     }
356
357     Status = ZwWriteFile( fp->f_handle,
358                          0,
359                          NULL,
360                          NULL,
361                          &IoStatus,
362                          buf,
363                          nbytes,
364                          &address,
365                          NULL );
366
367     if (!NT_SUCCESS(Status)) {
368         rc =  cfs_error_code(Status);
369     } else {
370         rc = (int)IoStatus.Information;
371         fp->f_pos = address.QuadPart + rc;
372  
373         if (pos != NULL) {
374             *pos = fp->f_pos;
375         }   
376     }
377
378     return rc;
379 }
380
381
382 NTSTATUS
383 CompletionRoutine(
384     PDEVICE_OBJECT DeviceObject,
385     PIRP Irp,
386     PVOID Context)
387 {
388     /* copy the IoStatus result */
389     *Irp->UserIosb = Irp->IoStatus;
390     
391     /* singal the event we set */
392     KeSetEvent(Irp->UserEvent, 0, FALSE);
393    
394     /* free the Irp we allocated */
395     IoFreeIrp(Irp);
396     
397     return STATUS_MORE_PROCESSING_REQUIRED;
398 }
399
400
401 /*
402  * cfs_filp_fsync
403  *     To sync the dirty data of the file to disk
404  *
405  * Arguments:
406  *   fp: the pointer of the cfs_file_t strcture
407  *
408  * Return Value:
409  *   Zero:  in success case
410  *   Error code: in failure case
411  *
412  * Notes: 
413  *   Nt kernel doesn't export such a routine to flush a file,
414  *   we must allocate our own Irp and issue it to the file
415  *   system driver.
416  */
417
418 int cfs_filp_fsync(cfs_file_t *fp)
419 {
420
421     PFILE_OBJECT            FileObject;
422     PDEVICE_OBJECT          DeviceObject;
423
424     NTSTATUS                Status;
425     PIRP                    Irp;
426     KEVENT                  Event;
427     IO_STATUS_BLOCK         IoSb;
428     PIO_STACK_LOCATION      IrpSp;
429
430     /* get the FileObject and the DeviceObject */
431
432     Status = ObReferenceObjectByHandle(
433                 fp->f_handle,
434                 FILE_WRITE_DATA,
435                 NULL,
436                 KernelMode,
437                 (PVOID*)&FileObject,
438                 NULL );
439
440     if (!NT_SUCCESS(Status)) {
441         return cfs_error_code(Status);
442     }
443
444     DeviceObject = IoGetRelatedDeviceObject(FileObject);
445
446     /* allocate a new Irp */
447
448     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
449
450     if (!Irp) {
451
452         ObDereferenceObject(FileObject);
453         return -ENOMEM;
454     }
455
456     /* intialize the event */
457     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
458
459     /* setup the Irp */
460     Irp->UserEvent = &Event;
461     Irp->UserIosb = &IoSb;
462     Irp->RequestorMode = KernelMode;
463
464     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
465     Irp->Tail.Overlay.OriginalFileObject = FileObject;
466
467     /* setup the Irp stack location */
468     IrpSp = IoGetNextIrpStackLocation(Irp);
469
470     IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
471     IrpSp->DeviceObject = DeviceObject;
472     IrpSp->FileObject = FileObject;
473
474     IoSetCompletionRoutine(Irp, CompletionRoutine, 0, TRUE, TRUE, TRUE);
475
476
477     /* issue the Irp to the underlying file system driver */
478     IoCallDriver(DeviceObject, Irp);
479
480     /* wait until it is finished */
481     KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
482
483     /* cleanup our reference on it */
484     ObDereferenceObject(FileObject);
485
486     Status = IoSb.Status;
487
488     return cfs_error_code(Status);
489 }
490
491 /*
492  * cfs_get_file
493  *     To increase the reference of the file object
494  *
495  * Arguments:
496  *   fp:   the pointer of the cfs_file_t strcture
497  *
498  * Return Value:
499  *   Zero:  in success case
500  *   Non-Zero: in failure case
501  *
502  * Notes: 
503  *   N/A
504  */
505
506 int cfs_get_file(cfs_file_t *fp)
507 {
508     InterlockedIncrement(&(fp->f_count));
509     return 0;
510 }
511
512
513 /*
514  * cfs_put_file
515  *     To decrease the reference of the file object
516  *
517  * Arguments:
518  *   fp:   the pointer of the cfs_file_t strcture
519  *
520  * Return Value:
521  *   Zero:  in success case
522  *   Non-Zero: in failure case
523  *
524  * Notes: 
525  *   N/A
526  */
527
528 int cfs_put_file(cfs_file_t *fp)
529 {
530     if (InterlockedDecrement(&(fp->f_count)) == 0) {
531         cfs_filp_close(fp);
532     }
533
534     return 0;
535 }
536
537
538 /*
539  * cfs_file_count
540  *   To query the reference count of the file object
541  *
542  * Arguments:
543  *   fp:   the pointer of the cfs_file_t strcture
544  *
545  * Return Value:
546  *   the reference count of the file object
547  *
548  * Notes: 
549  *   N/A
550  */
551
552 int cfs_file_count(cfs_file_t *fp)
553 {
554     return (int)(fp->f_count);
555 }