VfatCreateFile函数主要用来创建或者打开一个文件,具体实现如下:
#001 static NTSTATUS
#002 VfatCreateFile ( PDEVICE_OBJECT DeviceObject,PIRP Irp )
#003 /*
#004 * FUNCTION: Create or open a file
#005 */
#006 {
#007 PIO_STACK_LOCATION Stack;
#008 PFILE_OBJECT FileObject;
#009 NTSTATUS Status = STATUS_SUCCESS;
#010 PDEVICE_EXTENSION DeviceExt;
#011 ULONG RequestedDisposition,RequestedOptions;
#012 PVFATCCB pCcb;
#013 PVFATFCB pFcb = NULL;
#014 PVFATFCB ParentFcb = NULL;
#015 PWCHAR c,last;
#016 BOOLEAN PagingFileCreate = FALSE;
#017 BOOLEAN Dots;
#018 UNICODE_STRING FileNameU;
#019 UNICODE_STRING PathNameU;
#020
#021 /* Unpack the varIoUs parameters. */
获取当前IRP栈位置。
#022 Stack = IoGetCurrentIrpStackLocation (Irp);
获取请求的参数。
#023 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
#024 RequestedOptions =
#025 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
#026 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
#027 FileObject = Stack->FileObject;
#028 DeviceExt = DeviceObject->DeviceExtension;
#029
检查参数是否有效。
#030 /* Check their validity. */
#031 if (RequestedOptions & FILE_DIRECTORY_FILE &&
#032 RequestedDisposition == FILE_SUPERSEDE)
#033 {
#034 return(STATUS_INVALID_PARAMETER);
#035 }
#036
#037 if (RequestedOptions & FILE_DIRECTORY_FILE &&
#038 RequestedOptions & FILE_NON_DIRECTORY_FILE)
#039 {
#040 return(STATUS_INVALID_PARAMETER);
#041 }
#042
#043 /* This a open operation for the volume itself */
打文件卷的操作。
#044 if (FileObject->FileName.Length == 0 &&
#045 FileObject->RelatedFileObject == NULL)
#046 {
#047 if (RequestedDisposition == FILE_CREATE ||
#048 RequestedDisposition == FILE_OVERWRITE_IF ||
#049 RequestedDisposition == FILE_SUPERSEDE)
#050 {
#051 return(STATUS_ACCESS_DENIED);
#052 }
#053 if (RequestedOptions & FILE_DIRECTORY_FILE)
#054 {
#055 return(STATUS_NOT_A_DIRECTORY);
#056 }
#057 pFcb = DeviceExt->VolumeFcb;
#058 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
#059 if (pCcb == NULL)
#060 {
#061 return (STATUS_INSUFFICIENT_RESOURCES);
#062 }
#063 RtlZeroMemory(pCcb,sizeof(VFATCCB));
#064 FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
#065 FileObject->FsContext = pFcb;
#066 FileObject->FsContext2 = pCcb;
#067 pFcb->RefCount++;
#068
#069 Irp->IoStatus.Information = FILE_OPENED;
打开当前设备的文件卷成功返回、
#070 return(STATUS_SUCCESS);
#071 }
#072
#073 /*
#074 * Check for illegal characters and illegale dot sequences in the file name
#075 */
#076 PathNameU = FileObject->FileName;
#077 c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
#078 last = c - 1;
#079 Dots = TRUE;
#080 while (c-- > PathNameU.Buffer)
#081 {
#082 if (*c == L'//' || c == PathNameU.Buffer)
#083 {
#084 if (Dots && last > c)
#085 {
#086 return(STATUS_OBJECT_NAME_INVALID);
#087 }
#088 last = c - 1;
#089 Dots = TRUE;
#090 }
#091 else if (*c != L'.')
#092 {
#093 Dots = FALSE;
#094 }
#095
#096 if (*c != '//' && vfatIsLongIllegal(*c))
#097 {
#098 return(STATUS_OBJECT_NAME_INVALID);
#099 }
#100 }
#101 if (FileObject->RelatedFileObject && PathNameU.Buffer[0] == L'//')
#102 {
#103 return(STATUS_OBJECT_NAME_INVALID);
#104 }
#105 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'//')
#106 {
#107 PathNameU.Length -= sizeof(WCHAR);
#108 }
#109
#110 /* Try opening the file. */
尝试打开文件。
#111 Status = VfatOpenFile (DeviceExt,&PathNameU,FileObject,&ParentFcb);
#112
#113 /*
#114 * If the directory containing the file to open doesn't exist then
#115 * fail immediately
#116 */
#117 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
#118 Status == STATUS_INVALID_PARAMETER ||
#119 Status == STATUS_DELETE_PENDING)
#120 {
#121 if (ParentFcb)
#122 {
#123 vfatReleaseFCB (DeviceExt,ParentFcb);
#124 }
#125 return(Status);
#126 }
如果获取状态和父目录控制块出错就返回。
#127 if (!NT_SUCCESS(Status) && ParentFcb == NULL)
#128 {
#129 DPRINT1("VfatOpenFile faild for '%wZ',status %x/n",Status);
#130 return Status;
#131 }
#132
#133 /*
#134 * If the file open Failed then create the required file
#135 */
#136 if (!NT_SUCCESS (Status))
#137 {
#138 if (RequestedDisposition == FILE_CREATE ||
#139 RequestedDisposition == FILE_OPEN_IF ||
#140 RequestedDisposition == FILE_OVERWRITE_IF ||
#141 RequestedDisposition == FILE_SUPERSEDE)
#142 {
#143 ULONG Attributes;
#144 Attributes = Stack->Parameters.Create.FileAttributes;
#145
#146 vfatSplitPathName(&PathNameU,NULL,&FileNameU);
#147 Status = VfatAddEntry (DeviceExt,&FileNameU,&pFcb,ParentFcb,RequestedOptions,
#148 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
#149 vfatReleaseFCB (DeviceExt,ParentFcb);
#150 if (NT_SUCCESS (Status))
#151 {
#152 Status = vfatAttachFCBToFileObject (DeviceExt,pFcb,FileObject);
#153 if ( !NT_SUCCESS(Status) )
#154 {
#155 vfatReleaseFCB (DeviceExt,pFcb);
#156 return Status;
#157 }
#158
设置IRP返回创建文件成功。
#159 Irp->IoStatus.Information = FILE_CREATED;
分配文件大小。
#160 VfatSetAllocationSizeInformation(FileObject,
#161 pFcb,
#162 DeviceExt,
#163 &Irp->Overlay.AllocationSize);
#164 VfatSetExtendedAttributes(FileObject,
#165 Irp->AssociatedIrp.SystemBuffer,
#166 Stack->Parameters.Create.EaLength);
#167
#168 if (PagingFileCreate)
#169 {
#170 pFcb->Flags |= FCB_IS_PAGE_FILE;
#171 }
#172 }
#173 else
#174 {
#175 return(Status);
#176 }
#177 }
#178 else
#179 {
#180 if (ParentFcb)
#181 {
#182 vfatReleaseFCB (DeviceExt,ParentFcb);
#183 }
#184 return(Status);
#185 }
#186 }
#187 else
#188 {
打开文件成功。
#189 if (ParentFcb)
#190 {
#191 vfatReleaseFCB (DeviceExt,ParentFcb);
#192 }
#193 /* Otherwise fail if the caller wanted to create a new file */
#194 if (RequestedDisposition == FILE_CREATE)
#195 {
#196 Irp->IoStatus.Information = FILE_EXISTS;
#197 VfatCloseFile (DeviceExt,FileObject);
#198 return(STATUS_OBJECT_NAME_COLLISION);
#199 }
#200
#201 pFcb = FileObject->FsContext;
#202
如果打开这个文件次数不为0,说明这个文件已经有一个打开的实例,检查文件是否允许共享打开。
#203 if (pFcb->OpenHandleCount != 0)
#204 {
#205 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
#206 Stack->Parameters.Create.ShareAccess,
#207 FileObject,
#208 &pFcb->FCBShareAccess,
#209 FALSE);
如果不允许共享打开,就出错返回。
#210 if (!NT_SUCCESS(Status))
#211 {
#212 VfatCloseFile (DeviceExt,FileObject);
#213 return(Status);
#214 }
#215 }
#216
#217 /*
#218 * Check the file has the requested attributes
#219 */
如果请求打开的不是目录文件,但当前的文件控制块是目录,那么就与请求的不一致出错。
#220 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
#221 *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
#222 {
#223 VfatCloseFile (DeviceExt,FileObject);
#224 return(STATUS_FILE_IS_A_DIRECTORY);
#225 }
如果请求的是目录,但文件控制块不是目录,那么也是出错的情况。
#226 if (RequestedOptions & FILE_DIRECTORY_FILE &&
#227 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
#228 {
#229 VfatCloseFile (DeviceExt,FileObject);
#230 return(STATUS_NOT_A_DIRECTORY);
#231 }
#232 #ifndef USE_ROS_CC_AND_FS
#233 if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
#234 {
#235 if (Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA ||
#236 RequestedDisposition == FILE_OVERWRITE ||
#237 RequestedDisposition == FILE_OVERWRITE_IF)
#238 {
#239 if (!MmFlushImageSection(&pFcb->SectionObjectPointers,MmFlushForWrite))
#240 {
#241 DPRINT1("%wZ/n",&pFcb->PathNameU);
#242 DPRINT1("%d %d %d/n",Stack->Parameters.Create.SecurityContext->DesiredAccess &
#243 FILE_WRITE_DATA,
#244 RequestedDisposition == FILE_OVERWRITE,RequestedDisposition
#245 == FILE_OVERWRITE_IF);
#246 VfatCloseFile (DeviceExt,FileObject);
#247 return STATUS_SHARING_VIOLATION;
#248 }
#249 }
#250 }
#251 #endif
#252 if (PagingFileCreate)
#253 {
#254 /* FIXME:
#255 * Do more checking for page files. It is possible,
#256 * that the file was opened and closed prevIoUsly
#257 * as a normal cached file. In this case,the cache
#258 * manager has referenced the fileobject and the fcb
#259 * is held in memory. Try to remove the fileobject
#260 * from cache manager and use the fcb.
#261 */
#262 if (pFcb->RefCount > 1)
#263 {
#264 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
#265 {
#266 VfatCloseFile(DeviceExt,FileObject);
#267 return(STATUS_INVALID_PARAMETER);
#268 }
#269 }
#270 else
#271 {
#272 pFcb->Flags |= FCB_IS_PAGE_FILE;
#273 }
#274 }
#275 else
#276 {
#277 if (pFcb->Flags & FCB_IS_PAGE_FILE)
#278 {
#279 VfatCloseFile(DeviceExt,FileObject);
#280 return(STATUS_INVALID_PARAMETER);
#281 }
#282 }
#283
#284
#285 if (RequestedDisposition == FILE_OVERWRITE ||
#286 RequestedDisposition == FILE_OVERWRITE_IF ||
#287 RequestedDisposition == FILE_SUPERSEDE)
#288 {
#289 ExAcquireResourceExclusiveLite(&(pFcb->MainResource),TRUE);
#290 Status = VfatSetAllocationSizeInformation (FileObject,
#291 pFcb,
#292 DeviceExt,
#293 &Irp->Overlay.AllocationSize);
#294 ExReleaseResourceLite(&(pFcb->MainResource));
#295 if (!NT_SUCCESS (Status))
#296 {
#297 VfatCloseFile (DeviceExt,FileObject);
#298 return(Status);
#299 }
#300 }
#301
#302 if (RequestedDisposition == FILE_SUPERSEDE)
#303 {
#304 Irp->IoStatus.Information = FILE_SUPERSEDED;
#305 }
#306 else if (RequestedDisposition == FILE_OVERWRITE ||
#307 RequestedDisposition == FILE_OVERWRITE_IF)
#308 {
#309 Irp->IoStatus.Information = FILE_OVERWRITTEN;
#310 }
#311 else
#312 {
#313 Irp->IoStatus.Information = FILE_OPENED;
#314 }
#315 }
#316
#317 if (pFcb->OpenHandleCount == 0)
#318 {
#319 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
#320 Stack->Parameters.Create.ShareAccess,
#321 FileObject,
#322 &pFcb->FCBShareAccess);
#323 }
#324 else
#325 {
#326 IoUpdateShareAccess(
#327 FileObject,
#328 &pFcb->FCBShareAccess
#329 );
#330
#331 }
#332
#333 pFcb->OpenHandleCount++;
#334
#335 /* FIXME : test write access if requested */
#336
#337 return(Status);
#338}