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