0

I'm writing an application that works from efi environment (f.e. can be run from EFI shell). My problem is that I cannot create any file on my machine's volume. I tested it on WMVare and on real machines with ntfs and even on mac with hfs+ (got drivers frim http://efi.akeo.ie/). I can read everything, but when I try to write I got error code 8 (EFI_WRITE_PROTECTED).

Is there any way to avoid this protection? Maybe I should go deeper and work with block devices instead of file systems (don't really want to do this)?

My code. Driver Loading (I think it works fine, just for the case):

Print(L"\nLoading NTFS Driver... ");
Status = BS->LocateHandleBuffer(ByProtocol, &FileSystemProtocol, NULL, &NumHandles, &Handle);
if (EFI_ERROR(Status)) 
{
    PrintStatusError(Status, L"\n  Failed to list file systems");
    goto exit;
}

for (i = 0; i < NumHandles; i++) 
{
    // Look for our NTFS driver. Note: the path MUST be specified using backslashes!
    DevicePath = FileDevicePath(Handle[i], DriverPath);
    if (DevicePath == NULL)
        continue;

    // Attempt to load the driver. If that fails, it means we weren't on the right partition
    Status = BS->LoadImage(FALSE, ImageHandle, DevicePath, NULL, 0, &DriverHandle);
    SafeFree(DevicePath);
    if (EFI_ERROR(Status))
        continue;

    // Load was a success - attempt to start the driver
    Status = BS->StartImage(DriverHandle, NULL, NULL);
    if (EFI_ERROR(Status)) 
    {
        PrintStatusError(Status, L"\n  Driver did not start");
        goto exit;
    }
    Print(L"LOADED");
    break;
}
SafeFree(Handle);
if (i >= NumHandles) 
{
    Print(L"\n  Failed to locate driver. Please check that '%s' exists on the FAT partition", DriverPath);
    Status = EFI_NOT_FOUND;
    goto exit;
}

File reading/writing:

// Now enumerate all disk handles again
Status = BS->LocateHandleBuffer(ByProtocol, &DiskIoProtocol, NULL, &NumHandles, &Handle);
if (EFI_ERROR(Status)) 
{
    PrintStatusError(Status, L"\n  Failed to list disks");
    goto exit;
}

// Go through the partitions and find the NTFS one
for (i = 0; i < NumHandles; i++)
{
    dev_path = DevicePathFromHandle(Handle[i]);
    Print(L"\nVolume [%d]: ", i);

    // Calling ConnectController() on a handle starts all the drivers that can service it
    Status = BS->ConnectController(Handle[i], NULL, NULL, TRUE);
    if (Status == EFI_SUCCESS)
    {
        Print(L"Driver connected! ");
    }

    // Open the the volume
    Status = BS->HandleProtocol(Handle[i], &FileSystemProtocol, (VOID**)&Volume);
    if (EFI_ERROR(Status))
    {
        PrintStatusError(Status, L"\n  Could not find volume");
        continue;
    }

    // Open the root directory
    Root = NULL;
    Status = Volume->OpenVolume(Volume, &Root);
    if ((EFI_ERROR(Status)) || (Root == NULL))
    {
        PrintStatusError(Status, L"\n  Could not open Root directory");
        continue;
    }

    Status = Root->Open(Root, &FileHandle, L"bb.txt", EFI_FILE_MODE_READ, 0);
    Print(L"\n  Read %d", Status);
    if (Status == EFI_SUCCESS)
    {
        UINTN fsize = 5;
        char fdata[5];
        Status = FileHandle->Read(FileHandle, &fsize, fdata);
        fdata[4] = 0;
        Print(L" %d [%x%x%x%x] ", Status, fdata[0], fdata[1], fdata[2], fdata[3]);
        FileHandle->Close(FileHandle);
    }

    Status = Root->Open(Root, &FileHandle, L"aa.txt", EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
    Print(L"  Create %d", Status);
    if (Status == EFI_SUCCESS)
    {
        UINTN fsize = 4;
        Status = FileHandle->Write(FileHandle, &fsize, file_content);
        Print(L"    Wr %d", Status);
        Status = FileHandle->Flush(FileHandle);
        Print(L"    Fl %d", Status);
        Status = FileHandle->Close(FileHandle);
        Print(L"    Cl %d", Status);
    }
}

<---------------- after a bit of investigation ------------------------>

It turned out that the only thing we can do with machine's file system is to change existing file content. Seems like it is the only possible way without monthes of research. But still, its not easy to do:

I have "EFI_FILE *fileHandle" variable and can read mine pre-created file. How to find corresponding LBA (or offset for DiskIO)?

I looked to EFI sources (from AMI bios sources) and found that there are hidden data placed right after EFI_FILE struct:

    typedef struct _FILE_HANDLE_INSTANCE {

    EFI_FILE_PROTOCOL FileHandle;                       // Should be the first entry in the structure
    EFI_STATUS HandleInstanceStatus;
    FILE_HANDLE *pFH;
    UINT64 OpenMode;                            // Open Modes
    UINT64 Position;                            //
    UINT32 CurrentCluster;                      // will point to sector number where the position is pointing currently
    UINT32 CurrentClusterOffset;                        // will point to sector number where the position is pointing currently
    BOOLEAN MEDIA_NOT_VALID;                    // Will be true if for any reason current instances cannot use the volume Eg: Change in Media
    DLINK ViFILink;                             // This link is for the DLIST OpenFIs in the VOLUME_INFO
    } FILE_HANDLE_INSTANCE;

And they operate with it like this:

void example_read_inside_efi(EFI_FILE *FileHandle, ...)
{
FILE_HANDLE_INSTANCE    *fhi = (FILE_HANDLE_INSTANCE *)FileHandle;
...

But when I try to read that struct, it don't seem that this struct has right field values (f.e. FILE_HANDLE pointer is not valid). I don't know what to do with this next. Have no ideas..

So, the question is: how can i find corresponding LBA (or offset for diskIO) if I have valid EFI_FILE pointer?

LeTigre
  • 1
  • 2
  • It turned out that I missed very important note at http://efi.akeo.ie/ saying that his drivers are READ-ONLY. That drivers do not satisfy me then. But the main question is still here - how to create a file on machine's volume.. – LeTigre Aug 24 '15 at 11:00
  • Unfortunately nothing you can do if UEFI FS Driver simply doesn't support writing.Using BlockIO directly to NTFS will be tricky to say at least. It's not an easy walk. Why do you think driver doesn't have that capability? Because it's way too much work for an Open Source project. Maybe they will add that caps in the future. I wrote FAT32 FS once it's relatively easy and straightforward and If I had to I would do it with FAT32 (let's imagine that it was read-only for some reason) but with NTFS... I wouldn't even go there. – Alex D Aug 25 '15 at 16:54
  • Actually I have an idea! If you could create an empty non-zero sized file from OS Present. Then you could use it like a virtual space. You have to find an offset on the disk and write the data into that file directly via BlockIo. The file is already in the NTFS system, so all difficult work is already done. ;) I don't know whether it will help but I like that idea! :) – Alex D Aug 25 '15 at 17:00
  • Thanks, Alex! Plese, see my answer in question body. – LeTigre Aug 26 '15 at 15:53

0 Answers0