EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, IN struct fsw_dnode *dno, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; EFI_FILE_INFO *FileInfo; UINTN RequiredSize; struct fsw_dnode_stat sb; // make sure the dnode has complete info Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume); if (EFI_ERROR(Status)) return Status; // TODO: check/assert that the dno's name is in UTF16 // check buffer size RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name); if (*BufferSize < RequiredSize) { // TODO: wind back the directory in this case #if DEBUG_LEVEL Print(L"...BUFFER TOO SMALL\n"); #endif *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // fill structure ZeroMem(Buffer, RequiredSize); FileInfo = (EFI_FILE_INFO *)Buffer; FileInfo->Size = RequiredSize; FileInfo->FileSize = dno->size; FileInfo->Attribute = 0; if (dno->type == FSW_DNODE_TYPE_DIR) FileInfo->Attribute |= EFI_FILE_DIRECTORY; fsw_efi_strcpy(FileInfo->FileName, &dno->name); // get the missing info from the fs driver ZeroMem(&sb, sizeof(struct fsw_dnode_stat)); sb.store_time_posix = fsw_efi_store_time_posix; sb.store_attr_posix = fsw_efi_store_attr_posix; sb.host_data = FileInfo; Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume); if (EFI_ERROR(Status)) return Status; FileInfo->PhysicalSize = sb.used_bytes; // prepare for return *BufferSize = RequiredSize; #if DEBUG_LEVEL Print(L"...returning '%s'\n", FileInfo->FileName); #endif return EFI_SUCCESS; }
EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, OUT EFI_FILE **NewFileHandle) { EFI_STATUS Status; FSW_FILE_DATA *File; FSW_MSG_DEBUG((FSW_MSGSTR(__FUNCTION__ ": enter\n"))); // make sure the dnode has complete info Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data); if (EFI_ERROR(Status)) { goto Done; } // check type if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR) { Status = EFI_UNSUPPORTED; goto Done; } // allocate file structure File = AllocateZeroPool(sizeof(FSW_FILE_DATA)); File->Signature = FSW_FILE_DATA_SIGNATURE; if (dno->type == FSW_DNODE_TYPE_FILE) File->Type = FSW_EFI_FILE_TYPE_FILE; else if (dno->type == FSW_DNODE_TYPE_DIR) File->Type = FSW_EFI_FILE_TYPE_DIR; // open shandle Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand), (FSW_VOLUME_DATA *)dno->vol->host_data); if (EFI_ERROR(Status)) { FreePool(File); goto Done; } // populate the file handle File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION; File->FileHandle.Open = fsw_efi_FileHandle_Open; File->FileHandle.Close = fsw_efi_FileHandle_Close; File->FileHandle.Delete = fsw_efi_FileHandle_Delete; File->FileHandle.Read = fsw_efi_FileHandle_Read; File->FileHandle.Write = fsw_efi_FileHandle_Write; File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition; File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition; File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo; File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo; File->FileHandle.Flush = fsw_efi_FileHandle_Flush; *NewFileHandle = &File->FileHandle; Status = EFI_SUCCESS; Done: FSW_MSG_DEBUG((FSW_MSGSTR(__FUNCTION__ ": leaving with %r\n"), Status)); return Status; }
EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; struct fsw_dnode *dno; #if DEBUG_LEVEL Print(L"fsw_efi_dir_read...\n"); #endif // read the next entry Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume); if (Status == EFI_NOT_FOUND) { // end of directory *BufferSize = 0; #if DEBUG_LEVEL Print(L"...no more entries\n"); #endif return EFI_SUCCESS; } if (EFI_ERROR(Status)) return Status; // get info into buffer Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer); fsw_dnode_release(dno); return Status; }
static EFI_STATUS fsw_efi_ReMount(IN FSW_VOLUME_DATA *pVolume, IN EFI_HANDLE ControllerHandle, EFI_DISK_IO *pDiskIo, EFI_BLOCK_IO *pBlockIo) { EFI_STATUS Status; VBoxLogFlowFuncEnter(); pVolume->Signature = FSW_VOLUME_DATA_SIGNATURE; pVolume->Handle = ControllerHandle; pVolume->DiskIo = pDiskIo; pVolume->MediaId = pBlockIo->Media->MediaId; pVolume->LastIOStatus = EFI_SUCCESS; // mount the filesystem Status = fsw_efi_map_status(fsw_mount(pVolume, &fsw_efi_host_table, &FSW_FSTYPE_TABLE_NAME(FSTYPE), &pVolume->vol), pVolume); VBoxLogFlowFuncMarkRC(Status); if (!EFI_ERROR(Status)) { // register the SimpleFileSystem protocol pVolume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION; pVolume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &pVolume->FileSystem, NULL); if (EFI_ERROR(Status)) Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status); } VBoxLogFlowFuncLeaveRC(Status); return Status; }
EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; struct fsw_dnode *dno; struct fsw_dnode *target_dno; struct fsw_string lookup_path; #if DEBUG_LEVEL Print(L"fsw_efi_dir_open: '%s'\n", FileName); #endif if (OpenMode != EFI_FILE_MODE_READ) return EFI_WRITE_PROTECTED; lookup_path.type = FSW_STRING_TYPE_UTF16; lookup_path.len = (int)StrLen(FileName); lookup_path.size = lookup_path.len * sizeof(fsw_u16); lookup_path.data = FileName; // resolve the path (symlinks along the way are automatically resolved) Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), Volume); if (EFI_ERROR(Status)) return Status; // if the final node is a symlink, also resolve it Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume); fsw_dnode_release(dno); if (EFI_ERROR(Status)) return Status; dno = target_dno; // make a new EFI handle for the target dnode Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle); fsw_dnode_release(dno); return Status; }
EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; fsw_u32 buffer_size; FSW_MSG_DEBUG((FSW_MSGSTR(__FUNCTION__ ": enter to read %d bytes\n"), *BufferSize)); buffer_size = (fsw_u32)(*BufferSize); Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer), (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data); *BufferSize = buffer_size; FSW_MSG_DEBUG((FSW_MSGSTR(__FUNCTION__ ": leaving with %r\n"), Status)); return Status; }
EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; fsw_u32 buffer_size; #if DEBUG_LEVEL Print(L"fsw_efi_file_read %d bytes\n", *BufferSize); #endif buffer_size = (fsw_u32)*BufferSize; Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer), (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data); *BufferSize = buffer_size; return Status; }
EFI_STATUS fsw_efi_AttachVolume(IN EFI_HANDLE ControllerHandle, IN EFI_DISK_IO_PROTOCOL *pDiskIo, IN EFI_BLOCK_IO_PROTOCOL *pBlockIo) { EFI_STATUS Status; FSW_VOLUME_DATA *pVolume; pVolume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA)); if (pVolume == NULL) { return EFI_OUT_OF_RESOURCES; } pVolume->Signature = FSW_VOLUME_DATA_SIGNATURE; pVolume->Handle = ControllerHandle; pVolume->DiskIo = pDiskIo; pVolume->MediaId = pBlockIo->Media->MediaId; pVolume->FileSystem.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; pVolume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; pVolume->LastIOStatus = EFI_SUCCESS; Status = fsw_efi_map_status(fsw_mount(pVolume, &fsw_efi_host_table, &FSW_FSTYPE_TABLE_NAME(FSTYPE), &pVolume->vol), pVolume); if (EFI_ERROR(Status)) { goto Done; } Status = BS->InstallMultipleProtocolInterfaces( &pVolume->Handle, &PROTO_NAME(SimpleFileSystemProtocol), &pVolume->FileSystem, NULL); if (EFI_ERROR(Status)) { goto Done; } DEBUG((EFI_D_INIT, "fsw_efi: Installed volume on %p\n", ControllerHandle)); Done: if (EFI_ERROR(Status)) { fsw_efi_DetachVolume(pVolume); } return Status; }
EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { EFI_STATUS Status; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DISK_IO2_PROTOCOL *DiskIo2; FSW_VOLUME_DATA *Volume; #if DEBUG_LEVEL // Print(L"fsw_efi_DriverBinding_Start\n"); #endif // open consumed protocols Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(BlockIo2Protocol), (VOID **) &BlockIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { BlockIo2 = NULL; } Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(BlockIoProtocol), (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId if ((BlockIo2 == NULL) && EFI_ERROR(Status)) { // Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status); return Status; } Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(DiskIo2Protocol), (VOID **) &DiskIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR(Status)) { DiskIo2 = NULL; } Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if ((DiskIo2 == NULL) && EFI_ERROR(Status)) { // DBG("Fsw ERROR: OpenProtocol(DiskIo) returned %r\n", Status); return Status; } // allocate volume structure Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA)); Volume->Signature = FSW_VOLUME_DATA_SIGNATURE; Volume->Handle = ControllerHandle; Volume->DiskIo = DiskIo; Volume->DiskIo2 = DiskIo2; Volume->LastIOStatus = EFI_SUCCESS; if (BlockIo2 != NULL) { Volume->MediaId = BlockIo2->Media->MediaId; } else { Volume->MediaId = BlockIo->Media->MediaId; } // mount the filesystem Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table, &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol), Volume); if (!EFI_ERROR(Status)) { // register the SimpleFileSystem protocol Volume->FileSystem.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; Status = BS->InstallMultipleProtocolInterfaces( &ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) { // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status); } } // on errors, close the opened protocols if (EFI_ERROR(Status)) { if (Volume->vol != NULL) fsw_unmount(Volume->vol); FreePool(Volume); BS->CloseProtocol(ControllerHandle, &PROTO_NAME(DiskIo2Protocol), This->DriverBindingHandle, ControllerHandle); BS->CloseProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); } return Status; }
EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer) { EFI_STATUS Status; FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; EFI_FILE_SYSTEM_INFO *FSInfo; UINTN RequiredSize; struct fsw_volume_stat vsb; if (CompareGuid(InformationType, &GUID_NAME(FileInfo))) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n"); #endif Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer); } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemInfo))) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n"); #endif // check buffer size RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label); if (*BufferSize < RequiredSize) { *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // fill structure FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer; FSInfo->Size = RequiredSize; FSInfo->ReadOnly = TRUE; FSInfo->BlockSize = Volume->vol->log_blocksize; fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label); // get the missing info from the fs driver ZeroMem(&vsb, sizeof(struct fsw_volume_stat)); Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume); if (EFI_ERROR(Status)) return Status; FSInfo->VolumeSize = vsb.total_bytes; FSInfo->FreeSpace = vsb.free_bytes; // prepare for return *BufferSize = RequiredSize; Status = EFI_SUCCESS; } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemVolumeLabelInfoId))) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n"); #endif // check buffer size RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label); if (*BufferSize < RequiredSize) { *BufferSize = RequiredSize; return EFI_BUFFER_TOO_SMALL; } // copy volume label fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label); // prepare for return *BufferSize = RequiredSize; Status = EFI_SUCCESS; } else { Status = EFI_UNSUPPORTED; } return Status; }