2 Abstract device driver for the UEFI Shell-hosted environment.
4 In a Shell-hosted environment, this is the driver that is called
5 when no other driver matches.
7 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials are licensed and made available under
9 the terms and conditions of the BSD License that accompanies this distribution.
10 The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/BaseLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/ShellLib.h>
23 #include <LibConfig.h>
24 #include <sys/EfiSysCall.h>
32 #include <sys/fcntl.h>
33 #include <sys/syslimits.h>
35 #include <Device/Device.h>
37 #include <Efi/SysEfi.h>
43 IN
struct __filedes
*Fp
46 EFIerrno
= ShellCloseFile( (SHELL_FILE_HANDLE
*)&Fp
->devdata
);
47 if(RETURN_ERROR(EFIerrno
)) {
57 struct __filedes
*filp
62 Status
= ShellDeleteFile( (SHELL_FILE_HANDLE
*)&filp
->devdata
);
63 if(Status
!= RETURN_SUCCESS
) {
64 errno
= EFI2errno(Status
);
75 struct __filedes
*filp
,
81 RETURN_STATUS Status
= RETURN_SUCCESS
;
82 SHELL_FILE_HANDLE FileHandle
;
84 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
86 if(whence
!= SEEK_SET
) {
87 // We are doing a relative seek
88 if(whence
== SEEK_END
) {
89 // seeking relative to EOF, so position there first.
90 Status
= ShellSetFilePosition( FileHandle
, 0xFFFFFFFFFFFFFFFFULL
);
92 if(Status
== RETURN_SUCCESS
) {
93 // Now, determine our current position.
94 Status
= ShellGetFilePosition( FileHandle
, (UINT64
*)&CurPos
);
98 CurPos
= 0; // offset is an absolute position for SEEK_SET
100 Status
= RETURN_INVALID_PARAMETER
;
103 if(Status
== RETURN_SUCCESS
) {
104 /* CurPos now indicates the point we are seeking from, so seek... */
105 Status
= ShellSetFilePosition( FileHandle
, (UINT64
)(CurPos
+ offset
));
106 if(Status
== RETURN_SUCCESS
) {
107 // Now, determine our final position.
108 Status
= ShellGetFilePosition( FileHandle
, (UINT64
*)&CurPos
);
111 if(Status
!= RETURN_SUCCESS
) {
112 if(Status
== EFI_UNSUPPORTED
) {
116 errno
= EFI2errno(Status
);
124 /** The directory path is created with the access permissions specified by
127 The directory is closed after it is created.
129 @retval 0 The directory was created successfully.
130 @retval -1 An error occurred and an error code is stored in errno.
140 SHELL_FILE_HANDLE FileHandle
;
141 RETURN_STATUS Status
;
142 EFI_FILE_INFO
*FileInfo
;
146 // Convert name from MBCS to WCS and change '/' to '\\'
147 NewPath
= NormalizePath( path
);
149 if(NewPath
!= NULL
) {
150 Status
= ShellCreateDirectory( NewPath
, &FileHandle
);
151 if(Status
== RETURN_SUCCESS
) {
152 FileInfo
= ShellGetFileInfo( FileHandle
);
153 Status
= RETURN_ABORTED
; // In case ShellGetFileInfo() failed
154 if(FileInfo
!= NULL
) {
155 FileInfo
->Attribute
= Omode2EFI(perms
);
156 Status
= ShellSetFileInfo( FileHandle
, FileInfo
);
158 if(Status
== RETURN_SUCCESS
) {
159 (void)ShellCloseFile(&FileHandle
);
164 errno
= EFI2errno(Status
);
175 IN OUT
struct __filedes
*filp
,
176 IN OUT off_t
*offset
,
177 IN
size_t BufferSize
,
182 SHELL_FILE_HANDLE FileHandle
;
183 RETURN_STATUS Status
;
186 BufSize
= (ssize_t
)da_ShellSeek(filp
, *offset
, SEEK_SET
);
188 filp
->f_offset
= BufSize
;
192 BufSize
= (ssize_t
)BufferSize
;
193 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
195 Status
= ShellReadFile( FileHandle
, (UINTN
*)&BufSize
, Buffer
);
196 if(Status
!= RETURN_SUCCESS
) {
198 errno
= EFI2errno(Status
);
199 if(Status
== RETURN_BUFFER_TOO_SMALL
) {
207 filp
->f_offset
+= BufSize
; // Advance to where we want to read next.
216 IN
struct __filedes
*filp
,
218 IN
size_t BufferSize
,
219 IN
const void *Buffer
223 SHELL_FILE_HANDLE FileHandle
;
224 RETURN_STATUS Status
;
229 if((offset
!= NULL
) || (filp
->Oflags
& O_APPEND
)) {
230 if(filp
->Oflags
& O_APPEND
) {
238 BufSize
= (ssize_t
)da_ShellSeek(filp
, Position
, How
);
240 filp
->f_offset
= BufSize
;
244 BufSize
= (ssize_t
)BufferSize
;
245 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
247 Status
= ShellWriteFile( FileHandle
, (UINTN
*)&BufSize
, (void *)Buffer
);
249 if(Status
!= RETURN_SUCCESS
) {
251 errno
= EFI2errno(Status
);
252 if(Status
== EFI_UNSUPPORTED
) {
258 filp
->f_offset
+= BufSize
; // Advance to where we want to write next.
268 struct __filedes
*filp
,
269 struct stat
*statbuf
,
273 SHELL_FILE_HANDLE FileHandle
;
274 EFI_FILE_INFO
*FileInfo
= NULL
;
276 RETURN_STATUS Status
;
279 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
281 FileInfo
= ShellGetFileInfo( FileHandle
);
283 if(FileInfo
!= NULL
) {
284 // Got the info, now populate statbuf with it
285 statbuf
->st_blksize
= S_BLKSIZE
;
286 statbuf
->st_size
= FileInfo
->FileSize
;
287 statbuf
->st_physsize
= FileInfo
->PhysicalSize
;
288 statbuf
->st_birthtime
= Efi2Time( &FileInfo
->CreateTime
);
289 statbuf
->st_atime
= Efi2Time( &FileInfo
->LastAccessTime
);
290 statbuf
->st_mtime
= Efi2Time( &FileInfo
->ModificationTime
);
291 Attributes
= FileInfo
->Attribute
;
292 newmode
= (mode_t
)(Attributes
<< S_EFISHIFT
) | S_ACC_READ
;
293 if((Attributes
& EFI_FILE_DIRECTORY
) == 0) {
295 if((Attributes
& EFI_FILE_READ_ONLY
) == 0) {
296 newmode
|= S_ACC_WRITE
;
302 statbuf
->st_mode
= newmode
;
303 Status
= RETURN_SUCCESS
;
306 Status
= RETURN_DEVICE_ERROR
;
311 if(FileInfo
!= NULL
) {
312 FreePool(FileInfo
); // Release the buffer allocated by the GetInfo function
314 return (Status
== RETURN_SUCCESS
)? 0 : -1;
321 struct __filedes
*filp
,
329 /** Open an abstract Shell File.
335 struct __filedes
*filp
,
336 int DevInstance
, /* Not used by Shell */
343 SHELL_FILE_HANDLE FileHandle
;
344 GenericInstance
*Gip
;
347 RETURN_STATUS Status
;
351 EFIerrno
= RETURN_SUCCESS
;
353 //Attributes = Omode2EFI(mode);
356 // Convert oflags to Attributes
357 oflags
= filp
->Oflags
;
358 OpenMode
= Oflags2EFI(oflags
);
364 /* Re-create the full mapped path for the shell. */
366 WPath
= AllocateZeroPool(PATH_MAX
* sizeof(wchar_t) + 1);
369 EFIerrno
= RETURN_OUT_OF_RESOURCES
;
372 wcsncpy(WPath
, MPath
, NAME_MAX
); /* Get the Map Name */
373 wcsncat(WPath
, Path
, (PATH_MAX
- NAME_MAX
)); /* Append the path */
379 retval
= -1; /* Initially assume failure. */
381 /* Do we care if the file already exists?
382 If O_TRUNC, then delete the file. It will be created anew subsequently.
383 If O_EXCL, then error if the file exists and O_CREAT is set.
385 !!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file
386 !!!!!!!!! instead of deleting and re-creating it.
388 do { /* Do fake exception handling */
389 if((oflags
& O_TRUNC
) || ((oflags
& (O_EXCL
| O_CREAT
)) == (O_EXCL
| O_CREAT
))) {
390 Status
= ShellIsFile( WPath
);
391 if(Status
== RETURN_SUCCESS
) {
393 if(oflags
& O_TRUNC
) {
394 NPath
= AllocateZeroPool(PATH_MAX
);
397 EFIerrno
= RETURN_OUT_OF_RESOURCES
;
400 wcstombs(NPath
, WPath
, PATH_MAX
);
401 // We do a truncate by deleting the existing file and creating a new one.
402 if(unlink(NPath
) != 0) {
403 filp
->f_iflags
= 0; // Release our reservation on this FD
409 else if((oflags
& (O_EXCL
| O_CREAT
)) == (O_EXCL
| O_CREAT
)) {
411 EFIerrno
= RETURN_ACCESS_DENIED
;
412 filp
->f_iflags
= 0; // Release our reservation on this FD
418 // Call the EFI Shell's Open function
419 Status
= ShellOpenFileByName( WPath
, &FileHandle
, OpenMode
, Attributes
);
420 if(RETURN_ERROR(Status
)) {
421 filp
->f_iflags
= 0; // Release our reservation on this FD
422 // Set errno based upon Status
423 errno
= EFI2errno(Status
);
428 // Successfully got a regular File
429 filp
->f_iflags
|= S_IFREG
;
431 // Update the info in the fd
432 filp
->devdata
= (void *)FileHandle
;
434 Gip
= (GenericInstance
*)DevNode
->InstanceList
;
436 filp
->f_ops
= &Gip
->Abstraction
;
437 // filp->devdata = FileHandle;
440 /* If we get this far, WPath is not NULL.
441 If MPath is not NULL, then WPath was allocated so we need to free it.
449 #include <sys/poll.h>
450 /* Returns a bit mask describing which operations could be completed immediately.
452 For now, assume the file system, via the shell, is always ready.
454 (POLLIN | POLLRDNORM) The file system is ready to be read.
455 (POLLOUT) The file system is ready for output.
462 struct __filedes
*filp
,
469 RdyMask
= (UINT32
)filp
->Oflags
;
471 switch(RdyMask
& O_ACCMODE
) {
473 retval
= (POLLIN
| POLLRDNORM
);
481 retval
= (POLLIN
| POLLRDNORM
| POLLOUT
);
488 return (retval
& (events
| POLL_RETONLY
));
499 RETURN_STATUS Status
;
500 EFI_FILE_INFO
*NewFileInfo
;
501 EFI_FILE_INFO
*OldFileInfo
;
504 SHELL_FILE_HANDLE FileHandle
;
505 wchar_t *NormalizedPath
;
508 OldFd
= open(from
, O_RDWR
, 0);
510 FileHandle
= (SHELL_FILE_HANDLE
)gMD
->fdarray
[OldFd
].devdata
;
512 NewFileInfo
= malloc(sizeof(EFI_FILE_INFO
) + PATH_MAX
);
513 if(NewFileInfo
!= NULL
) {
514 OldFileInfo
= ShellGetFileInfo( FileHandle
);
515 if(OldFileInfo
!= NULL
) {
516 // Copy the Old file info into our new buffer, and free the old.
517 memcpy(NewFileInfo
, OldFileInfo
, sizeof(EFI_FILE_INFO
));
518 FreePool(OldFileInfo
);
519 // Normalize path and convert to WCS.
520 NormalizedPath
= NormalizePath(to
);
521 if (NormalizedPath
!= NULL
) {
522 // Strip off all but the file name portion of new
523 NewFn
= GetFileNameFromPath(NormalizedPath
);
524 // Copy the new file name into our new file info buffer
525 wcsncpy(NewFileInfo
->FileName
, NewFn
, wcslen(NewFn
) + 1);
526 // Update the size of the structure.
527 NewFileInfo
->Size
= sizeof(EFI_FILE_INFO
) + StrSize(NewFn
);
528 // Apply the new file name
529 Status
= ShellSetFileInfo(FileHandle
, NewFileInfo
);
530 free(NormalizedPath
);
532 if(Status
== EFI_SUCCESS
) {
533 // File has been successfully renamed. We are DONE!
536 errno
= EFI2errno( Status
);
560 struct __filedes
*filp
563 SHELL_FILE_HANDLE FileHandle
;
564 RETURN_STATUS Status
= RETURN_SUCCESS
;
565 EFI_FILE_INFO
*FileInfo
= NULL
;
567 BOOLEAN NoFile
= FALSE
;
569 errno
= 0; // Make it easier to see if we have an error later
571 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
573 FileInfo
= ShellGetFileInfo(FileHandle
);
574 if(FileInfo
!= NULL
) {
575 if((FileInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0) {
579 // See if the directory has any entries other than ".." and ".".
580 FreePool(FileInfo
); // Free up the buffer from ShellGetFileInfo()
581 Status
= ShellFindFirstFile( FileHandle
, &FileInfo
);
582 if(Status
== RETURN_SUCCESS
) {
585 Status
= ShellFindNextFile( FileHandle
, FileInfo
, &NoFile
);
586 if(Status
== RETURN_SUCCESS
) {
596 FreePool(FileInfo
); // Free buffer from ShellFindFirstFile()
598 // Directory is empty
599 Status
= ShellDeleteFile( &FileHandle
);
600 if(Status
== RETURN_SUCCESS
) {
601 EFIerrno
= RETURN_SUCCESS
;
603 /* ######## SUCCESSFUL RETURN ######## */
622 errno
= EFI2errno( Status
);
627 /** Construct an instance of the abstract Shell device.
629 Allocate the instance structure and populate it with the information for
635 IN EFI_HANDLE ImageHandle
,
636 IN EFI_SYSTEM_TABLE
*SystemTable
639 GenericInstance
*Stream
;
641 RETURN_STATUS Status
;
643 Stream
= (GenericInstance
*)AllocateZeroPool(sizeof(GenericInstance
));
645 return RETURN_OUT_OF_RESOURCES
;
648 Stream
->Cookie
= CON_COOKIE
;
649 Stream
->InstanceNum
= 1;
651 Stream
->Abstraction
.fo_close
= &da_ShellClose
;
652 Stream
->Abstraction
.fo_read
= &da_ShellRead
;
653 Stream
->Abstraction
.fo_write
= &da_ShellWrite
;
654 Stream
->Abstraction
.fo_fcntl
= &fnullop_fcntl
;
655 Stream
->Abstraction
.fo_poll
= &da_ShellPoll
;
656 Stream
->Abstraction
.fo_flush
= &fnullop_flush
;
657 Stream
->Abstraction
.fo_stat
= &da_ShellStat
;
658 Stream
->Abstraction
.fo_ioctl
= &da_ShellIoctl
;
659 Stream
->Abstraction
.fo_delete
= &da_ShellDelete
;
660 Stream
->Abstraction
.fo_rmdir
= &da_ShellRmdir
;
661 Stream
->Abstraction
.fo_mkdir
= &da_ShellMkdir
;
662 Stream
->Abstraction
.fo_rename
= &da_ShellRename
;
663 Stream
->Abstraction
.fo_lseek
= &da_ShellSeek
;
665 Node
= __DevRegister(NULL
, NULL
, &da_ShellOpen
, Stream
, 1, sizeof(GenericInstance
), O_RDWR
);
667 Stream
->Parent
= Node
;
675 IN EFI_HANDLE ImageHandle
,
676 IN EFI_SYSTEM_TABLE
*SystemTable
679 if(daDefaultDevice
!= NULL
) {
680 if(daDefaultDevice
->InstanceList
!= NULL
) {
681 FreePool(daDefaultDevice
->InstanceList
);
683 FreePool(daDefaultDevice
);
685 return RETURN_SUCCESS
;