1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 # define DEBUG_SUBSYSTEM S_LNET
39 #include <libcfs/libcfs.h>
41 const CHAR *dos_file_prefix = "\\??\\";
45 * To open or create a file in kernel mode
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
54 * the pointer to the cfs_file_t or NULL if it fails
60 cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
62 cfs_file_t * fp = NULL;
66 OBJECT_ATTRIBUTES ObjectAttributes;
68 IO_STATUS_BLOCK IoStatus;
69 ACCESS_MASK DesiredAccess;
70 ULONG CreateDisposition;
74 USHORT NameLength = 0;
75 USHORT PrefixLength = 0;
77 UNICODE_STRING UnicodeName;
78 PWCHAR UnicodeString = NULL;
81 PUCHAR AnsiString = NULL;
83 /* Analyze the flags settings */
85 if (cfs_is_flag_set(flags, O_WRONLY)) {
86 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
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;
92 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
93 ShareAccess = FILE_SHARE_READ;
96 if (cfs_is_flag_set(flags, O_CREAT)) {
97 if (cfs_is_flag_set(flags, O_EXCL)) {
98 CreateDisposition = FILE_CREATE;
100 CreateDisposition = FILE_OPEN_IF;
103 CreateDisposition = FILE_OPEN;
106 if (cfs_is_flag_set(flags, O_TRUNC)) {
107 if (cfs_is_flag_set(flags, O_EXCL)) {
108 CreateDisposition = FILE_OVERWRITE;
110 CreateDisposition = FILE_OVERWRITE_IF;
116 if (cfs_is_flag_set(flags, O_DIRECTORY)) {
117 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
120 if (cfs_is_flag_set(flags, O_SYNC)) {
121 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
124 if (cfs_is_flag_set(flags, O_DIRECT)) {
125 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
128 /* Initialize the unicode path name for the specified file */
130 NameLength = (USHORT)strlen(name);
132 if (name[0] != '\\') {
133 PrefixLength = (USHORT)strlen(dos_file_prefix);
136 AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
138 if (NULL == AnsiString) {
139 if (err) *err = -ENOMEM;
143 UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
146 if (NULL == UnicodeString) {
147 if (err) *err = -ENOMEM;
148 cfs_free(AnsiString);
153 RtlCopyMemory(&AnsiString[0], dos_file_prefix , PrefixLength);
156 RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
157 NameLength += PrefixLength;
159 AnsiName.MaximumLength = NameLength + 1;
160 AnsiName.Length = NameLength;
161 AnsiName.Buffer = AnsiString;
163 UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
164 UnicodeName.Length = 0;
165 UnicodeName.Buffer = (PWSTR)UnicodeString;
167 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
169 /* Setup the object attributes structure for the file. */
171 InitializeObjectAttributes(
174 OBJ_CASE_INSENSITIVE |
179 /* Now to open or create the file now */
181 Status = ZwCreateFile(
187 FILE_ATTRIBUTE_NORMAL,
194 /* Check the returned status of IoStatus... */
196 if (!NT_SUCCESS(IoStatus.Status)) {
197 *err = cfs_error_code(IoStatus.Status);
198 cfs_free(UnicodeString);
199 cfs_free(AnsiString);
203 /* Allocate the cfs_file_t: libcfs file object */
205 fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
208 Status = ZwClose(FileHandle);
209 ASSERT(NT_SUCCESS(Status));
211 cfs_free(UnicodeString);
212 cfs_free(AnsiString);
216 fp->f_handle = FileHandle;
217 strcpy(fp->f_name, name);
219 fp->f_mode = (mode_t)mode;
223 /* free the memory of temporary name strings */
224 cfs_free(UnicodeString);
225 cfs_free(AnsiString);
233 * To close the opened file and release the filp structure
236 * fp: the pointer of the cfs_file_t strcture
240 * Non-Zero: on failure
246 int cfs_filp_close(cfs_file_t *fp)
251 ASSERT(fp->f_handle != NULL);
253 /* release the file handle */
254 Status = ZwClose(fp->f_handle);
255 ASSERT(NT_SUCCESS(Status));
257 /* free the file flip structure */
265 * To read data from the opened file
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
275 * Actual size read into the buffer in success case
276 * Error code in failure case
282 int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
284 LARGE_INTEGER address;
286 IO_STATUS_BLOCK IoStatus;
290 /* Read data from the file into the specified buffer */
293 address.QuadPart = *pos;
295 address.QuadPart = fp->f_pos;
298 Status = ZwReadFile( fp->f_handle,
308 if (!NT_SUCCESS(IoStatus.Status)) {
309 rc = cfs_error_code(IoStatus.Status);
311 rc = (int)IoStatus.Information;
312 fp->f_pos = address.QuadPart + rc;
325 * To write specified data to the opened file
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
335 * Actual size written into the buffer in success case
336 * Error code in failure case
342 int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
344 LARGE_INTEGER address;
346 IO_STATUS_BLOCK IoStatus;
349 /* Write user specified data into the file */
352 address.QuadPart = *pos;
354 address.QuadPart = fp->f_pos;
357 Status = ZwWriteFile( fp->f_handle,
367 if (!NT_SUCCESS(Status)) {
368 rc = cfs_error_code(Status);
370 rc = (int)IoStatus.Information;
371 fp->f_pos = address.QuadPart + rc;
384 PDEVICE_OBJECT DeviceObject,
388 /* copy the IoStatus result */
389 *Irp->UserIosb = Irp->IoStatus;
391 /* singal the event we set */
392 KeSetEvent(Irp->UserEvent, 0, FALSE);
394 /* free the Irp we allocated */
397 return STATUS_MORE_PROCESSING_REQUIRED;
403 * To sync the dirty data of the file to disk
406 * fp: the pointer of the cfs_file_t strcture
409 * Zero: in success case
410 * Error code: in failure case
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
418 int cfs_filp_fsync(cfs_file_t *fp)
421 PFILE_OBJECT FileObject;
422 PDEVICE_OBJECT DeviceObject;
427 IO_STATUS_BLOCK IoSb;
428 PIO_STACK_LOCATION IrpSp;
430 /* get the FileObject and the DeviceObject */
432 Status = ObReferenceObjectByHandle(
440 if (!NT_SUCCESS(Status)) {
441 return cfs_error_code(Status);
444 DeviceObject = IoGetRelatedDeviceObject(FileObject);
446 /* allocate a new Irp */
448 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
452 ObDereferenceObject(FileObject);
456 /* intialize the event */
457 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
460 Irp->UserEvent = &Event;
461 Irp->UserIosb = &IoSb;
462 Irp->RequestorMode = KernelMode;
464 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
465 Irp->Tail.Overlay.OriginalFileObject = FileObject;
467 /* setup the Irp stack location */
468 IrpSp = IoGetNextIrpStackLocation(Irp);
470 IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
471 IrpSp->DeviceObject = DeviceObject;
472 IrpSp->FileObject = FileObject;
474 IoSetCompletionRoutine(Irp, CompletionRoutine, 0, TRUE, TRUE, TRUE);
477 /* issue the Irp to the underlying file system driver */
478 IoCallDriver(DeviceObject, Irp);
480 /* wait until it is finished */
481 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
483 /* cleanup our reference on it */
484 ObDereferenceObject(FileObject);
486 Status = IoSb.Status;
488 return cfs_error_code(Status);
493 * To increase the reference of the file object
496 * fp: the pointer of the cfs_file_t strcture
499 * Zero: in success case
500 * Non-Zero: in failure case
506 int cfs_get_file(cfs_file_t *fp)
508 InterlockedIncrement(&(fp->f_count));
515 * To decrease the reference of the file object
518 * fp: the pointer of the cfs_file_t strcture
521 * Zero: in success case
522 * Non-Zero: in failure case
528 int cfs_put_file(cfs_file_t *fp)
530 if (InterlockedDecrement(&(fp->f_count)) == 0) {
540 * To query the reference count of the file object
543 * fp: the pointer of the cfs_file_t strcture
546 * the reference count of the file object
552 int cfs_file_count(cfs_file_t *fp)
554 return (int)(fp->f_count);