Home | History | Annotate | Download | only in Host
      1 /**@file
      2 
      3 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 **/
     13 
     14 #include "Host.h"
     15 
     16 #define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')
     17 typedef struct {
     18   UINTN                       Signature;
     19 
     20   EMU_IO_THUNK_PROTOCOL       *Thunk;
     21 
     22   char                        *Filename;
     23   UINTN                       ReadMode;
     24   UINTN                       Mode;
     25 
     26   int                         fd;
     27 
     28   BOOLEAN                     RemovableMedia;
     29   BOOLEAN                     WriteProtected;
     30 
     31   UINT64                      NumberOfBlocks;
     32   UINT32                      BlockSize;
     33 
     34   EMU_BLOCK_IO_PROTOCOL       EmuBlockIo;
     35   EFI_BLOCK_IO_MEDIA          *Media;
     36 
     37 } EMU_BLOCK_IO_PRIVATE;
     38 
     39 #define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \
     40          CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)
     41 
     42 
     43 
     44 EFI_STATUS
     45 EmuBlockIoReset (
     46   IN EMU_BLOCK_IO_PROTOCOL    *This,
     47   IN BOOLEAN                  ExtendedVerification
     48   );
     49 
     50 
     51 /*++
     52 
     53 This function extends the capability of SetFilePointer to accept 64 bit parameters
     54 
     55 **/
     56 EFI_STATUS
     57 SetFilePointer64 (
     58   IN  EMU_BLOCK_IO_PRIVATE        *Private,
     59   IN  INT64                      DistanceToMove,
     60   OUT UINT64                     *NewFilePointer,
     61   IN  INT32                      MoveMethod
     62   )
     63 {
     64   EFI_STATUS    Status;
     65   off_t         res;
     66   off_t         offset = DistanceToMove;
     67 
     68   Status = EFI_SUCCESS;
     69   res = lseek (Private->fd, offset, (int)MoveMethod);
     70   if (res == -1) {
     71     Status = EFI_INVALID_PARAMETER;
     72   }
     73 
     74   if (NewFilePointer != NULL) {
     75     *NewFilePointer = res;
     76   }
     77 
     78   return Status;
     79 }
     80 
     81 
     82 EFI_STATUS
     83 EmuBlockIoOpenDevice (
     84   IN EMU_BLOCK_IO_PRIVATE   *Private
     85   )
     86 {
     87   EFI_STATUS            Status;
     88   UINT64                FileSize;
     89   struct statfs         buf;
     90 
     91 
     92   //
     93   // If the device is already opened, close it
     94   //
     95   if (Private->fd >= 0) {
     96     EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
     97   }
     98 
     99   //
    100   // Open the device
    101   //
    102   Private->fd = open (Private->Filename, Private->Mode, 0644);
    103   if (Private->fd < 0) {
    104     printf ("EmuOpenBlock: Could not open %s: %s\n", Private->Filename, strerror(errno));
    105     Private->Media->MediaPresent  = FALSE;
    106     Status                        = EFI_NO_MEDIA;
    107     goto Done;
    108   }
    109 
    110   if (!Private->Media->MediaPresent) {
    111     //
    112     // BugBug: try to emulate if a CD appears - notify drivers to check it out
    113     //
    114     Private->Media->MediaPresent = TRUE;
    115   }
    116 
    117   //
    118   // get the size of the file
    119   //
    120   Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
    121   if (EFI_ERROR (Status)) {
    122     printf ("EmuOpenBlock: Could not get filesize of %s\n", Private->Filename);
    123     Status = EFI_UNSUPPORTED;
    124     goto Done;
    125   }
    126 
    127   if (FileSize == 0) {
    128     // lseek fails on a real device. ioctl calls are OS specific
    129 #if __APPLE__
    130     {
    131       UINT32 BlockSize;
    132 
    133       if (ioctl (Private->fd, DKIOCGETBLOCKSIZE, &BlockSize) == 0) {
    134         Private->Media->BlockSize = BlockSize;
    135       }
    136       if (ioctl (Private->fd, DKIOCGETBLOCKCOUNT, &Private->NumberOfBlocks) == 0) {
    137         if ((Private->NumberOfBlocks == 0) && (BlockSize == 0x800)) {
    138           // A DVD is ~ 4.37 GB so make up a number
    139           Private->Media->LastBlock = (0x100000000ULL/0x800) - 1;
    140         } else {
    141           Private->Media->LastBlock = Private->NumberOfBlocks - 1;
    142         }
    143       }
    144       ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity);
    145     }
    146 #else
    147     {
    148       size_t BlockSize;
    149       UINT64 DiskSize;
    150 
    151       if (ioctl (Private->fd, BLKSSZGET, &BlockSize) == 0) {
    152         Private->Media->BlockSize = BlockSize;
    153       }
    154       if (ioctl (Private->fd, BLKGETSIZE64, &DiskSize) == 0) {
    155         Private->NumberOfBlocks = DivU64x32 (DiskSize, (UINT32)BlockSize);
    156         Private->Media->LastBlock = Private->NumberOfBlocks - 1;
    157       }
    158     }
    159 #endif
    160 
    161   } else {
    162     Private->Media->BlockSize = Private->BlockSize;
    163     Private->NumberOfBlocks = DivU64x32 (FileSize, Private->Media->BlockSize);
    164     Private->Media->LastBlock = Private->NumberOfBlocks - 1;
    165 
    166     if (fstatfs (Private->fd, &buf) == 0) {
    167 #if __APPLE__
    168       Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;
    169 #else
    170       Private->Media->OptimalTransferLengthGranularity = buf.f_bsize/buf.f_bsize;
    171 #endif
    172     }
    173   }
    174 
    175   DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));
    176   Status = EFI_SUCCESS;
    177 
    178 Done:
    179   if (EFI_ERROR (Status)) {
    180     if (Private->fd >= 0) {
    181       EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
    182     }
    183   }
    184 
    185   return Status;
    186 }
    187 
    188 
    189 EFI_STATUS
    190 EmuBlockIoCreateMapping (
    191   IN     EMU_BLOCK_IO_PROTOCOL    *This,
    192   IN     EFI_BLOCK_IO_MEDIA       *Media
    193   )
    194 {
    195   EFI_STATUS              Status;
    196   EMU_BLOCK_IO_PRIVATE    *Private;
    197 
    198   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    199 
    200   Private->Media = Media;
    201 
    202   Media->MediaId          = 0;
    203   Media->RemovableMedia   = Private->RemovableMedia;
    204   Media->MediaPresent     = TRUE;
    205   Media->LogicalPartition = FALSE;
    206   Media->ReadOnly         = Private->WriteProtected;
    207   Media->WriteCaching     = FALSE;
    208   Media->IoAlign          = 1;
    209   Media->LastBlock        = 0; // Filled in by OpenDevice
    210 
    211   // EFI_BLOCK_IO_PROTOCOL_REVISION2
    212   Media->LowestAlignedLba              = 0;
    213   Media->LogicalBlocksPerPhysicalBlock = 0;
    214 
    215 
    216   // EFI_BLOCK_IO_PROTOCOL_REVISION3
    217   Media->OptimalTransferLengthGranularity = 0;
    218 
    219   Status = EmuBlockIoOpenDevice (Private);
    220 
    221 
    222   return Status;
    223 }
    224 
    225 
    226 EFI_STATUS
    227 EmuBlockIoError (
    228   IN EMU_BLOCK_IO_PRIVATE      *Private
    229   )
    230 {
    231   EFI_STATUS            Status;
    232   BOOLEAN               ReinstallBlockIoFlag;
    233 
    234 
    235   switch (errno) {
    236 
    237   case EAGAIN:
    238     Status                        = EFI_NO_MEDIA;
    239     Private->Media->ReadOnly      = FALSE;
    240     Private->Media->MediaPresent  = FALSE;
    241     ReinstallBlockIoFlag          = FALSE;
    242     break;
    243 
    244   case EACCES:
    245     Private->Media->ReadOnly      = FALSE;
    246     Private->Media->MediaPresent  = TRUE;
    247     Private->Media->MediaId += 1;
    248     ReinstallBlockIoFlag  = TRUE;
    249     Status                = EFI_MEDIA_CHANGED;
    250     break;
    251 
    252   case EROFS:
    253     Private->Media->ReadOnly  = TRUE;
    254     ReinstallBlockIoFlag      = FALSE;
    255     Status                    = EFI_WRITE_PROTECTED;
    256     break;
    257 
    258   default:
    259     ReinstallBlockIoFlag  = FALSE;
    260     Status                = EFI_DEVICE_ERROR;
    261     break;
    262   }
    263   return Status;
    264 }
    265 
    266 
    267 EFI_STATUS
    268 EmuBlockIoReadWriteCommon (
    269   IN  EMU_BLOCK_IO_PRIVATE        *Private,
    270   IN UINT32                       MediaId,
    271   IN EFI_LBA                      Lba,
    272   IN UINTN                        BufferSize,
    273   IN VOID                         *Buffer,
    274   IN CHAR8                        *CallerName
    275   )
    276 {
    277   EFI_STATUS  Status;
    278   UINTN       BlockSize;
    279   UINT64      LastBlock;
    280   INT64       DistanceToMove;
    281   UINT64      DistanceMoved;
    282 
    283   if (Private->fd < 0) {
    284     Status = EmuBlockIoOpenDevice (Private);
    285     if (EFI_ERROR (Status)) {
    286       return Status;
    287     }
    288   }
    289 
    290   if (!Private->Media->MediaPresent) {
    291     DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
    292     return EFI_NO_MEDIA;
    293   }
    294 
    295   if (Private->Media->MediaId != MediaId) {
    296     return EFI_MEDIA_CHANGED;
    297   }
    298 
    299   if ((UINTN) Buffer % Private->Media->IoAlign != 0) {
    300     return EFI_INVALID_PARAMETER;
    301   }
    302 
    303   //
    304   // Verify buffer size
    305   //
    306   BlockSize = Private->Media->BlockSize;
    307   if (BufferSize == 0) {
    308     DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
    309     return EFI_SUCCESS;
    310   }
    311 
    312   if ((BufferSize % BlockSize) != 0) {
    313     DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
    314     return EFI_BAD_BUFFER_SIZE;
    315   }
    316 
    317   LastBlock = Lba + (BufferSize / BlockSize) - 1;
    318   if (LastBlock > Private->Media->LastBlock) {
    319     DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
    320     return EFI_INVALID_PARAMETER;
    321   }
    322   //
    323   // Seek to End of File
    324   //
    325   DistanceToMove = MultU64x32 (Lba, BlockSize);
    326   Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);
    327 
    328   if (EFI_ERROR (Status)) {
    329     DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
    330     return EmuBlockIoError (Private);
    331   }
    332 
    333   return EFI_SUCCESS;
    334 }
    335 
    336 
    337 /**
    338   Read BufferSize bytes from Lba into Buffer.
    339 
    340   This function reads the requested number of blocks from the device. All the
    341   blocks are read, or an error is returned.
    342   If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
    343   non-blocking I/O is being used, the Event associated with this request will
    344   not be signaled.
    345 
    346   @param[in]       This       Indicates a pointer to the calling context.
    347   @param[in]       MediaId    Id of the media, changes every time the media is
    348                               replaced.
    349   @param[in]       Lba        The starting Logical Block Address to read from.
    350   @param[in, out]  Token	    A pointer to the token associated with the transaction.
    351   @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
    352   @param[out]      Buffer     A pointer to the destination buffer for the data. The
    353                               caller is responsible for either having implicit or
    354                               explicit ownership of the buffer.
    355 
    356   @retval EFI_SUCCESS           The read request was queued if Token->Event is
    357                                 not NULL.The data was read correctly from the
    358                                 device if the Token->Event is NULL.
    359   @retval EFI_DEVICE_ERROR      The device reported an error while performing
    360                                 the read.
    361   @retval EFI_NO_MEDIA          There is no media in the device.
    362   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
    363   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
    364                                 intrinsic block size of the device.
    365   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    366                                 or the buffer is not on proper alignment.
    367   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
    368                                 of resources.
    369 **/
    370 EFI_STATUS
    371 EmuBlockIoReadBlocks (
    372   IN     EMU_BLOCK_IO_PROTOCOL  *This,
    373   IN     UINT32                 MediaId,
    374   IN     EFI_LBA                LBA,
    375   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
    376   IN     UINTN                  BufferSize,
    377      OUT VOID                   *Buffer
    378   )
    379 {
    380   EFI_STATUS              Status;
    381   EMU_BLOCK_IO_PRIVATE    *Private;
    382   ssize_t                 len;
    383 
    384   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    385 
    386   Status  = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");
    387   if (EFI_ERROR (Status)) {
    388     goto Done;
    389   }
    390 
    391   len = read (Private->fd, Buffer, BufferSize);
    392   if (len != BufferSize) {
    393     DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
    394     Status = EmuBlockIoError (Private);
    395     goto Done;
    396   }
    397 
    398   //
    399   // If we read then media is present.
    400   //
    401   Private->Media->MediaPresent = TRUE;
    402   Status = EFI_SUCCESS;
    403 
    404 Done:
    405   if (Token != NULL) {
    406     if (Token->Event != NULL) {
    407       // Caller is responcible for signaling EFI Event
    408       Token->TransactionStatus = Status;
    409       return EFI_SUCCESS;
    410     }
    411   }
    412   return Status;
    413 }
    414 
    415 
    416 /**
    417   Write BufferSize bytes from Lba into Buffer.
    418 
    419   This function writes the requested number of blocks to the device. All blocks
    420   are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
    421   EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
    422   being used, the Event associated with this request will not be signaled.
    423 
    424   @param[in]       This       Indicates a pointer to the calling context.
    425   @param[in]       MediaId    The media ID that the write request is for.
    426   @param[in]       Lba        The starting logical block address to be written. The
    427                               caller is responsible for writing to only legitimate
    428                               locations.
    429   @param[in, out]  Token      A pointer to the token associated with the transaction.
    430   @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
    431   @param[in]       Buffer     A pointer to the source buffer for the data.
    432 
    433   @retval EFI_SUCCESS           The write request was queued if Event is not NULL.
    434                                 The data was written correctly to the device if
    435                                 the Event is NULL.
    436   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    437   @retval EFI_NO_MEDIA          There is no media in the device.
    438   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
    439   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
    440   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    441   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
    442                                 or the buffer is not on proper alignment.
    443   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
    444                                 of resources.
    445 
    446 **/
    447 EFI_STATUS
    448 EmuBlockIoWriteBlocks (
    449   IN     EMU_BLOCK_IO_PROTOCOL  *This,
    450   IN     UINT32                 MediaId,
    451   IN     EFI_LBA                LBA,
    452   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
    453   IN     UINTN                  BufferSize,
    454   IN     VOID                   *Buffer
    455   )
    456 {
    457   EMU_BLOCK_IO_PRIVATE    *Private;
    458   ssize_t                 len;
    459   EFI_STATUS              Status;
    460 
    461 
    462   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    463 
    464   Status  = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");
    465   if (EFI_ERROR (Status)) {
    466     goto Done;
    467   }
    468 
    469   len = write (Private->fd, Buffer, BufferSize);
    470   if (len != BufferSize) {
    471     DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
    472     Status = EmuBlockIoError (Private);
    473     goto Done;
    474   }
    475 
    476   //
    477   // If the write succeeded, we are not write protected and media is present.
    478   //
    479   Private->Media->MediaPresent = TRUE;
    480   Private->Media->ReadOnly     = FALSE;
    481   Status = EFI_SUCCESS;
    482 
    483 Done:
    484   if (Token != NULL) {
    485     if (Token->Event != NULL) {
    486       // Caller is responcible for signaling EFI Event
    487       Token->TransactionStatus = Status;
    488       return EFI_SUCCESS;
    489     }
    490   }
    491 
    492   return Status;
    493 }
    494 
    495 
    496 /**
    497   Flush the Block Device.
    498 
    499   If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
    500   is returned and non-blocking I/O is being used, the Event associated with
    501   this request will not be signaled.
    502 
    503   @param[in]      This     Indicates a pointer to the calling context.
    504   @param[in,out]  Token    A pointer to the token associated with the transaction
    505 
    506   @retval EFI_SUCCESS          The flush request was queued if Event is not NULL.
    507                                All outstanding data was written correctly to the
    508                                device if the Event is NULL.
    509   @retval EFI_DEVICE_ERROR     The device reported an error while writting back
    510                                the data.
    511   @retval EFI_WRITE_PROTECTED  The device cannot be written to.
    512   @retval EFI_NO_MEDIA         There is no media in the device.
    513   @retval EFI_MEDIA_CHANGED    The MediaId is not for the current media.
    514   @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
    515                                of resources.
    516 
    517 **/
    518 EFI_STATUS
    519 EmuBlockIoFlushBlocks (
    520   IN     EMU_BLOCK_IO_PROTOCOL    *This,
    521   IN OUT EFI_BLOCK_IO2_TOKEN      *Token
    522   )
    523 {
    524   EMU_BLOCK_IO_PRIVATE *Private;
    525 
    526   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    527 
    528   if (Private->fd >= 0) {
    529     fsync (Private->fd);
    530 #if __APPLE__
    531     fcntl (Private->fd, F_FULLFSYNC);
    532 #endif
    533   }
    534 
    535 
    536   if (Token != NULL) {
    537     if (Token->Event != NULL) {
    538       // Caller is responcible for signaling EFI Event
    539       Token->TransactionStatus = EFI_SUCCESS;
    540       return EFI_SUCCESS;
    541     }
    542   }
    543 
    544   return EFI_SUCCESS;
    545 }
    546 
    547 
    548 /**
    549   Reset the block device hardware.
    550 
    551   @param[in]  This                 Indicates a pointer to the calling context.
    552   @param[in]  ExtendedVerification Indicates that the driver may perform a more
    553                                    exhausive verfication operation of the device
    554                                    during reset.
    555 
    556   @retval EFI_SUCCESS          The device was reset.
    557   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
    558                                not be reset.
    559 
    560 **/
    561 EFI_STATUS
    562 EmuBlockIoReset (
    563   IN EMU_BLOCK_IO_PROTOCOL    *This,
    564   IN BOOLEAN                  ExtendedVerification
    565   )
    566 {
    567   EMU_BLOCK_IO_PRIVATE *Private;
    568 
    569   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    570 
    571   if (Private->fd >= 0) {
    572     close (Private->fd);
    573     Private->fd = -1;
    574   }
    575 
    576   return EFI_SUCCESS;
    577 }
    578 
    579 
    580 char *
    581 StdDupUnicodeToAscii (
    582   IN  CHAR16 *Str
    583   )
    584 {
    585   UINTN   Size;
    586   char    *Ascii;
    587   char    *Ptr;
    588 
    589   Size = StrLen (Str) + 1;
    590   Ascii = malloc (Size);
    591   if (Ascii == NULL) {
    592     return NULL;
    593   }
    594 
    595   for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {
    596     *Ptr = *Str;
    597   }
    598   *Ptr = 0;
    599 
    600   return Ascii;
    601 }
    602 
    603 
    604 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {
    605   GasketEmuBlockIoReset,
    606   GasketEmuBlockIoReadBlocks,
    607   GasketEmuBlockIoWriteBlocks,
    608   GasketEmuBlockIoFlushBlocks,
    609   GasketEmuBlockIoCreateMapping
    610 };
    611 
    612 EFI_STATUS
    613 EmuBlockIoThunkOpen (
    614   IN  EMU_IO_THUNK_PROTOCOL   *This
    615   )
    616 {
    617   EMU_BLOCK_IO_PRIVATE  *Private;
    618   char                  *Str;
    619 
    620   if (This->Private != NULL) {
    621     return EFI_ALREADY_STARTED;
    622   }
    623 
    624   if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
    625     return EFI_UNSUPPORTED;
    626   }
    627 
    628   Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));
    629   if (Private == NULL) {
    630     return EFI_OUT_OF_RESOURCES;
    631   }
    632 
    633 
    634   Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;
    635   Private->Thunk     = This;
    636   CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));
    637   Private->fd        = -1;
    638   Private->BlockSize = 512;
    639 
    640   Private->Filename = StdDupUnicodeToAscii (This->ConfigString);
    641   if (Private->Filename == NULL) {
    642     return EFI_OUT_OF_RESOURCES;
    643   }
    644 
    645   Str = strstr (Private->Filename, ":");
    646   if (Str == NULL) {
    647     Private->RemovableMedia = FALSE;
    648     Private->WriteProtected = FALSE;
    649   } else {
    650     for (*Str++ = '\0'; *Str != 0; Str++) {
    651       if (*Str == 'R' || *Str == 'F') {
    652         Private->RemovableMedia = (BOOLEAN) (*Str == 'R');
    653       }
    654       if (*Str == 'O' || *Str == 'W') {
    655         Private->WriteProtected  = (BOOLEAN) (*Str == 'O');
    656       }
    657       if (*Str == ':') {
    658         Private->BlockSize = strtol (++Str, NULL, 0);
    659         break;
    660       }
    661     }
    662   }
    663 
    664   Private->Mode = Private->WriteProtected ? O_RDONLY : O_RDWR;
    665 
    666   This->Interface = &Private->EmuBlockIo;
    667   This->Private   = Private;
    668   return EFI_SUCCESS;
    669 }
    670 
    671 
    672 EFI_STATUS
    673 EmuBlockIoThunkClose (
    674   IN  EMU_IO_THUNK_PROTOCOL   *This
    675   )
    676 {
    677   EMU_BLOCK_IO_PRIVATE  *Private;
    678 
    679   if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
    680     return EFI_UNSUPPORTED;
    681   }
    682 
    683   Private = This->Private;
    684 
    685   if (This->Private != NULL) {
    686     if (Private->Filename != NULL) {
    687       free (Private->Filename);
    688     }
    689     free (This->Private);
    690     This->Private = NULL;
    691   }
    692 
    693   return EFI_SUCCESS;
    694 }
    695 
    696 
    697 
    698 EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {
    699   &gEmuBlockIoProtocolGuid,
    700   NULL,
    701   NULL,
    702   0,
    703   GasketBlockIoThunkOpen,
    704   GasketBlockIoThunkClose,
    705   NULL
    706 };
    707 
    708 
    709