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