1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=4:tabstop=4:
4 * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
6 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
23 # define DEBUG_SUBSYSTEM S_LNET
25 #include <libcfs/libcfs.h>
27 const CHAR *dos_file_prefix = "\\??\\";
31 * To open or create a file in kernel mode
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
40 * the pointer to the cfs_file_t or NULL if it fails
46 cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
48 cfs_file_t * fp = NULL;
52 OBJECT_ATTRIBUTES ObjectAttributes;
54 IO_STATUS_BLOCK IoStatus;
55 ACCESS_MASK DesiredAccess;
56 ULONG CreateDisposition;
60 USHORT NameLength = 0;
61 USHORT PrefixLength = 0;
63 UNICODE_STRING UnicodeName;
64 PWCHAR UnicodeString = NULL;
67 PUCHAR AnsiString = NULL;
69 /* Analyze the flags settings */
71 if (cfs_is_flag_set(flags, O_WRONLY)) {
72 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
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;
78 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
79 ShareAccess = FILE_SHARE_READ;
82 if (cfs_is_flag_set(flags, O_CREAT)) {
83 if (cfs_is_flag_set(flags, O_EXCL)) {
84 CreateDisposition = FILE_CREATE;
86 CreateDisposition = FILE_OPEN_IF;
89 CreateDisposition = FILE_OPEN;
92 if (cfs_is_flag_set(flags, O_TRUNC)) {
93 if (cfs_is_flag_set(flags, O_EXCL)) {
94 CreateDisposition = FILE_OVERWRITE;
96 CreateDisposition = FILE_OVERWRITE_IF;
102 if (cfs_is_flag_set(flags, O_DIRECTORY)) {
103 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
106 if (cfs_is_flag_set(flags, O_SYNC)) {
107 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
110 if (cfs_is_flag_set(flags, O_DIRECT)) {
111 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
114 /* Initialize the unicode path name for the specified file */
116 NameLength = (USHORT)strlen(name);
118 if (name[0] != '\\') {
119 PrefixLength = (USHORT)strlen(dos_file_prefix);
122 AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
124 if (NULL == AnsiString) {
125 if (err) *err = -ENOMEM;
129 UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
132 if (NULL == UnicodeString) {
133 if (err) *err = -ENOMEM;
134 cfs_free(AnsiString);
139 RtlCopyMemory(&AnsiString[0], dos_file_prefix , PrefixLength);
142 RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
143 NameLength += PrefixLength;
145 AnsiName.MaximumLength = NameLength + 1;
146 AnsiName.Length = NameLength;
147 AnsiName.Buffer = AnsiString;
149 UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
150 UnicodeName.Length = 0;
151 UnicodeName.Buffer = (PWSTR)UnicodeString;
153 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
155 /* Setup the object attributes structure for the file. */
157 InitializeObjectAttributes(
160 OBJ_CASE_INSENSITIVE |
165 /* Now to open or create the file now */
167 Status = ZwCreateFile(
173 FILE_ATTRIBUTE_NORMAL,
180 /* Check the returned status of IoStatus... */
182 if (!NT_SUCCESS(IoStatus.Status)) {
183 *err = cfs_error_code(IoStatus.Status);
184 cfs_free(UnicodeString);
185 cfs_free(AnsiString);
189 /* Allocate the cfs_file_t: libcfs file object */
191 fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
194 Status = ZwClose(FileHandle);
195 ASSERT(NT_SUCCESS(Status));
197 cfs_free(UnicodeString);
198 cfs_free(AnsiString);
202 fp->f_handle = FileHandle;
203 strcpy(fp->f_name, name);
205 fp->f_mode = (mode_t)mode;
209 /* free the memory of temporary name strings */
210 cfs_free(UnicodeString);
211 cfs_free(AnsiString);
219 * To close the opened file and release the filp structure
222 * fp: the pointer of the cfs_file_t strcture
226 * Non-Zero: on failure
232 int cfs_filp_close(cfs_file_t *fp)
237 ASSERT(fp->f_handle != NULL);
239 /* release the file handle */
240 Status = ZwClose(fp->f_handle);
241 ASSERT(NT_SUCCESS(Status));
243 /* free the file flip structure */
251 * To read data from the opened file
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
261 * Actual size read into the buffer in success case
262 * Error code in failure case
268 int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
270 LARGE_INTEGER address;
272 IO_STATUS_BLOCK IoStatus;
276 /* Read data from the file into the specified buffer */
279 address.QuadPart = *pos;
281 address.QuadPart = fp->f_pos;
284 Status = ZwReadFile( fp->f_handle,
294 if (!NT_SUCCESS(IoStatus.Status)) {
295 rc = cfs_error_code(IoStatus.Status);
297 rc = (int)IoStatus.Information;
298 fp->f_pos = address.QuadPart + rc;
311 * To write specified data to the opened file
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
321 * Actual size written into the buffer in success case
322 * Error code in failure case
328 int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
330 LARGE_INTEGER address;
332 IO_STATUS_BLOCK IoStatus;
335 /* Write user specified data into the file */
338 address.QuadPart = *pos;
340 address.QuadPart = fp->f_pos;
343 Status = ZwWriteFile( fp->f_handle,
353 if (!NT_SUCCESS(Status)) {
354 rc = cfs_error_code(Status);
356 rc = (int)IoStatus.Information;
357 fp->f_pos = address.QuadPart + rc;
370 PDEVICE_OBJECT DeviceObject,
374 /* copy the IoStatus result */
375 *Irp->UserIosb = Irp->IoStatus;
377 /* singal the event we set */
378 KeSetEvent(Irp->UserEvent, 0, FALSE);
380 /* free the Irp we allocated */
383 return STATUS_MORE_PROCESSING_REQUIRED;
389 * To sync the dirty data of the file to disk
392 * fp: the pointer of the cfs_file_t strcture
395 * Zero: in success case
396 * Error code: in failure case
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
404 int cfs_filp_fsync(cfs_file_t *fp)
407 PFILE_OBJECT FileObject;
408 PDEVICE_OBJECT DeviceObject;
413 IO_STATUS_BLOCK IoSb;
414 PIO_STACK_LOCATION IrpSp;
416 /* get the FileObject and the DeviceObject */
418 Status = ObReferenceObjectByHandle(
426 if (!NT_SUCCESS(Status)) {
427 return cfs_error_code(Status);
430 DeviceObject = IoGetRelatedDeviceObject(FileObject);
432 /* allocate a new Irp */
434 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
438 ObDereferenceObject(FileObject);
442 /* intialize the event */
443 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
446 Irp->UserEvent = &Event;
447 Irp->UserIosb = &IoSb;
448 Irp->RequestorMode = KernelMode;
450 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
451 Irp->Tail.Overlay.OriginalFileObject = FileObject;
453 /* setup the Irp stack location */
454 IrpSp = IoGetNextIrpStackLocation(Irp);
456 IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
457 IrpSp->DeviceObject = DeviceObject;
458 IrpSp->FileObject = FileObject;
460 IoSetCompletionRoutine(Irp, CompletionRoutine, 0, TRUE, TRUE, TRUE);
463 /* issue the Irp to the underlying file system driver */
464 IoCallDriver(DeviceObject, Irp);
466 /* wait until it is finished */
467 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
469 /* cleanup our reference on it */
470 ObDereferenceObject(FileObject);
472 Status = IoSb.Status;
474 return cfs_error_code(Status);
479 * To increase the reference of the file object
482 * fp: the pointer of the cfs_file_t strcture
485 * Zero: in success case
486 * Non-Zero: in failure case
492 int cfs_get_file(cfs_file_t *fp)
494 InterlockedIncrement(&(fp->f_count));
501 * To decrease the reference of the file object
504 * fp: the pointer of the cfs_file_t strcture
507 * Zero: in success case
508 * Non-Zero: in failure case
514 int cfs_put_file(cfs_file_t *fp)
516 if (InterlockedDecrement(&(fp->f_count)) == 0) {
526 * To query the reference count of the file object
529 * fp: the pointer of the cfs_file_t strcture
532 * the reference count of the file object
538 int cfs_file_count(cfs_file_t *fp)
540 return (int)(fp->f_count);