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