UdfOpenVolume (
  IN   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
  OUT  EFI_FILE_PROTOCOL                **Root
  )
{
  EFI_TPL                     OldTpl;
  EFI_STATUS                  Status;
  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;
  PRIVATE_UDF_FILE_DATA       *PrivFileData;

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (This == NULL || Root == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto Error_Invalid_Params;
  }

  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);

  if (PrivFsData->OpenFiles == 0) {
    //
    // There is no more open files. Read volume information again since it was
    // cleaned up on the last UdfClose() call.
    //
    Status = ReadUdfVolumeInformation (
      PrivFsData->BlockIo,
      PrivFsData->DiskIo,
      &PrivFsData->Volume
      );
    if (EFI_ERROR (Status)) {
      goto Error_Read_Udf_Volume;
    }
  }

  CleanupFileInformation (&PrivFsData->Root);

  //
  // Find root directory file.
  //
  Status = FindRootDirectory (
    PrivFsData->BlockIo,
    PrivFsData->DiskIo,
    &PrivFsData->Volume,
    &PrivFsData->Root
    );
  if (EFI_ERROR (Status)) {
    goto Error_Find_Root_Dir;
  }

  PrivFileData =
    (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
  if (PrivFileData == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Error_Alloc_Priv_File_Data;
  }

  PrivFileData->Signature        = PRIVATE_UDF_FILE_DATA_SIGNATURE;
  PrivFileData->SimpleFs         = This;
  PrivFileData->Root             = &PrivFsData->Root;
  PrivFileData->IsRootDirectory  = TRUE;

  CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,
           sizeof (EFI_FILE_PROTOCOL));

  *Root = &PrivFileData->FileIo;

  PrivFsData->OpenFiles++;

  gBS->RestoreTPL (OldTpl);

  return EFI_SUCCESS;

Error_Alloc_Priv_File_Data:
  CleanupFileInformation (&PrivFsData->Root);

Error_Find_Root_Dir:

Error_Read_Udf_Volume:
Error_Invalid_Params:
  gBS->RestoreTPL (OldTpl);

  return Status;
}

UdfOpenVolume (
  IN   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
  OUT  EFI_FILE_PROTOCOL                **Root
  )
{
  EFI_TPL                     OldTpl;
  EFI_STATUS                  Status;
  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;
  PRIVATE_UDF_FILE_DATA       *PrivFileData;

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  if (This == NULL || Root == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto Error_Invalid_Params;
  }

  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);

  if (PrivFsData->OpenFiles == 0) {
     
     
     
     
    Status = ReadUdfVolumeInformation (
      PrivFsData->BlockIo,
      PrivFsData->DiskIo,
      &PrivFsData->Volume
      );
    if (EFI_ERROR (Status)) {
      goto Error_Read_Udf_Volume;
    }
  }

  CleanupFileInformation (&PrivFsData->Root);

   
   
   
  Status = FindRootDirectory (
    PrivFsData->BlockIo,
    PrivFsData->DiskIo,
    &PrivFsData->Volume,
    &PrivFsData->Root
    );
  if (EFI_ERROR (Status)) {
    goto Error_Find_Root_Dir;
  }

  PrivFileData =
    (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
  if (PrivFileData == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Error_Alloc_Priv_File_Data;
  }

  PrivFileData->Signature        = PRIVATE_UDF_FILE_DATA_SIGNATURE;
  PrivFileData->SimpleFs         = This;
  PrivFileData->Root             = &PrivFsData->Root;
  PrivFileData->IsRootDirectory  = TRUE;

  CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,
           sizeof (EFI_FILE_PROTOCOL));

  *Root = &PrivFileData->FileIo;

  PrivFsData->OpenFiles++;

  gBS->RestoreTPL (OldTpl);

  return EFI_SUCCESS;

Error_Alloc_Priv_File_Data:
  CleanupFileInformation (&PrivFsData->Root);

Error_Find_Root_Dir:

Error_Read_Udf_Volume:
Error_Invalid_Params:
  gBS->RestoreTPL (OldTpl);

  return Status;
}
