zl程序教程

您现在的位置是:首页 >  系统

当前栏目

reactos操作系统实现(126)

操作系统 实现 reactos 126
2023-09-14 09:10:38 时间

 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", &PathNameU, 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);

 

为这个文件添加一个FAT的入口项。

#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  }