2 * the regents of the university of michigan
5 * permission is granted to use, copy, create derivative works and
6 * redistribute this software and such derivative works for any purpose,
7 * so long as the name of the university of michigan is not used in
8 * any advertising or publicity pertaining to the use or distribution
9 * of this software without specific, written prior authorization. if
10 * the above copyright notice or any other identification of the
11 * university of michigan is included in any copy of any portion of
12 * this software, then the disclaimer below must also be included.
14 * this software is provided as is, without representation from the
15 * university of michigan as to its fitness for any purpose, and without
16 * warranty by the university of michigan of any kind, either express
17 * or implied, including without limitation the implied warranties of
18 * merchantability and fitness for a particular purpose. the regents
19 * of the university of michigan shall not be liable for any damages,
20 * including special, indirect, incidental, or consequential damages,
21 * with respect to any claim arising out or in connection with the use
22 * of the software, even if it has been or is hereafter advised of the
23 * possibility of such damages.
28 * 03-jun 2005 (eric williams) entered into versioning
31 /* developer: eric williams,
32 * center for information technology integration,
33 * university of michigan, ann arbor
35 * comments: nativeafs@citi.umich.edu
38 #define IRPMJFUNCDESC /* pull in text strings of the names of irp codes */
39 #define RPC_SRV /* which half of the rpc library to use */
51 /* flag pooltag Io(sp)(sp) to check queryinfo requests for buffer overrun */
55 IoAllocateDriverObjectExtension(
56 IN PDRIVER_OBJECT DriverObject,
57 IN PVOID ClientIdentificationAddress,
58 IN ULONG DriverObjectExtensionSize,
59 OUT PVOID *DriverObjectExtension
62 /*** local structs ***/
63 /* represents a specific file */
66 FSRTL_COMMON_FCB_HEADER; /* needed to interface with cache manager, etc. */
67 SECTION_OBJECT_POINTERS sectionPtrs;
68 ERESOURCE _resource; /* pointed to by fcb_header->Resource */
69 ERESOURCE _pagingIoResource;
70 unsigned long fid; /* a courtesy from the userland daemon (a good hash function) */
71 UCHAR delPending; /* 3 types: FIX */
72 struct afs_ccb *ccb_list; /* list of open instances */
73 SHARE_ACCESS share_access; /* common access control */
75 typedef struct afs_fcb afs_fcb_t;
77 /* represents an open instance of a file */
80 struct afs_ccb *next; /* these are chained as siblings, non-circularly */
81 ULONG access; /* how this instance is opened */
82 wchar_t *name; /* ptr to name buffer */
83 UNICODE_STRING str; /* full name struct, for notification fns */
84 FILE_OBJECT *fo; /* can get parent fcb from this */
85 LARGE_INTEGER cookie; /* on enum ops, where we are */
86 wchar_t *filter; /* on enum ops, what we are filtering on */
87 PACCESS_TOKEN token; /* security data of opening app */
88 ULONG attribs; /* is dir, etc. */
90 typedef struct afs_ccb afs_ccb_t;
94 /* use wisely -- should be set by each thread in an arbitrary context */
95 /* here mostly as a development convenience */
96 DEVICE_OBJECT *RdrDevice, *ComDevice;
97 struct AfsRdrExtension *rdrExt;
98 struct ComExtension *comExt;
101 /*** error and return handling ***/
102 /* current code is stable without, but these should wrap all operations */
104 #define EXCEPT(x, y) } except(EXCEPTION_EXECUTE_HANDLER) \
107 rpt4(("exception", "occurred")); \
108 Irp->IoStatus.Status = x; \
109 Irp->IoStatus.Information = y; \
114 #define STATUS(st, in) Irp->IoStatus.Information = (in), Irp->IoStatus.Status = (st)
115 #define SYNC_FAIL(st) \
121 #define SYNC_FAIL2(st, in) \
127 #define SYNC_RET(st) \
133 #define SYNC_RET2(st, in) \
139 #define SYNC_FAIL_RPC_TIMEOUT SYNC_FAIL(STATUS_NETWORK_BUSY)
141 #define LOCK_FCB_LIST FsRtlEnterFileSystem(); ExAcquireFastMutex(&rdrExt->fcbLock);
142 #define UNLOCK_FCB_LIST ExReleaseFastMutex(&rdrExt->fcbLock); FsRtlExitFileSystem();
144 #define LOCK_FCB ExAcquireResourceExclusiveLite(fcb->Resource, TRUE)
145 #define SLOCK_FCB ExAcquireResourceSharedLite(fcb->Resource, TRUE)
146 #define UNLOCK_FCB if (fcb) ExReleaseResourceLite(fcb->Resource)
148 #define LOCK_PAGING_FCB ExAcquireResourceExclusiveLite(fcb->PagingIoResource, TRUE)
149 #define SLOCK_PAGING_FCB ExAcquireResourceSharedLite(fcb->PagingIoResource, TRUE)
150 #define UNLOCK_PAGING_FCB if (fcb) ExReleaseResourceLite(fcb->PagingIoResource)
153 #define AFS_RDR_TAG (0x73666440)//@dfs//0x482ac230//0x3029a4f2
155 #define AFS_FS_NAME L"Andrew File System"
157 #define COMM_IOCTL (void*)0x01
158 #define COMM_DOWNCALL (void*)0x02
159 #define COMM_UPCALLHOOK (void*)0x03
161 /*#define ACC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_LIST_DIRECTORY
162 #define ACC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA)*
165 /* dates from afs are time_t style -- seconds since 1970 */ /* 11644505691.6384 */
166 #define AfsTimeToWindowsTime(x) (((x)+11644505692L)*10000000L) /*(1970L-1601L)*365.242199*24L*3600L)*/
167 #define WindowsTimeToAfsTime(x) ((x)/10000000L-11644505692L) /*(1970L-1601L)*365.242199*24L*3600L)*/
168 #define IsDeviceFile(fo) (!fo->FsContext)
171 /*** auxiliary functions ***/
172 #define COMPLETE_NO_BOOST IoCompleteRequest(Irp, IO_NO_INCREMENT)
173 #define COMPLETE IoCompleteRequest(Irp, IO_NETWORK_INCREMENT)
175 afs_fcb_t *FindFcb(FILE_OBJECT *fo)
178 return fo->FsContext;
182 void *AfsFindBuffer(IRP *Irp)
187 outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
191 outPtr = Irp->AssociatedIrp.SystemBuffer;
195 /* we do Resource locking because we don't want to figure out when to pull MainResource */
196 BOOLEAN lazyWriteLock(PVOID context, BOOLEAN wait)
198 afs_fcb_t *fcb = context;
200 return ExAcquireResourceExclusiveLite(fcb->Resource, wait);
203 void lazyWriteUnlock(PVOID context)
205 afs_fcb_t *fcb = context;
207 ExReleaseResourceLite(fcb->Resource);
210 BOOLEAN readAheadLock(PVOID context, BOOLEAN wait)
212 afs_fcb_t *fcb = context;
214 return ExAcquireResourceSharedLite(fcb->Resource, wait);
217 void readAheadUnlock(PVOID context)
219 afs_fcb_t *fcb = context;
221 ExReleaseResourceLite(fcb->Resource);
224 afs_fcb_t *find_fcb(ULONG fid)
226 afs_fcb_t compare, *compare_ptr, **fcbp;
229 compare_ptr = &compare;
230 fcbp = RtlLookupElementGenericTable(&rdrExt->fcbTable, (void*)&compare_ptr);
238 /**********************************************************
240 * - handle open and create requests
242 * - FsContext of file object points to FCB
243 * - FsContext2 of file object is usermode handle of file instance
244 * - beginning failure codes and conditions came from ifstest
245 **********************************************************/
246 NTSTATUS AfsRdrCreate(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *_fcb)
248 afs_fcb_t *pfcb, *fcb, **fcbp;
249 afs_ccb_t *ccb, *pccb;
252 ULONG fid, access, granted, disp;
253 LARGE_INTEGER size, creation, accesst, change, written, zero;
259 PACCESS_TOKEN acc_token;
261 /* set rpc security context for current thread */
262 acc_token = SeQuerySubjectContextToken(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
264 rpc_set_context(acc_token);
266 /* attempt to open afs volume directly */
267 if (IrpSp->FileObject->FileName.Length == 0)
268 SYNC_FAIL(STATUS_SHARING_VIOLATION);
270 if (IrpSp->FileObject->FileName.Length > MAX_PATH*sizeof(wchar_t))
271 SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
273 if (IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY &&
274 IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE)
275 SYNC_FAIL(STATUS_INVALID_PARAMETER);
277 /* relative opens cannot start with \ */
278 if (IrpSp->FileObject->RelatedFileObject &&
279 IrpSp->FileObject->FileName.Length &&
280 IrpSp->FileObject->FileName.Buffer[0] == L'\\')
281 SYNC_FAIL(STATUS_INVALID_PARAMETER);/*STATUS_OBJECT_PATH_SYNTAX_BAD);*/
283 /* a create request can be relative to a prior file. build filename here */
285 if (IrpSp->FileObject->RelatedFileObject)
286 pccb = IrpSp->FileObject->RelatedFileObject->FsContext2;
287 len = IrpSp->FileObject->FileName.Length + (pccb?wcslen(pccb->name):0)*sizeof(wchar_t) + 6;
288 str = ExAllocatePoolWithTag(NonPagedPool, len, AFS_RDR_TAG);
289 RtlZeroMemory(str, len);
292 StringCbCatN(str, len, IrpSp->FileObject->RelatedFileObject->FileName.Buffer, IrpSp->FileObject->RelatedFileObject->FileName.Length);
293 StringCbCat(str, len, L"\\");
295 StringCbCatN(str, len, IrpSp->FileObject->FileName.Buffer, IrpSp->FileObject->FileName.Length);
297 /* request to open heirarchical parent of specified path */
298 /* remove last path component */
299 if (IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)
308 if (y == x && x != 0)
324 /* first two characters are \%01d . %d is number of path components immediately
325 following that should not be returned in file name queries.
326 EX: \3\mount\path\start\fname.ext is mapped to <driveletter>:\fname.ext */
327 if (wcslen(str) <= 2)
329 ExFreePoolWithTag(str, AFS_RDR_TAG);
330 SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
334 disp = (unsigned char)((IrpSp->Parameters.Create.Options >> 24) & 0xff);
335 access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
336 share = IrpSp->Parameters.Create.ShareAccess;
340 /* check for file existance. we jump to creating it if needed */
341 if (disp == FILE_OPEN || disp == FILE_OPEN_IF || disp == FILE_OVERWRITE ||
342 disp == FILE_OVERWRITE_IF || disp == FILE_SUPERSEDE)
344 /* chop our internal mount flagging from the beginning */
345 status = uc_namei(str+2, &fid);
346 if (status == IFSL_DOES_NOT_EXIST &&
347 (disp == FILE_OPEN_IF ||
348 disp == FILE_OVERWRITE_IF ||
349 disp == FILE_SUPERSEDE))
352 if (status != IFSL_SUCCESS)
354 ExFreePoolWithTag(str, AFS_RDR_TAG);
357 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
358 case IFSL_NO_ACCESS: SYNC_FAIL(STATUS_ACCESS_DENIED);
359 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
360 case IFSL_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_NAME_NOT_FOUND, FILE_DOES_NOT_EXIST);
361 case IFSL_PATH_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_PATH_NOT_FOUND, FILE_DOES_NOT_EXIST);
362 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
366 /* make upcall to get ACL in afs. we specify our requested level to
367 keep it from hitting the network on a public volume. */
368 status = uc_check_access(fid, access, &granted);
369 if (status != IFSL_SUCCESS)
371 ExFreePoolWithTag(str, AFS_RDR_TAG);
374 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
375 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
376 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
380 /* make sure daemon approved access */
381 if ((access & granted) != access)
383 ExFreePoolWithTag(str, AFS_RDR_TAG);
384 SYNC_FAIL(STATUS_ACCESS_DENIED);
387 /* we depend on this information for caching, etc. */
388 status = uc_stat(fid, &attribs, &size, &creation, &accesst, &change, &written);
389 if (status != IFSL_SUCCESS)
391 ExFreePoolWithTag(str, AFS_RDR_TAG);
394 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
395 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
396 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
400 /* afsd does not maintain instance-specific data, so we adjust here */
401 if (granted & FILE_READ_DATA && !(granted & FILE_WRITE_DATA))
402 attribs |= FILE_ATTRIBUTE_READONLY;
404 if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE &&
405 !(attribs & FILE_ATTRIBUTE_DIRECTORY))
407 ExFreePoolWithTag(str, AFS_RDR_TAG);
408 SYNC_FAIL(STATUS_NOT_A_DIRECTORY);
410 if (IrpSp->Parameters.Create.Options & FILE_NON_DIRECTORY_FILE &&
411 attribs & FILE_ATTRIBUTE_DIRECTORY)
413 ExFreePoolWithTag(str, AFS_RDR_TAG);
414 SYNC_FAIL(STATUS_FILE_IS_A_DIRECTORY);
417 /* check for previous open instance(s) of file. it will be in the fcb chain.
418 when we have this locked, we cannot make upcalls -- running at APC_LEVEL.
419 lock here (not later) to prevent possible truncation races. */
428 /* if we found it, check to make sure open disposition and sharing
429 are not in conflict with previous opens. then, make new file
430 instance entry and, if necessary, file entry. */
433 /* file contents cannot be cached for a successful delete */
434 if (access & FILE_WRITE_DATA)
435 if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForWrite))
440 ExFreePoolWithTag(str, AFS_RDR_TAG);
441 SYNC_FAIL(STATUS_SHARING_VIOLATION);
444 if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForWrite))//Delete))
449 ExFreePoolWithTag(str, AFS_RDR_TAG);
450 SYNC_FAIL(STATUS_SHARING_VIOLATION);
453 /* check common sharing flags, but do not change */
454 if (IoCheckShareAccess(access, share, IrpSp->FileObject, &fcb->share_access, FALSE) != STATUS_SUCCESS)
456 rpt0(("create", "sharing violation for %ws", str));
460 ExFreePoolWithTag(str, AFS_RDR_TAG);
461 SYNC_FAIL(STATUS_SHARING_VIOLATION);
466 if (!MmCanFileBeTruncated(&(fcb->sectionPtrs), &zero))
471 ExFreePoolWithTag(str, AFS_RDR_TAG);
472 SYNC_FAIL(STATUS_SHARING_VIOLATION);
476 /* do overwrite/supersede tasks */
477 if (disp == FILE_OVERWRITE ||
478 disp == FILE_OVERWRITE_IF ||
479 disp == FILE_SUPERSEDE)
482 if (fcb && !MmCanFileBeTruncated(&(fcb->sectionPtrs), &zero))
487 ExFreePoolWithTag(str, AFS_RDR_TAG);
488 SYNC_FAIL(STATUS_SHARING_VIOLATION);
490 if (size.QuadPart != 0)
493 status = uc_trunc(fid, size);
494 if (status != IFSL_SUCCESS)
499 ExFreePoolWithTag(str, AFS_RDR_TAG);
500 SYNC_FAIL(STATUS_ACCESS_DENIED);
504 fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size;
505 CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
508 if (Irp->Overlay.AllocationSize.QuadPart)
510 status = uc_trunc(fid, Irp->Overlay.AllocationSize);
511 size = Irp->Overlay.AllocationSize;
512 if (status != IFSL_SUCCESS)
517 ExFreePoolWithTag(str, AFS_RDR_TAG);
518 SYNC_FAIL(STATUS_DISK_FULL);
522 fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size;
523 CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
530 /* make actual change in common sharing flags */
531 IoUpdateShareAccess(IrpSp->FileObject, &fcb->share_access);
539 /* if disposition was to create the file, or its non-existance necessitates this */
541 if (disp == FILE_CREATE ||
542 status == IFSL_DOES_NOT_EXIST && (disp == FILE_OPEN_IF || disp == FILE_OVERWRITE_IF || disp == FILE_SUPERSEDE))
544 attribs = IrpSp->Parameters.Create.FileAttributes;
545 if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE)
546 attribs |= FILE_ATTRIBUTE_DIRECTORY;
547 if (IrpSp->Parameters.Create.Options & FILE_NON_DIRECTORY_FILE)
548 attribs &= ~FILE_ATTRIBUTE_DIRECTORY;
549 status = uc_create(str+2, attribs, Irp->Overlay.AllocationSize, access, &granted, &fid);
550 if (status != IFSL_SUCCESS)
552 ExFreePoolWithTag(str, AFS_RDR_TAG);
555 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
556 case IFSL_NO_ACCESS: SYNC_FAIL(STATUS_ACCESS_DENIED);
557 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
558 case IFSL_PATH_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_PATH_NOT_FOUND, FILE_DOES_NOT_EXIST);
559 case IFSL_OPEN_EXISTS: SYNC_FAIL2(STATUS_OBJECT_NAME_COLLISION, FILE_EXISTS);
560 case IFSL_OVERQUOTA: SYNC_FAIL(STATUS_DISK_FULL);//STATUS_QUOTA_EXCEEDED);
561 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
565 /* lock list like above. check again just to make sure it isn't in the list.
566 if it is, we should process like above. depending on how we follow symlinks
567 (same fid for multiple files), we cannot expect serialized create requests. */
573 if (size.QuadPart != 0)
577 if (status != IFSL_SUCCESS)
580 ExFreePoolWithTag(str, AFS_RDR_TAG);
581 SYNC_FAIL(STATUS_DISK_FULL);
584 if (Irp->Overlay.AllocationSize.QuadPart)
586 uc_trunc(fid, Irp->Overlay.AllocationSize);
587 size = Irp->Overlay.AllocationSize;
588 if (status != IFSL_SUCCESS)
591 ExFreePoolWithTag(str, AFS_RDR_TAG);
592 SYNC_FAIL(STATUS_ACCESS_DENIED);
600 /* OS passed unexpected disposition */
601 ExFreePoolWithTag(str, AFS_RDR_TAG);
602 SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
603 /*SYNC_FAIL2(STATUS_OBJECT_NAME_NOT_FOUND, FILE_DOES_NOT_EXIST);*/
606 /* allocate nonpaged struct to track this file and all open instances */
608 fcb = ExAllocateFromNPagedLookasideList(&rdrExt->fcbMemList);
610 RtlZeroMemory(fcb, sizeof(afs_fcb_t));
614 fcb->ccb_list = NULL;
615 fcb->IsFastIoPossible = FastIoIsNotPossible;
617 ExInitializeResourceLite(&fcb->_resource);
618 ExInitializeResourceLite(&fcb->_pagingIoResource);
619 fcb->Resource = &fcb->_resource;
620 fcb->PagingIoResource = &fcb->_pagingIoResource;
624 fcb->sectionPtrs.DataSectionObject = NULL;
625 fcb->sectionPtrs.SharedCacheMap = NULL;
626 fcb->sectionPtrs.ImageSectionObject = NULL;
627 fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size;
629 IoSetShareAccess(access, share, IrpSp->FileObject, &fcb->share_access);
631 /* we store a pointer to the fcb. the table would want to store a copy otherwise. */
633 RtlInsertElementGenericTable(&rdrExt->fcbTable, fcbp, sizeof(fcbp), NULL);
635 sizes.AllocationSize = sizes.FileSize = sizes.ValidDataLength = size;
636 rpt1(("create", "created size %d name %ws", size.LowPart, str));
638 /* allocate nonpaged struct tracking information specific to (file, open instance) pair,
639 and link from parent. is put at head of parent's list. */
641 /* there are two different types of pending deletes. we return different
642 errors in places depending on a) delete specified on call to open,
643 or b) file specifically deleted */
644 /* need to check for DELETE perms too? */
645 if (IrpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE)
648 ccb = ExAllocateFromNPagedLookasideList(&rdrExt->ccbMemList);
650 ccb->access = granted;
651 ccb->fo = IrpSp->FileObject;
652 ccb->cookie.QuadPart = 0;
654 ccb->attribs = attribs;
656 /* save security context information. we never change this ccb attribute. */
657 ObReferenceObjectByPointer(acc_token, TOKEN_QUERY, NULL, KernelMode);
658 ccb->token = acc_token;
659 /*ObOpenObjectByPointer(acc_token, OBJ_KERNEL_HANDLE, NULL, TOKEN_QUERY, NULL, KernelMode, &ccb->token);*/
669 ccb->next = fcb->ccb_list;
676 /* how we pack (as it is expected): a) fscontext same for all open instances of a file,
677 b) fscontext2 unique among each instance, c) private cache map pointer set by cache
678 manager upon caching, d) so pointers are per-file, as in (a). */
679 IrpSp->FileObject->FsContext = fcb;
680 IrpSp->FileObject->FsContext2 = ccb;
681 IrpSp->FileObject->PrivateCacheMap = NULL;
682 IrpSp->FileObject->SectionObjectPointer = &(fcb->sectionPtrs);
684 /* explicitly start caching on a data file. caching will still happen upon
685 paging i/o even if commented out below. the other option is to cache upon
686 the first read/write operation. that code is also in place. */
687 if (!(attribs & FILE_ATTRIBUTE_DIRECTORY))
689 /*CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);*/
690 /*CcSetAdditionalCacheAttributes(IrpSp->FileObject, TRUE, TRUE);*/
693 /* customize returns; semantics largely derived from output of ifstest.exe */
697 SYNC_FAIL2(STATUS_SUCCESS, FILE_OPENED)
701 SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
703 SYNC_FAIL2(STATUS_SUCCESS, FILE_OPENED)
706 SYNC_FAIL2(STATUS_SUCCESS, FILE_OVERWRITTEN)
708 case FILE_OVERWRITE_IF:
710 SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
712 SYNC_FAIL2(STATUS_SUCCESS, FILE_OVERWRITTEN)
716 SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
718 SYNC_FAIL2(STATUS_SUCCESS, FILE_SUPERSEDED)
721 SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
727 /* experimental; does not work. need to handle filesizes
728 and cache invalidation in more places. */
729 #define EXPLICIT_CACHING
731 /**********************************************************
734 **********************************************************/
735 NTSTATUS AfsRdrRead(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
739 LARGE_INTEGER offset, curroff;
745 ULONG currpos, ttlread, toread;
747 ccb = IrpSp->FileObject->FsContext2;
748 if (IsDeviceFile(IrpSp->FileObject) || (ccb->attribs & FILE_ATTRIBUTE_DIRECTORY))
749 SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
751 /* the second line disables read ahead and write behind. since our data is
752 already cached in userland, and there are read-ahead parameters there,
753 we do not use this service. */
754 #ifdef EXPLICIT_CACHING
755 if (!IrpSp->FileObject->PrivateCacheMap)
757 CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);
758 CcSetAdditionalCacheAttributes(IrpSp->FileObject, FALSE, TRUE);
759 //CcSetReadAheadGranularity
763 if (!(ccb->access & FILE_READ_DATA) && !(Irp->Flags & IRP_PAGING_IO))
764 SYNC_FAIL(STATUS_ACCESS_DENIED);
766 if (!IrpSp->Parameters.Read.Length)
767 SYNC_FAIL(STATUS_SUCCESS);
769 offset = IrpSp->Parameters.Read.ByteOffset;
770 length = IrpSp->Parameters.Read.Length;
772 /* FIX: lock here, before finding end-of-file */
774 /* fast out for reads starting beyond eof */
775 if (offset.QuadPart > fcb->ValidDataLength.QuadPart)
776 SYNC_FAIL(STATUS_END_OF_FILE);
777 /* pre-truncate reads */
778 if (offset.QuadPart + length > fcb->ValidDataLength.QuadPart)
779 length = (ULONG)(fcb->ValidDataLength.QuadPart - offset.QuadPart);
781 outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
783 SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
785 #ifdef EXPLICIT_CACHING
786 if (!(Irp->Flags & (IRP_NOCACHE | IRP_PAGING_IO)))
788 FsRtlEnterFileSystem();
793 if (!CcCopyRead(IrpSp->FileObject, &offset, length, TRUE, outPtr, &Irp->IoStatus))
796 FsRtlExitFileSystem();
797 SYNC_FAIL(STATUS_UNSUCCESSFUL);
799 // KdPrint(("read %x at %x cache done %x\n", length, (ULONG)offset.QuadPart, Irp->IoStatus.Information));
800 ttlread = Irp->IoStatus.Information;
802 except (EXCEPTION_EXECUTE_HANDLER)
804 STATUS(STATUS_UNSUCCESSFUL, 0);
807 FsRtlExitFileSystem();
808 if (Irp->IoStatus.Status == STATUS_UNSUCCESSFUL)
809 SYNC_FAIL(STATUS_UNSUCCESSFUL);
814 FsRtlEnterFileSystem();
816 for (currpos = ttlread = 0; ttlread < length; )
818 toread = length - currpos;
819 toread = (toread > TRANSFER_CHUNK_SIZE) ? TRANSFER_CHUNK_SIZE : toread;
820 curroff.QuadPart = offset.QuadPart + currpos;
821 status = uc_read(fcb->fid, curroff, toread, &read, outPtr);
822 // KdPrint(("read %x at %x done %x\n", length, (ULONG)offset.QuadPart, read));
832 FsRtlExitFileSystem();
835 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
836 case IFSL_IS_A_DIR: SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
837 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
838 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
843 FsRtlExitFileSystem();
846 /* update byteoffset when this is not a paging or async request */
847 if (IoIsOperationSynchronous(Irp) && !(Irp->Flags & IRP_PAGING_IO))
848 IrpSp->FileObject->CurrentByteOffset.QuadPart += ttlread;
850 if (ttlread == 0)//< length)
851 SYNC_FAIL2(STATUS_END_OF_FILE, ttlread)
853 SYNC_FAIL2(STATUS_SUCCESS, ttlread)
858 /**********************************************************
861 **********************************************************/
862 NTSTATUS AfsRdrWrite(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
866 ULONG length, written;
867 LARGE_INTEGER offset, end;
870 CC_FILE_SIZES sizes, oldSizes;
871 ULONG towrite, ttlwritten, currpos;
872 LARGE_INTEGER curroff;
873 BOOLEAN change, paging_lock;
875 ccb = IrpSp->FileObject->FsContext2;
876 if (IsDeviceFile(IrpSp->FileObject) || (ccb->attribs & FILE_ATTRIBUTE_DIRECTORY))
877 SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
879 /* since we will be performing io on this instance, start caching. */
880 #ifdef EXPLICIT_CACHING
881 if (!IrpSp->FileObject->PrivateCacheMap)
883 CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);
884 CcSetAdditionalCacheAttributes(IrpSp->FileObject, FALSE, TRUE);
888 if (!(ccb->access & FILE_WRITE_DATA) && !(Irp->Flags & IRP_PAGING_IO))
889 SYNC_FAIL(STATUS_ACCESS_DENIED);
891 /* fast-out for zero-length i/o */
892 if (!IrpSp->Parameters.Write.Length)
893 SYNC_FAIL(STATUS_SUCCESS);
895 if (IrpSp->Parameters.Write.ByteOffset.HighPart == 0xffffffff &&
896 IrpSp->Parameters.Write.ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE)
897 offset.QuadPart = fcb->FileSize.QuadPart;
899 offset = IrpSp->Parameters.Write.ByteOffset;
900 length = IrpSp->Parameters.Write.Length;
902 if (!(outPtr = AfsFindBuffer(Irp)))
903 SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
905 #ifdef EXPLICIT_CACHING
906 if (!(Irp->Flags & (IRP_NOCACHE | IRP_PAGING_IO)))
908 /* extend file for cached writes */
909 FsRtlEnterFileSystem();
911 if (offset.QuadPart + length > fcb->FileSize.QuadPart)
913 end.QuadPart = offset.QuadPart + length;
914 fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = end;
916 CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
918 /*ret = *//*CcZeroData(IrpSp->FileObject, &oldSizes.FileSize, &end, FALSE);*/ /* should wait? */
922 if (!CcCopyWrite(IrpSp->FileObject, &offset, length, TRUE, outPtr))
923 SYNC_FAIL(STATUS_UNSUCCESSFUL);
925 except (EXCEPTION_EXECUTE_HANDLER)
927 STATUS(STATUS_UNSUCCESSFUL, 0);
929 // KdPrint(("write %x at %x cache done\n", length, (ULONG)offset.QuadPart));
931 FsRtlExitFileSystem();
932 ttlwritten = written = length;
933 if (Irp->IoStatus.Status == STATUS_UNSUCCESSFUL)
934 SYNC_FAIL(STATUS_UNSUCCESSFUL);
939 FsRtlEnterFileSystem();
942 if (offset.QuadPart + length > fcb->FileSize.QuadPart)
946 if (change && !(Irp->Flags & IRP_PAGING_IO))
953 if (offset.QuadPart + length > fcb->FileSize.QuadPart)
955 if (Irp->Flags & IRP_PAGING_IO)
957 /* the input buffer and length is for a full page. ignore this. */
958 if (offset.QuadPart > fcb->FileSize.QuadPart)
966 FsRtlExitFileSystem();
967 SYNC_FAIL2(STATUS_SUCCESS, length);
969 length = (ULONG)(fcb->FileSize.QuadPart - offset.QuadPart);
989 end.QuadPart = offset.QuadPart + length;
990 fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = end;
991 CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
1006 for (currpos = ttlwritten = 0; ttlwritten < length; )
1008 towrite = length - currpos;
1009 towrite = (towrite > TRANSFER_CHUNK_SIZE) ? TRANSFER_CHUNK_SIZE : towrite;
1010 curroff.QuadPart = offset.QuadPart + currpos;
1011 status = uc_write(fcb->fid, curroff, towrite, &written, outPtr);
1012 // KdPrint(("write %x at %x done\n", length, (ULONG)offset.QuadPart));
1015 ttlwritten += written;
1017 if (written < towrite)
1022 FsRtlExitFileSystem();
1025 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
1026 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
1027 case IFSL_OVERQUOTA: SYNC_FAIL(STATUS_DISK_FULL);
1028 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
1033 FsRtlExitFileSystem();
1036 if (IoIsOperationSynchronous(Irp) && !(Irp->Flags & IRP_PAGING_IO))
1037 IrpSp->FileObject->CurrentByteOffset.QuadPart += ttlwritten;
1039 /* if we failed a write, we would not be here. so, we must
1040 tell the vmm that all data was written. */
1041 if (Irp->Flags & IRP_PAGING_IO)
1042 SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.Write.Length)
1043 SYNC_FAIL2(STATUS_SUCCESS, ttlwritten)
1047 wchar_t *SEARCH_MATCH_ALL = L"**";
1049 /**********************************************************
1051 * - handle directory notification callbacks
1052 * - handle directory enumeration
1053 **********************************************************/
1054 NTSTATUS AfsRdrDirCtrl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1056 struct EnumDirKOut *p;
1057 LARGE_INTEGER size, creation, access, change, written;
1058 ULONG attribs, count;
1061 void *outPtr, *info, *pre_adj_info;
1062 FILE_BOTH_DIR_INFORMATION *info_both, *info_both_prev;
1063 FILE_DIRECTORY_INFORMATION *info_dir, *info_dir_prev;
1064 FILE_NAMES_INFORMATION *info_names, *info_names_prev;
1068 LARGE_INTEGER last_cookie;
1071 FILE_NOTIFY_INFORMATION *notify;
1073 if (IsDeviceFile(IrpSp->FileObject))
1074 SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
1076 if (IrpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
1078 ccb = IrpSp->FileObject->FsContext2;
1079 ccb->str.Length = wcslen(ccb->name)*sizeof(wchar_t);
1080 ccb->str.MaximumLength = ccb->str.Length + sizeof(wchar_t);
1081 ccb->str.Buffer = ccb->name;
1083 FsRtlEnterFileSystem();
1084 LOCK_FCB; /* FIX: shared lock? */
1085 FsRtlNotifyFullChangeDirectory(rdrExt->notifyList, &rdrExt->listHead,
1088 IrpSp->Flags & SL_WATCH_TREE,
1090 /*FILE_NOTIFY_CHANGE_FILE_NAME,*/IrpSp->Parameters.NotifyDirectory.CompletionFilter,
1093 FsRtlExitFileSystem();
1094 /* do NOT complete request; that will be done by fsrtlnotify functions */
1095 return STATUS_PENDING;
1098 if (IrpSp->MinorFunction != IRP_MN_QUERY_DIRECTORY)
1099 SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
1101 if (IrpSp->Parameters.QueryDirectory.FileInformationClass != FileBothDirectoryInformation &&
1102 IrpSp->Parameters.QueryDirectory.FileInformationClass != FileDirectoryInformation &&
1103 IrpSp->Parameters.QueryDirectory.FileInformationClass != FileNamesInformation)
1106 rpt0(("enum", "enum class %d not supported", IrpSp->Parameters.QueryDirectory.FileInformationClass));
1107 SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
1110 ccb = IrpSp->FileObject->FsContext2;
1112 if (!(outPtr = AfsFindBuffer(Irp)))
1113 SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
1115 if (IrpSp->Flags & SL_INDEX_SPECIFIED)
1117 /* we were told where to start our search; afsd should scrub this input */
1118 ccb->cookie.QuadPart = IrpSp->Parameters.QueryDirectory.FileIndex;
1119 if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL)
1120 ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG);
1121 ccb->filter = SEARCH_MATCH_ALL;
1123 else if (IrpSp->Flags & SL_RESTART_SCAN ||
1124 ((IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) && ccb->cookie.QuadPart == 0))
1126 /* copy new filter string into nonpaged memory */
1127 ccb->cookie.QuadPart = 0;
1128 if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL)
1129 ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG);
1130 buf_size = IrpSp->Parameters.QueryDirectory.FileName->Length+6;
1131 ccb->filter = ExAllocatePoolWithTag(NonPagedPool, buf_size, AFS_RDR_TAG);
1132 RtlCopyMemory(ccb->filter, IrpSp->Parameters.QueryDirectory.FileName->Buffer, buf_size);
1133 ccb->filter[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = L'\0';
1136 if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
1140 status = uc_readdir(fcb->fid, ccb->cookie, ccb->filter, &count, buf, &buf_size);
1144 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
1145 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
1146 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
1150 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass)
1152 case FileBothDirectoryInformation:
1153 info_size = sizeof(FILE_BOTH_DIR_INFORMATION);
1155 case FileDirectoryInformation:
1156 info_size = sizeof(FILE_DIRECTORY_INFORMATION);
1158 case FileNamesInformation:
1159 info_size = sizeof(FILE_NAMES_INFORMATION);
1162 KeBugCheckEx(0x12345, 0x98, 0x0, 0x0, 0x0);
1165 info = (FILE_BOTH_DIR_INFORMATION *)outPtr;
1166 ii = (readdir_data_t *)buf;
1167 Irp->IoStatus.Information = 0;
1170 if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY && ccb->cookie.QuadPart == 0)
1171 SYNC_FAIL(STATUS_NO_SUCH_FILE);
1172 SYNC_FAIL(STATUS_NO_MORE_FILES);
1175 info_both_prev = NULL;
1176 info_dir_prev = NULL;
1177 info_names_prev = NULL;
1178 if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
1181 for (x = 0; x < count; x++)
1183 pre_adj_info = info;
1185 /* must explicitly align second and subsequent entries on 8-byte boundaries */
1186 if (((ULONG)info & 0x7) && x)
1187 info = (void*)(((ULONG)info) + (8-((ULONG)info & 0x7)));
1189 overflow = ((long)info + info_size + (long)ii->name_length >
1190 (long)outPtr + (long)IrpSp->Parameters.QueryDirectory.Length);
1191 if (overflow && x != 0)
1193 ccb->cookie = ii->cookie;
1194 SYNC_FAIL2(STATUS_SUCCESS, (long)pre_adj_info - (long)outPtr);
1197 memset(info, 0, info_size);
1198 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass)
1200 case FileBothDirectoryInformation:
1203 info_both_prev->NextEntryOffset = (char*)info_both - (char*)info_both_prev;
1205 info_both->NextEntryOffset = 0;
1206 info_both->FileIndex = (ULONG)ii->cookie.QuadPart;
1207 info_both->CreationTime.QuadPart = AfsTimeToWindowsTime(ii->creation.QuadPart);
1208 info_both->LastAccessTime.QuadPart = AfsTimeToWindowsTime(ii->access.QuadPart);
1209 info_both->LastWriteTime.QuadPart = AfsTimeToWindowsTime(ii->write.QuadPart);
1210 info_both->ChangeTime.QuadPart = AfsTimeToWindowsTime(ii->change.QuadPart);
1211 info_both->EndOfFile = info_both->AllocationSize = ii->size;
1212 info_both->FileAttributes = ii->attribs;/*| FILE_ATTRIBUTE_READONLY*/;
1213 info_both->EaSize = 0;
1214 info_both->ShortNameLength = ii->short_name_length;
1215 info_both->FileNameLength = ii->name_length;
1216 RtlCopyMemory(info_both->ShortName, ii->short_name, ii->short_name_length*sizeof(WCHAR));
1220 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
1221 info_both->FileNameLength = 0;
1222 info_both->FileName[0] = L'\0';
1226 RtlCopyMemory(info_both->FileName, ii->name, ii->name_length*sizeof(WCHAR));
1227 info_both_prev = info_both;
1230 case FileDirectoryInformation:
1233 info_dir_prev->NextEntryOffset = (char*)info_dir - (char*)info_dir_prev;
1235 info_dir->NextEntryOffset = 0;
1236 info_dir->FileIndex = (ULONG)ii->cookie.QuadPart;
1237 info_dir->CreationTime.QuadPart = AfsTimeToWindowsTime(ii->creation.QuadPart);
1238 info_dir->LastAccessTime.QuadPart = AfsTimeToWindowsTime(ii->access.QuadPart);
1239 info_dir->LastWriteTime.QuadPart = AfsTimeToWindowsTime(ii->write.QuadPart);
1240 info_dir->ChangeTime.QuadPart = AfsTimeToWindowsTime(ii->change.QuadPart);
1241 info_dir->EndOfFile = info_dir->AllocationSize = ii->size;
1242 info_dir->FileAttributes = ii->attribs /*| FILE_ATTRIBUTE_READONLY*/;
1243 info_dir->FileNameLength = ii->name_length;
1247 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
1248 info_dir->FileNameLength = 0;
1249 info_dir->FileName[0] = L'\0';
1253 RtlCopyMemory(info_dir->FileName, ii->name, ii->name_length*sizeof(WCHAR));
1254 info_dir_prev = info_dir;
1257 case FileNamesInformation:
1259 if (info_names_prev)
1260 info_names_prev->NextEntryOffset = (char*)info_names - (char*)info_names_prev;
1262 info_names->NextEntryOffset = 0;
1263 info_names->FileIndex = (ULONG)ii->cookie.QuadPart;
1264 info_names->FileNameLength = ii->name_length;
1268 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
1269 info_names->FileNameLength = 0;
1270 info_names->FileName[0] = L'\0';
1274 RtlCopyMemory(info_names->FileName, ii->name, ii->name_length*sizeof(WCHAR));
1275 info_names_prev = info_names;
1279 info = (void*)(((ULONG)info) + info_size + (ULONG)ii->name_length*sizeof(WCHAR));
1280 ii = (readdir_data_t *)(((unsigned char *)ii) + sizeof(readdir_data_t) + ii->name_length);
1281 last_cookie = ii->cookie;
1284 Irp->IoStatus.Status = STATUS_SUCCESS;
1286 ccb->cookie = last_cookie;
1288 SYNC_FAIL2(Irp->IoStatus.Status, (long)info - (long)outPtr);
1294 /**********************************************************
1296 * - handle stat calls
1297 **********************************************************/
1298 NTSTATUS AfsRdrQueryInfo(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1300 FILE_BASIC_INFORMATION *infoBasic;
1301 FILE_NAME_INFORMATION *infoName;
1302 FILE_STANDARD_INFORMATION *infoStandard;
1303 FILE_POSITION_INFORMATION *infoPosition;
1304 FILE_ALL_INFORMATION *infoAll;
1305 FILE_INTERNAL_INFORMATION *infoInternal;
1306 LARGE_INTEGER size, creation, access, change, written;
1314 if (IsDeviceFile(IrpSp->FileObject))
1315 SYNC_FAIL(STATUS_UNSUCCESSFUL); // what should happen?
1317 if (!(outPtr = AfsFindBuffer(Irp)))
1318 SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
1320 ccb = IrpSp->FileObject->FsContext2;
1322 status = uc_stat(fcb->fid, &attribs, &size, &creation, &access, &change, &written);
1325 case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
1326 case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
1327 default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
1331 /* afsd does not maintain instance-specific data, so we adjust here */
1332 if (ccb->access & FILE_READ_DATA && !(ccb->access & FILE_WRITE_DATA))
1333 attribs |= FILE_ATTRIBUTE_READONLY;
1335 (void*)infoBasic = (void*)infoName = (void*)infoPosition = (void*)infoStandard = (void*)infoInternal = NULL;
1336 switch (IrpSp->Parameters.QueryFile.FileInformationClass)
1338 case FileBasicInformation:
1339 infoBasic = (FILE_BASIC_INFORMATION*)outPtr;
1341 case FileNameInformation:
1342 infoName = (FILE_NAME_INFORMATION*)outPtr;
1344 case FileStandardInformation:
1345 infoStandard = (FILE_STANDARD_INFORMATION*)outPtr;
1347 case FilePositionInformation:
1348 infoPosition = (FILE_POSITION_INFORMATION*)outPtr;
1350 case FileAllInformation:
1351 infoAll = (FILE_ALL_INFORMATION*)outPtr;
1352 infoBasic = &infoAll->BasicInformation;
1353 infoName = &infoAll->NameInformation;
1354 infoStandard = &infoAll->StandardInformation;
1355 infoPosition = &infoAll->PositionInformation;
1357 case FileInternalInformation:
1358 infoInternal = (FILE_INTERNAL_INFORMATION*)outPtr;
1361 STATUS(STATUS_NOT_IMPLEMENTED, 0);
1367 memset(infoBasic, 0, sizeof(FILE_BASIC_INFORMATION));
1368 infoBasic->FileAttributes = attribs;
1369 infoBasic->CreationTime.QuadPart = AfsTimeToWindowsTime(creation.QuadPart);
1370 infoBasic->LastAccessTime.QuadPart = AfsTimeToWindowsTime(access.QuadPart);
1371 infoBasic->LastWriteTime.QuadPart = AfsTimeToWindowsTime(written.QuadPart);
1372 infoBasic->ChangeTime.QuadPart = AfsTimeToWindowsTime(change.QuadPart);
1373 STATUS(STATUS_SUCCESS, sizeof(FILE_BASIC_INFORMATION));
1374 //KdPrint(("query basicinfo %d,%d %x,%I64d,%I64d\n", fcb->fid, (ULONG)IrpSp->FileObject->FsContext2, infoBasic->FileAttributes, infoBasic->CreationTime.QuadPart, infoBasic->ChangeTime.QuadPart));
1379 memset(infoName, 0, sizeof(FILE_NAME_INFORMATION));
1381 count = (long)(*(start+1) - L'0');
1382 if (count > 9 || count < 0)
1383 SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
1384 if (count || *start == L'0')
1386 for ( ; count >= 0 && start; count--)
1387 start = wcschr(start+1, L'\\');
1389 SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
1391 infoName->FileNameLength = wcslen(start)*sizeof(WCHAR);
1392 if (((IrpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation) ? sizeof(*infoAll) : sizeof(*infoName)) +
1393 infoName->FileNameLength > IrpSp->Parameters.QueryFile.Length)
1395 infoName->FileNameLength = 0;
1396 infoName->FileName[0] = L'\0';
1397 STATUS(STATUS_BUFFER_OVERFLOW, sizeof(FILE_NAME_INFORMATION));
1398 //KdPrint(("query overflowing buffer %d\n", IrpSp->Parameters.QueryFile.Length));
1401 { //TODO:check filename is correct/correct format
1402 StringCbCopy(infoName->FileName, IrpSp->Parameters.QueryFile.Length - sizeof(*infoName), start);
1403 STATUS(STATUS_SUCCESS, sizeof(FILE_NAME_INFORMATION) + (infoName->FileNameLength - sizeof(WCHAR)));
1405 //KdPrint(("query nameinfo %ws from %ws\n", infoName->FileName, ccb->name));
1410 memset(infoStandard, 0, sizeof(FILE_STANDARD_INFORMATION));
1411 infoStandard->AllocationSize.QuadPart = size.QuadPart;
1412 infoStandard->EndOfFile.QuadPart = size.QuadPart;
1413 infoStandard->NumberOfLinks = 1;
1414 infoStandard->DeletePending = (fcb->delPending == 1);
1415 infoStandard->Directory = (attribs & FILE_ATTRIBUTE_DIRECTORY)?TRUE:FALSE; //TODO:check if flag is valid at this point
1416 STATUS(STATUS_SUCCESS, sizeof(FILE_STANDARD_INFORMATION));
1417 //KdPrint(("query stdinfo %d,%d %I64d,%s\n", fcb->fid, (ULONG)IrpSp->FileObject->FsContext2, infoStandard->EndOfFile.QuadPart, infoStandard->Directory?"dir":"file"));
1422 infoPosition->CurrentByteOffset = IrpSp->FileObject->CurrentByteOffset;
1423 STATUS(STATUS_SUCCESS, sizeof(FILE_POSITION_INFORMATION));
1424 //KdPrint(("query position %d,%d %I64d\n", fcb, (ULONG)IrpSp->FileObject->FsContext2, infoPosition->CurrentByteOffset.QuadPart));
1427 if (IrpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation)
1429 if (!infoName->FileNameLength)
1430 STATUS(STATUS_BUFFER_OVERFLOW, sizeof(FILE_ALL_INFORMATION));
1432 STATUS(STATUS_SUCCESS, sizeof(FILE_ALL_INFORMATION) + (infoName->FileNameLength - sizeof(WCHAR)));
1437 infoInternal->IndexNumber.QuadPart = fcb->fid;
1438 STATUS(STATUS_SUCCESS, sizeof(FILE_INTERNAL_INFORMATION));
1441 status = Irp->IoStatus.Status;
1449 /**********************************************************
1451 * - handle setting mod time
1453 * - handle truncation/extension
1455 **********************************************************/
1456 NTSTATUS AfsRdrSetInfo(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1458 struct SetInfoKOut *p;
1461 FILE_DISPOSITION_INFORMATION *infoDisp;
1462 FILE_BASIC_INFORMATION *infoBasic;
1463 FILE_END_OF_FILE_INFORMATION *infoLength;
1464 FILE_RENAME_INFORMATION *infoRename;
1465 FILE_POSITION_INFORMATION *infoPosition;
1467 wchar_t *buf, *part, *ptr;
1468 ULONG size, new_fid;
1471 if (IrpSp->FileObject->FileName.Length == 0)
1472 SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
1474 ccb = IrpSp->FileObject->FsContext2;
1476 switch (IrpSp->Parameters.SetFile.FileInformationClass)
1478 /* delete disposition */
1479 case FileDispositionInformation:
1480 infoDisp = Irp->AssociatedIrp.SystemBuffer;
1482 FsRtlEnterFileSystem();
1485 if (infoDisp->DeleteFile)
1487 if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForDelete))
1488 SYNC_FAIL(STATUS_ACCESS_DENIED);
1489 fcb->delPending |= 0x1;
1492 fcb->delPending &= ~0x1;
1494 FsRtlExitFileSystem();
1495 SYNC_RET(STATUS_SUCCESS);
1497 /*case FileAllocationInformation:*/
1498 case FileEndOfFileInformation:
1499 /* ignore extensions caused by paging requests*/
1500 if (Irp->Flags & IRP_PAGING_IO)
1501 SYNC_FAIL(STATUS_SUCCESS);
1503 infoLength = Irp->AssociatedIrp.SystemBuffer;
1505 FsRtlEnterFileSystem();
1508 if (IrpSp->Parameters.SetFile.AdvanceOnly && (infoLength->EndOfFile.QuadPart > fcb->FileSize.QuadPart) ||
1509 !IrpSp->Parameters.SetFile.AdvanceOnly && (infoLength->EndOfFile.QuadPart < fcb->FileSize.QuadPart))
1511 status = uc_trunc(fcb->fid, infoLength->EndOfFile);
1512 /* because it is not written to the server immediately, this error will not always happen */
1513 if (status == IFSL_OVERQUOTA)
1517 FsRtlExitFileSystem();
1518 SYNC_FAIL(STATUS_DISK_FULL);
1521 fcb->FileSize = fcb->AllocationSize = fcb->ValidDataLength = infoLength->EndOfFile;
1522 CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
1523 //CcPurgeCacheSection(IrpSp->FileObject->SectionObjectPointer, &fcb->AllocationSize, 0, FALSE);
1526 FsRtlExitFileSystem();
1527 SYNC_FAIL(STATUS_SUCCESS);
1529 case FileBasicInformation:
1530 infoBasic = Irp->AssociatedIrp.SystemBuffer;
1531 status = uc_setinfo(fcb->fid, infoBasic->FileAttributes, infoBasic->CreationTime, infoBasic->LastAccessTime, infoBasic->ChangeTime, infoBasic->LastWriteTime);
1532 SYNC_FAIL(STATUS_SUCCESS);
1534 case FileRenameInformation:
1535 //KdPrint(("set rename %d\n", fcb->fid));
1536 infoRename = Irp->AssociatedIrp.SystemBuffer;
1538 //rpt1(("setinfo", "rename %d,%d %d,%ws", ExtractFid(fcb), (ULONG)IrpSp->FileObject->FsContext2, infoRename->ReplaceIfExists, infoRename->FileName));
1540 if (IrpSp->Parameters.SetFile.FileObject)
1541 fcbt = FindFcb(IrpSp->Parameters.SetFile.FileObject);
1543 //null-terminate all strings into uc_rename?
1544 //FIX/one rename case not working
1546 if (IrpSp->Parameters.SetFile.FileObject == NULL &&
1547 infoRename->RootDirectory == NULL)
1549 WCHAR fname[300]; /* FIX: uc_rename needs null-terminated string */
1550 StringCchCopyNW(fname, 300-1, infoRename->FileName, infoRename->FileNameLength/sizeof(WCHAR));
1551 uc_rename(fcb->fid, ccb->name+2, NULL, fname, &new_fid);
1554 else if (IrpSp->Parameters.SetFile.FileObject != NULL &&
1555 infoRename->RootDirectory == NULL)
1558 StringCchCopyNW(fname, 300-1, infoRename->FileName, infoRename->FileNameLength/sizeof(WCHAR));
1559 uc_rename(fcb->fid, ccb->name+2, fcbt->ccb_list->name+2, fname, &new_fid);
1565 /*fcbt = FindFcb(IrpSp->Parameters.SetFile.FileObject);
1568 StringCbCopyW(buf, size, fcb->name);
1569 p->NewNameOff = wcslen(buf)+1;
1570 StringCbCopyNW(buf + p->NewNameOff,
1571 size - p->NewNameOff,
1572 infoRename->FileName,
1573 infoRename->FileNameLength*sizeof(wchar_t));
1574 buf[p->NewNameOff+infoRename->FileNameLength] = L'\0';
1575 p->NewDirOff = p->NewNameOff + wcslen(buf + p->NewNameOff)+1;
1576 StringCbCopyW(buf + p->NewDirOff,
1577 size - p->NewDirOff,
1580 SYNC_RET(STATUS_SUCCESS);
1583 case FilePositionInformation:
1584 infoPosition = Irp->AssociatedIrp.SystemBuffer;
1585 IrpSp->FileObject->CurrentByteOffset = infoPosition->CurrentByteOffset;
1586 SYNC_FAIL(STATUS_SUCCESS);
1589 KdPrint(("set unsupp %d type %d\n", fcb->fid, IrpSp->Parameters.SetFile.FileInformationClass));
1590 SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
1593 SYNC_FAIL(STATUS_UNSUCCESSFUL);
1596 dc_break_callback(ULONG fid)
1605 fcb = find_fcb(fid);
1609 return 1; /* we are done with this file */
1612 ASSERT(fcb->ccb_list);
1613 /*pos = wcslen(fcb->ccb_list->name);
1614 if (fcb->ccb_list->name[pos-1] == L'\\')
1619 if (fcb->ccb_list->name[pos-1] == L'\\')
1624 len = (wcslen(fcb->ccb_list->name) + 10) * sizeof(wchar_t);
1625 s = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)+len+sizeof(wchar_t));
1627 s->MaximumLength = len + sizeof(wchar_t);
1628 s->Buffer = (PWSTR)(s+1);
1630 StringCbCopyW((PWSTR)(s+1), len, fcb->ccb_list->name);
1631 if (s->Buffer[wcslen(s->Buffer) - 1] != L'\\')
1632 StringCbCatW(s->Buffer, len, L"\\");
1633 pos = wcslen(s->Buffer);
1634 StringCbCatW(s->Buffer, len, L"jj"); /* FIX: make bogus change notification */
1636 KdPrint(("break callback on %d %ws %ws\n", fid, fcb->ccb_list->name, fcb->ccb_list->name+pos));
1638 FsRtlNotifyFullReportChange(rdrExt->notifyList, &rdrExt->listHead,
1639 (PSTRING)s, (USHORT)pos*sizeof(wchar_t), NULL, NULL,
1640 FILE_NOTIFY_CHANGE_FILE_NAME/*FILE_NOTIFY_VALID_MASK/*FILE_NOTIFY_CHANGE_FILE_NAME*/, FILE_ACTION_ADDED, NULL);
1647 /**********************************************************
1648 * AfsRdrDeviceControl
1649 * - handle communication requests from fs, etc.
1651 **********************************************************/
1652 NTSTATUS AfsRdrDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1654 struct KOutEntry *entry;
1660 ULONG key, code, length;
1662 /* utility ioctls */
1663 if (DeviceObject == ComDevice &&
1664 IrpSp->FileObject->FsContext2 == COMM_IOCTL &&
1665 IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_IOCTL)
1667 outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
1671 rpc_set_context(IrpSp->FileObject->FsContext);
1672 code = uc_ioctl_write(IrpSp->Parameters.DeviceIoControl.InputBufferLength,
1673 Irp->AssociatedIrp.SystemBuffer,
1675 length = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
1677 code = uc_ioctl_read(key, &length, outPtr);
1678 rpc_remove_context();
1683 STATUS(STATUS_SUCCESS, length);
1686 STATUS(STATUS_UNSUCCESSFUL, 0);
1690 /* downcalls by afsd */
1691 else if (DeviceObject == ComDevice &&
1692 IrpSp->FileObject->FsContext2 == COMM_DOWNCALL &&
1693 IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_DOWNCALL)
1695 outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
1699 rpc_set_context(IrpSp->FileObject->FsContext);
1700 code = rpc_call(IrpSp->Parameters.DeviceIoControl.InputBufferLength,
1701 Irp->AssociatedIrp.SystemBuffer,
1702 IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
1705 rpc_remove_context();
1709 STATUS(STATUS_SUCCESS, length);
1712 STATUS(STATUS_UNSUCCESSFUL, 0);
1716 else if (DeviceObject == RdrDevice &&
1717 IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_GET_PATH)
1719 outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
1723 StringCbCopyW(outPtr, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, fcb->ccb_list->name+2);
1725 STATUS(STATUS_SUCCESS, (wcslen(outPtr)+1)*sizeof(wchar_t));
1729 rpt0(("devctl", "devctl %d rejected", IrpSp->Parameters.DeviceIoControl.IoControlCode));
1730 SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
1733 ret = Irp->IoStatus.Status;
1740 /**********************************************************
1742 * - called when usermode handle count reaches zero
1743 **********************************************************/
1744 NTSTATUS AfsRdrCleanup(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1747 struct AfsRdrExtension *ext;
1750 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1752 if (IrpSp->FileObject->FileName.Length == 0)
1753 SYNC_FAIL(STATUS_SUCCESS);
1755 ext = ((struct AfsRdrExtension*)RdrDevice->DeviceExtension);
1761 FsRtlNotifyCleanup(ext->notifyList, &ext->listHead, IrpSp->FileObject->FsContext2);
1763 CcFlushCache(IrpSp->FileObject->SectionObjectPointer, NULL, 0, NULL);
1765 if (fcb->delPending && !MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForDelete))
1766 /* yes, moot at this point */
1767 STATUS(STATUS_ACCESS_DENIED, 0);
1769 STATUS(STATUS_SUCCESS, 0);
1771 MmFlushImageSection(IrpSp->FileObject->SectionObjectPointer, MmFlushForWrite);
1772 CcPurgeCacheSection(IrpSp->FileObject->SectionObjectPointer, NULL, 0, TRUE);
1773 CcUninitializeCacheMap(IrpSp->FileObject, NULL, NULL);
1779 /*} except(EXCEPTION_EXECUTE_HANDLER)
1782 STATUS(STATUS_UNSUCCESSFUL, 0);
1783 ExReleaseResourceLite(&ext->fcbLock);
1784 FsRtlExitFileSystem();
1787 ret = Irp->IoStatus.Status;
1793 /**********************************************************
1795 * - handle actual unlinking
1797 **********************************************************/
1798 NTSTATUS AfsRdrClose(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1804 LARGE_INTEGER timeout;
1805 afs_ccb_t *ccb, *curr;
1807 if (IrpSp->FileObject->FileName.Length == 0)
1808 SYNC_FAIL(STATUS_SUCCESS);
1810 ccb = IrpSp->FileObject->FsContext2;
1813 /* set share correctly so future opens can succeed */
1814 IoRemoveShareAccess(IrpSp->FileObject, &fcb->share_access);
1815 ObDereferenceObject(ccb->token);
1817 curr = fcb->ccb_list;
1818 if (fcb->ccb_list == ccb)
1819 fcb->ccb_list = fcb->ccb_list->next;
1823 if (curr->next == ccb)
1825 curr->next = curr->next->next;
1834 if (fcb->delPending)
1836 uc_unlink(ccb->name+2);
1838 ExDeleteResourceLite(&fcb->_resource);
1839 ExDeleteResourceLite(&fcb->_pagingIoResource);
1840 RtlDeleteElementGenericTable(&rdrExt->fcbTable, &fcb);
1841 ExFreeToNPagedLookasideList(&rdrExt->fcbMemList, fcb);
1844 ExFreePoolWithTag(ccb->name, AFS_RDR_TAG);
1845 if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL)
1846 ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG);
1847 ExFreeToNPagedLookasideList(&rdrExt->ccbMemList, ccb);
1851 SYNC_FAIL(STATUS_SUCCESS);
1855 /**********************************************************
1857 * - should flush all data
1858 **********************************************************/
1859 NTSTATUS AfsRdrShutdown(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp)
1862 STATUS(STATUS_SUCCESS, 0);
1867 /**********************************************************
1869 * - flushes specified file to userspace and then disk
1870 **********************************************************/
1871 NTSTATUS AfsRdrFlushFile(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1877 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1879 if (IrpSp->FileObject->FileName.Length == 0)
1880 SYNC_RET(STATUS_INVALID_DEVICE_REQUEST);
1882 ccb = IrpSp->FileObject->FsContext2;
1884 CcFlushCache(&fcb->sectionPtrs, NULL, 0, &Irp->IoStatus);
1886 //SYNC_FAIL2(/*STATUS_LOCK_NOT_GRANTED*//*STATUS_NOT_IMPLEMENTED*/STATUS_SUCCESS, 0);
1888 /*EXCEPT(STATUS_UNSUCCESSFUL, 0);*/
1890 return Irp->IoStatus.Status;
1894 /**********************************************************
1896 * - should handle lock requests
1897 **********************************************************/
1898 NTSTATUS AfsRdrLockCtrl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
1903 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1905 /* complete lock on control device object without processing, as directed */
1906 if (IrpSp->FileObject->FileName.Length == 0)
1908 rpt0(("lock", "lock granted on root device obj"));
1909 SYNC_FAIL(STATUS_SUCCESS);
1912 SYNC_FAIL2(/*STATUS_LOCK_NOT_GRANTED*//*STATUS_NOT_IMPLEMENTED*/STATUS_SUCCESS, 0);
1914 /*EXCEPT(STATUS_UNSUCCESSFUL, 0);*/
1918 /**********************************************************
1920 * - handle volume information requests
1921 **********************************************************/
1922 NTSTATUS AfsRdrQueryVol(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp)
1924 FILE_FS_ATTRIBUTE_INFORMATION *infoAttr;
1925 FILE_FS_DEVICE_INFORMATION *infoDevice;
1926 FILE_FS_SIZE_INFORMATION * infoSize;
1927 FILE_FS_VOLUME_INFORMATION *infoVolume;
1932 switch (IrpSp->Parameters.QueryVolume.FsInformationClass)
1934 case FileFsAttributeInformation:
1935 infoAttr = (FILE_FS_ATTRIBUTE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
1936 memset(infoAttr, 0, sizeof(FILE_FS_ATTRIBUTE_INFORMATION));
1937 infoAttr->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH; //TODOTODO:?
1938 infoAttr->MaximumComponentNameLength = 255; // should this be 255?
1939 ///RtlCopyMemory(infoAttr->FileSystemName, L"AFS", 2);
1940 ///infoAttr->FileSystemNameLength = 2;
1941 //StringCbCopyLen(infoAttr->FileSystemName, IrpSp->Parameters.QueryVolume.Length-sizeof(*infoAttr)-2, L"AFS", &infoAttr->FileSystemNameLength);
1942 //IrpSp->Parameters.QueryVolume.Length = 0;
1943 //Irp->IoStatus.Information = sizeof(*infoAttr) + (infoAttr->FileSystemNameLength - sizeof(WCHAR));
1944 if (sizeof(*infoAttr) + wcslen(AFS_FS_NAME)*sizeof(wchar_t) > IrpSp->Parameters.QueryVolume.Length)
1946 infoAttr->FileSystemNameLength = 0;
1947 rpt0(("vol", "overflowing attr buffer %d", IrpSp->Parameters.QueryVolume.Length));
1948 SYNC_FAIL2(STATUS_BUFFER_OVERFLOW, sizeof(*infoAttr));
1952 infoAttr->FileSystemNameLength = wcslen(AFS_FS_NAME)*sizeof(wchar_t);
1953 StringCbCopyW(infoAttr->FileSystemName, IrpSp->Parameters.QueryVolume.Length - sizeof(*infoAttr) + sizeof(WCHAR), AFS_FS_NAME);
1954 SYNC_FAIL2(STATUS_SUCCESS, sizeof(*infoAttr) + (infoAttr->FileSystemNameLength - sizeof(WCHAR)));
1958 case FileFsDeviceInformation:
1959 infoDevice = (FILE_FS_DEVICE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
1960 memset(infoDevice, 0, sizeof(FILE_FS_DEVICE_INFORMATION));
1961 infoDevice->DeviceType = FILE_DEVICE_DISK;//DeviceObject->DeviceType;// FILE_DEVICE_NETWORK_FILE_SYSTEM;
1962 infoDevice->Characteristics = DeviceObject->Characteristics;//FILE_DEVICE_IS_MOUNTED /*| FILE_REMOTE_DEVICE*/; // remote device?
1963 IrpSp->Parameters.QueryVolume.Length = sizeof(*infoDevice);
1964 SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.QueryVolume.Length);
1967 case FileFsSizeInformation:
1968 infoSize = (FILE_FS_SIZE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
1969 memset(infoSize, 0, sizeof(FILE_FS_SIZE_INFORMATION));
1970 infoSize->TotalAllocationUnits.QuadPart = 0x00000000F0000000; //FIX
1971 infoSize->AvailableAllocationUnits.QuadPart = 0x00000000E0000000;
1972 infoSize->SectorsPerAllocationUnit = 1;
1973 infoSize->BytesPerSector = 1;
1974 IrpSp->Parameters.QueryVolume.Length = sizeof(*infoSize);
1975 SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.QueryVolume.Length);
1978 case FileFsVolumeInformation:
1979 infoVolume = (FILE_FS_VOLUME_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
1980 memset(infoVolume, 0, sizeof(FILE_FS_VOLUME_INFORMATION));
1981 infoVolume->VolumeCreationTime.QuadPart = AfsTimeToWindowsTime(1080000000);//0x43218765); //TODO:fix
1982 infoVolume->VolumeSerialNumber = 0x12345678; //TODO:fix
1983 infoVolume->SupportsObjects = FALSE;
1984 //StringCbCopyLen(infoVolume->VolumeLabel, IrpSp->Parameters.QueryVolume.Length-sizeof(*infoVolume)-2, L"AfsRed", &infoVolume->VolumeLabelLength);
1985 //IrpSp->Parameters.QueryVolume.Length = 0;
1986 if (sizeof(*infoVolume) + 12 > IrpSp->Parameters.QueryVolume.Length)
1988 infoVolume->VolumeLabelLength = 0;
1989 rpt0(("vol", "overflowing buffer %d", IrpSp->Parameters.QueryVolume.Length));
1990 SYNC_FAIL2(STATUS_BUFFER_OVERFLOW, sizeof(*infoVolume));
1994 infoVolume->VolumeLabelLength = 12;
1995 RtlCopyMemory(infoVolume->VolumeLabel, L"AfsRed", 12);
1996 SYNC_FAIL2(STATUS_SUCCESS, sizeof(*infoVolume) + (infoVolume->VolumeLabelLength - sizeof(WCHAR)));
1999 //case FileFsFullSizeInformation:
2003 EXCEPT(STATUS_UNSUCCESSFUL, 0);
2005 rpt0(("vol", "vol class %d unknown", IrpSp->Parameters.QueryVolume.FsInformationClass));
2006 SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
2009 VOID AfsRdrUnload(DRIVER_OBJECT *DriverObject)
2011 UNICODE_STRING userModeName;
2013 FsRtlNotifyUninitializeSync(&rdrExt->notifyList);
2015 RtlInitUnicodeString(&userModeName, L"\\DosDevices\\afscom");
2016 IoDeleteSymbolicLink(&userModeName);
2018 /*RtlInitUnicodeString(&userModeName, L"\\DosDevices\\T:");
2019 IoDeleteSymbolicLink(&userModeName);*/
2021 ExDeleteNPagedLookasideList(&rdrExt->fcbMemList);
2022 ExDeleteNPagedLookasideList(&rdrExt->ccbMemList);
2026 IoDeleteDevice(ComDevice);
2027 IoDeleteDevice(RdrDevice);
2030 rptCliClose(REPORT);
2033 KdPrint(("RdrUnload exiting.\n"));
2037 // handles all non-handled irp's synchronously
2038 NTSTATUS AfsRdrNull(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp)
2043 rpt0(("kunhand", IrpMjFuncDesc[IrpSp->MajorFunction]));*/
2045 SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
2047 /*EXCEPT(STATUS_UNSUCCESSFUL, 0);
2049 ret = Irp->IoStatus.Status;
2054 NTSTATUS ComDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
2056 IO_STACK_LOCATION *IrpSp, *IrpSpClient;
2058 struct ComExtension *ext;
2060 rpc_t find, *find_ptr;
2061 LARGE_INTEGER timeout;
2066 PACCESS_TOKEN acc_token;
2068 ext = (struct ComExtension *)DeviceObject->DeviceExtension;
2069 IrpSp = IoGetCurrentIrpStackLocation(Irp);
2071 switch (IrpSp->MajorFunction)
2074 IrpSp->FileObject->FsContext = 0;
2075 IrpSp->FileObject->FsContext2 = 0;
2076 if (IrpSp->FileObject->FileName.Length)
2078 /* ioctls come from fs, vos, bos, etc. using a pre-existing interface */
2079 /* downcalls come from afsd, using a new interface */
2080 /* upcall hooks come from afsd */
2081 if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\ioctl"))
2082 IrpSp->FileObject->FsContext2 = COMM_IOCTL;
2083 else if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\downcall"))
2084 IrpSp->FileObject->FsContext2 = COMM_DOWNCALL;
2085 else if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\upcallhook"))
2086 IrpSp->FileObject->FsContext2 = COMM_UPCALLHOOK;
2088 if (!IrpSp->FileObject->FsContext2)
2089 SYNC_FAIL2(STATUS_INVALID_DEVICE_REQUEST, 0);
2091 acc_token = SeQuerySubjectContextToken(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2093 /* SeQueryAuthenticationIdToken */
2094 IrpSp->FileObject->FsContext = acc_token;
2095 STATUS(STATUS_SUCCESS, FILE_OPENED);
2098 case IRP_MJ_CLEANUP:
2099 /* acc_token does not have to be released */
2101 STATUS(STATUS_SUCCESS, 0);
2105 /* we only process MDL writes */
2107 if (!Irp->MdlAddress ||
2108 !(ptr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))) /* should be LowPagePriority */
2109 SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
2111 if (!IrpSp->FileObject->FsContext ||
2112 !IrpSp->FileObject->FsContext2)
2113 SYNC_FAIL(STATUS_INVALID_HANDLE);
2115 if (IrpSp->FileObject->FsContext2 == COMM_UPCALLHOOK)
2117 rpc_recv(ptr, IrpSp->Parameters.Write.Length);
2118 STATUS(STATUS_SUCCESS, IrpSp->Parameters.Write.Length);
2121 STATUS(STATUS_INVALID_DEVICE_REQUEST, 0);
2124 if (!Irp->MdlAddress || !(ptr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))) // should be LowPagePriority
2127 if (IrpSp->FileObject->FsContext2 == COMM_UPCALLHOOK)
2129 /*timeout.QuadPart = -10000000L;*/
2130 timeout.QuadPart = -100000000L;
2131 KeWaitForSingleObject(&comExt->outEvent, Executive, KernelMode, FALSE, &timeout);
2133 if (!rpc_send(ptr, IrpSp->Parameters.Read.Length, &read))
2135 KeClearEvent(&comExt->outEvent);
2136 KeWaitForSingleObject(&comExt->outEvent, Executive, KernelMode/*UserMode*/, FALSE, &timeout);
2137 if (!rpc_send(ptr, IrpSp->Parameters.Read.Length, &read))
2139 KeClearEvent(&comExt->outEvent);
2140 SYNC_FAIL(STATUS_UNSUCCESSFUL);
2143 SYNC_FAIL2(STATUS_SUCCESS, read);
2146 STATUS(STATUS_INVALID_DEVICE_REQUEST, 0);
2148 case IRP_MJ_DEVICE_CONTROL:
2149 return AfsRdrDeviceControl(DeviceObject, Irp, IrpSp, NULL);
2151 STATUS(STATUS_INVALID_DEVICE_REQUEST, 0);
2155 ret = Irp->IoStatus.Status;
2161 // handles all irp's for primary (fs) device
2162 NTSTATUS Dispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
2164 IO_STACK_LOCATION *IrpSp;
2169 if (DeviceObject->DeviceType == FILE_DEVICE_DATALINK)
2170 return ComDispatch(DeviceObject, Irp);
2172 IrpSp = IoGetCurrentIrpStackLocation(Irp);
2174 rpt4(("irp", "%s min %d on %d (%ws) %x %x", IrpMjFuncDesc[IrpSp->MajorFunction], IrpSp->MinorFunction, 0/*ExtractFid(IrpSp->FileObject->FsContext)*/, IrpSp->FileObject->FileName.Buffer, IrpSp->Flags, IrpSp->Parameters.Create.Options));
2176 fcb = IrpSp->FileObject->FsContext;//FindFcb(IrpSp->FileObject);
2177 if (IrpSp->MajorFunction != IRP_MJ_CREATE)
2180 if (IrpSp->FileObject && IrpSp->FileObject->FsContext2)
2182 ccb = IrpSp->FileObject->FsContext2;
2183 rpc_set_context(ccb->token);
2186 switch (IrpSp->MajorFunction)
2189 ret = AfsRdrCreate(DeviceObject, Irp, IrpSp, NULL); break;
2190 case IRP_MJ_DIRECTORY_CONTROL:
2191 ret = AfsRdrDirCtrl(DeviceObject, Irp, IrpSp, fcb); break;
2193 ret = AfsRdrRead(DeviceObject, Irp, IrpSp, fcb); break;
2195 ret = AfsRdrWrite(DeviceObject, Irp, IrpSp, fcb); break;
2197 ret = AfsRdrClose(DeviceObject, Irp, IrpSp, fcb); break;
2198 case IRP_MJ_QUERY_INFORMATION:
2199 ret = AfsRdrQueryInfo(DeviceObject, Irp, IrpSp, fcb); break;
2200 case IRP_MJ_DEVICE_CONTROL:
2201 ret = AfsRdrDeviceControl(DeviceObject, Irp, IrpSp, fcb); break;
2202 case IRP_MJ_CLEANUP:
2203 ret = AfsRdrCleanup(DeviceObject, Irp, IrpSp, fcb); break;
2204 case IRP_MJ_LOCK_CONTROL:
2205 ret = AfsRdrLockCtrl(DeviceObject, Irp, IrpSp, fcb); break;
2206 case IRP_MJ_QUERY_VOLUME_INFORMATION:
2207 ret = AfsRdrQueryVol(DeviceObject, Irp, IrpSp); break;
2208 case IRP_MJ_SHUTDOWN:
2209 ret = AfsRdrShutdown(DeviceObject, Irp, IrpSp); break;
2210 case IRP_MJ_FILE_SYSTEM_CONTROL:
2211 if (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
2212 (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1 ||
2213 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2 ||
2214 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK ||
2215 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK))
2216 STATUS(STATUS_OPLOCK_NOT_GRANTED, 0);
2218 STATUS(STATUS_INVALID_DEVICE_REQUEST/*STATUS_NOT_IMPLEMENTED*//*STATUS_INVALID_PARAMETER*/, 0);
2219 ret = Irp->IoStatus.Status;
2221 case IRP_MJ_SET_INFORMATION:
2222 ret = AfsRdrSetInfo(DeviceObject, Irp, IrpSp, fcb); break;
2223 case IRP_MJ_FLUSH_BUFFERS:
2224 ret = AfsRdrFlushFile(DeviceObject, Irp, IrpSp, fcb); break;
2226 ret = AfsRdrNull(DeviceObject, Irp, IrpSp); break;
2228 rpc_remove_context();
2232 rpc_remove_context();
2239 IN struct _FILE_OBJECT *FileObject,
2240 IN PLARGE_INTEGER FileOffset,
2245 OUT PIO_STATUS_BLOCK IoStatus,
2246 IN struct _DEVICE_OBJECT *DeviceObject
2253 fcb = FileObject->FsContext;
2256 FsRtlEnterFileSystem();
2259 if (FileOffset->QuadPart > fcb->FileSize.QuadPart)
2262 FsRtlExitFileSystem();
2263 IoStatus->Status = STATUS_END_OF_FILE;
2264 IoStatus->Information = 0;
2267 if (FileOffset->QuadPart + Length > fcb->FileSize.QuadPart)
2268 adj_len = (ULONG)(fcb->FileSize.QuadPart - FileOffset->QuadPart);
2272 ret = CcCopyRead(FileObject, FileOffset, adj_len, Wait, Buffer, IoStatus);
2273 /*if (IoStatus->Status == STATUS_SUCCESS &&
2275 IoStatus->Status = STATUS_END_OF_FILE;*/
2276 // KdPrint(("read %x at %x fast done %x\n", Length, (ULONG)FileOffset->QuadPart, IoStatus->Information));
2277 FileObject->CurrentByteOffset.QuadPart += IoStatus->Information;
2279 FsRtlExitFileSystem();
2281 except (EXCEPTION_EXECUTE_HANDLER)
2284 FsRtlExitFileSystem();
2292 IN struct _FILE_OBJECT *FileObject,
2293 IN PLARGE_INTEGER FileOffset,
2298 OUT PIO_STATUS_BLOCK IoStatus,
2299 IN struct _DEVICE_OBJECT *DeviceObject
2303 LARGE_INTEGER adj_end;
2306 fcb = FileObject->FsContext;
2309 FsRtlEnterFileSystem();
2312 if (FileOffset->QuadPart + Length > fcb->FileSize.QuadPart)
2314 adj_end.QuadPart = fcb->FileSize.QuadPart + Length;
2315 fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = adj_end;
2319 CcSetFileSizes(FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
2321 except (EXCEPTION_EXECUTE_HANDLER)
2325 FsRtlExitFileSystem();
2333 ret = CcCopyWrite(FileObject, FileOffset, Length, Wait, Buffer);
2334 IoStatus->Status = ret?STATUS_SUCCESS:STATUS_UNSUCCESSFUL;
2335 IoStatus->Information = ret?Length:0;
2336 // KdPrint(("write %x at %x fast done\n", Length, (ULONG)FileOffset->QuadPart));
2337 FileObject->CurrentByteOffset.QuadPart += IoStatus->Information;
2339 FsRtlExitFileSystem();
2341 except (EXCEPTION_EXECUTE_HANDLER)
2344 FsRtlExitFileSystem();
2350 RTL_GENERIC_COMPARE_RESULTS FcbCompareRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct)
2354 p1 = (void*)*(afs_fcb_t**)FirstStruct; p2 = (void*)*(afs_fcb_t**)SecondStruct;
2355 if (p1->fid < p2->fid)
2356 return GenericLessThan;
2357 if (p1->fid > p2->fid)
2358 return GenericGreaterThan;
2359 return GenericEqual;
2362 RTL_GENERIC_COMPARE_RESULTS ReqCompareRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct)
2366 p1 = *(rpc_t**)FirstStruct; p2 = *(rpc_t**)SecondStruct;
2367 if (p1->key < p2->key)
2368 return GenericLessThan;
2369 if (p1->key > p2->key)
2370 return GenericGreaterThan;
2371 return GenericEqual;
2374 PVOID AllocateRoutine(struct _RTL_GENERIC_TABLE *Table, CLONG ByteSize)
2377 ret = ExAllocatePoolWithTag(NonPagedPool, ByteSize, AFS_RDR_TAG);
2379 RtlZeroMemory(ret, ByteSize);
2383 VOID FreeRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID Buffer)
2385 ExFreePoolWithTag(Buffer, AFS_RDR_TAG);
2388 //KSPIN_LOCK rpc_lock;
2390 FAST_MUTEX rpc_lock;
2392 void ifs_lock_rpcs()
2394 ExAcquireFastMutex(&rpc_lock);
2395 //KeAcquireSpinLock(&rpc_lock, &irql);
2398 void ifs_unlock_rpcs()
2400 ExReleaseFastMutex(&rpc_lock);
2401 //KeReleaseSpinLock(&rpc_lock, irql);
2404 NTSTATUS DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
2407 UNICODE_STRING rdrName, comName, userModeName, userModeCom;
2409 IO_STATUS_BLOCK status;
2410 FAST_IO_DISPATCH *fastIoDispatch;
2416 REPORT = rptOpen(NULL, "afskern");
2418 rpt0(("init", "rpt initialized at %x", REPORT));
2420 RtlInitUnicodeString(&rdrName, L"\\Device\\afsrdr");
2421 RtlInitUnicodeString(&comName, L"\\Device\\afscom");
2423 rpt0(("init", "kern initializing"));
2424 //KeInitializeSpinLock(&rpc_lock);
2425 ExInitializeFastMutex(&rpc_lock);
2427 IoAllocateDriverObjectExtension(DriverObject, (void *)0x394389f7, sizeof(FAST_IO_DISPATCH), &fastIoDispatch);
2428 RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
2429 fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
2430 fastIoDispatch->FastIoRead = fastIoRead;
2431 fastIoDispatch->FastIoWrite = fastIoWrite;
2432 DriverObject->FastIoDispatch = fastIoDispatch;
2434 for (x = 0; x < IRP_MJ_MAXIMUM_FUNCTION; x++)
2435 DriverObject->MajorFunction[x] = Dispatch;
2436 DriverObject->DriverUnload = AfsRdrUnload;
2438 err = IoCreateDevice(DriverObject, sizeof(struct AfsRdrExtension)*2, &rdrName, FILE_DEVICE_NETWORK_FILE_SYSTEM, /*FILE_REMOTE_DEVICE*/0, FALSE, &RdrDevice);
2439 if (!NT_SUCCESS(STATUS_SUCCESS))
2440 return STATUS_UNSUCCESSFUL;
2441 err = IoCreateDevice(DriverObject, sizeof(struct ComExtension)*2, &comName, FILE_DEVICE_DATALINK, 0, FALSE, &ComDevice);
2442 if (!NT_SUCCESS(STATUS_SUCCESS))
2443 return STATUS_UNSUCCESSFUL;
2445 RdrDevice->Flags |= DO_DIRECT_IO;
2446 RdrDevice->StackSize = 5; /* could this be zero? */
2447 rdrExt = ((struct AfsRdrExtension*)RdrDevice->DeviceExtension);
2448 RtlZeroMemory(rdrExt, sizeof(struct AfsRdrExtension));
2450 /* could raise exception */
2451 FsRtlNotifyInitializeSync(&rdrExt->notifyList);
2452 InitializeListHead(&rdrExt->listHead);
2454 rdrExt->callbacks.AcquireForLazyWrite = lazyWriteLock;
2455 rdrExt->callbacks.ReleaseFromLazyWrite = lazyWriteUnlock;
2456 rdrExt->callbacks.AcquireForReadAhead = readAheadLock;
2457 rdrExt->callbacks.ReleaseFromReadAhead = readAheadUnlock;
2458 ExInitializeNPagedLookasideList(&rdrExt->fcbMemList, NULL, NULL, 0, sizeof(afs_fcb_t), AFS_RDR_TAG, 0);
2459 ExInitializeNPagedLookasideList(&rdrExt->ccbMemList, NULL, NULL, 0, sizeof(afs_ccb_t), AFS_RDR_TAG, 0);
2460 ExInitializeFastMutex(&rdrExt->fcbLock);
2461 RtlInitializeGenericTable(&rdrExt->fcbTable, FcbCompareRoutine, AllocateRoutine, FreeRoutine, NULL);
2464 ComDevice->Flags |= DO_DIRECT_IO;
2465 ComDevice->StackSize = 5; // ??
2466 comExt = ((struct ComExtension*)ComDevice->DeviceExtension);
2467 RtlZeroMemory(comExt, sizeof(struct ComExtension));
2469 //ExInitializeNPagedLookasideList(&comExt->outMemList, NULL, NULL, 0, sizeof(struct KOutEntry)+100, AFS_RDR_TAG, 0);
2470 InitializeListHead(&comExt->outReqList);
2471 KeInitializeSpinLock(&comExt->outLock);
2472 ExInitializeFastMutex(&comExt->inLock);
2473 RtlInitializeGenericTable(&comExt->inTable, ReqCompareRoutine, AllocateRoutine, FreeRoutine, NULL);
2474 KeInitializeEvent(&comExt->outEvent, NotificationEvent, TRUE);
2475 KeInitializeEvent(&comExt->cancelEvent, NotificationEvent, TRUE);
2477 comExt->rdr = rdrExt;
2478 rdrExt->com = comExt;
2480 RtlInitUnicodeString(&userModeCom, L"\\DosDevices\\afscom");
2481 err = IoCreateSymbolicLink(&userModeCom, &comName);
2483 /*RtlInitUnicodeString(&rdrName, L"\\Device\\afsrdr\\1\\CITI.UMICH.EDU");
2484 RtlInitUnicodeString(&userModeName, L"\\DosDevices\\W:");
2485 err = IoCreateSymbolicLink(&userModeName, &rdrName);*/
2487 /*} except(EXCEPTION_EXECUTE_HANDLER)
2494 KdPrint(("DriverEntry exiting.\n"));
2495 return STATUS_SUCCESS;