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>
31 #include <sys/fcntl.h>
33 #include <Device/Device.h>
35 #include <Efi/SysEfi.h>
41 IN
struct __filedes
*Fp
44 EFIerrno
= ShellCloseFile( (SHELL_FILE_HANDLE
*)&Fp
->devdata
);
45 if(RETURN_ERROR(EFIerrno
)) {
55 struct __filedes
*filp
60 Status
= ShellDeleteFile( (SHELL_FILE_HANDLE
*)&filp
->devdata
);
61 if(Status
!= RETURN_SUCCESS
) {
62 errno
= EFI2errno(Status
);
73 struct __filedes
*filp
,
79 RETURN_STATUS Status
= RETURN_SUCCESS
;
80 SHELL_FILE_HANDLE FileHandle
;
82 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
84 if(whence
!= SEEK_SET
) {
85 // We are doing a relative seek
86 if(whence
== SEEK_END
) {
87 // seeking relative to EOF, so position there first.
88 Status
= ShellSetFilePosition( FileHandle
, 0xFFFFFFFFFFFFFFFFULL
);
90 if(Status
== RETURN_SUCCESS
) {
91 // Now, determine our current position.
92 Status
= ShellGetFilePosition( FileHandle
, (UINT64
*)&CurPos
);
96 CurPos
= 0; // offset is an absolute position for SEEK_SET
98 Status
= RETURN_INVALID_PARAMETER
;
101 if(Status
== RETURN_SUCCESS
) {
102 /* CurPos now indicates the point we are seeking from, so seek... */
103 Status
= ShellSetFilePosition( FileHandle
, (UINT64
)(CurPos
+ offset
));
104 if(Status
== RETURN_SUCCESS
) {
105 // Now, determine our final position.
106 Status
= ShellGetFilePosition( FileHandle
, (UINT64
*)&CurPos
);
109 if(Status
!= RETURN_SUCCESS
) {
110 if(Status
== EFI_UNSUPPORTED
) {
114 errno
= EFI2errno(Status
);
122 /** The directory path is created with the access permissions specified by
125 The directory is closed after it is created.
127 @retval 0 The directory was created successfully.
128 @retval -1 An error occurred and an error code is stored in errno.
138 SHELL_FILE_HANDLE FileHandle
;
139 RETURN_STATUS Status
;
140 EFI_FILE_INFO
*FileInfo
;
144 // Convert name from MBCS to WCS and change '/' to '\\'
145 NewPath
= NormalizePath( path
);
147 if(NewPath
!= NULL
) {
148 Status
= ShellCreateDirectory( NewPath
, &FileHandle
);
149 if(Status
== RETURN_SUCCESS
) {
150 FileInfo
= ShellGetFileInfo( FileHandle
);
151 Status
= RETURN_ABORTED
; // In case ShellGetFileInfo() failed
152 if(FileInfo
!= NULL
) {
153 FileInfo
->Attribute
= Omode2EFI(perms
);
154 Status
= ShellSetFileInfo( FileHandle
, FileInfo
);
156 if(Status
== RETURN_SUCCESS
) {
157 (void)ShellCloseFile(&FileHandle
);
162 errno
= EFI2errno(Status
);
173 IN OUT
struct __filedes
*filp
,
174 IN OUT off_t
*offset
,
175 IN
size_t BufferSize
,
180 SHELL_FILE_HANDLE FileHandle
;
181 RETURN_STATUS Status
;
184 BufSize
= (ssize_t
)da_ShellSeek(filp
, *offset
, SEEK_SET
);
186 filp
->f_offset
= BufSize
;
190 BufSize
= (ssize_t
)BufferSize
;
191 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
193 Status
= ShellReadFile( FileHandle
, (UINTN
*)&BufSize
, Buffer
);
194 if(Status
!= RETURN_SUCCESS
) {
196 errno
= EFI2errno(Status
);
197 if(Status
== RETURN_BUFFER_TOO_SMALL
) {
205 filp
->f_offset
+= BufSize
; // Advance to where we want to read next.
214 IN
struct __filedes
*filp
,
216 IN
size_t BufferSize
,
217 IN
const void *Buffer
221 SHELL_FILE_HANDLE FileHandle
;
222 RETURN_STATUS Status
;
227 if((offset
!= NULL
) || (filp
->Oflags
& O_APPEND
)) {
228 if(filp
->Oflags
& O_APPEND
) {
236 BufSize
= (ssize_t
)da_ShellSeek(filp
, Position
, How
);
238 filp
->f_offset
= BufSize
;
242 BufSize
= (ssize_t
)BufferSize
;
243 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
245 Status
= ShellWriteFile( FileHandle
, (UINTN
*)&BufSize
, (void *)Buffer
);
247 if(Status
!= RETURN_SUCCESS
) {
249 errno
= EFI2errno(Status
);
250 if(Status
== EFI_UNSUPPORTED
) {
256 filp
->f_offset
+= BufSize
; // Advance to where we want to write next.
266 struct __filedes
*filp
,
267 struct stat
*statbuf
,
271 SHELL_FILE_HANDLE FileHandle
;
272 EFI_FILE_INFO
*FileInfo
= NULL
;
274 RETURN_STATUS Status
;
277 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
279 FileInfo
= ShellGetFileInfo( FileHandle
);
281 if(FileInfo
!= NULL
) {
282 // Got the info, now populate statbuf with it
283 statbuf
->st_blksize
= S_BLKSIZE
;
284 statbuf
->st_size
= FileInfo
->FileSize
;
285 statbuf
->st_physsize
= FileInfo
->PhysicalSize
;
286 statbuf
->st_birthtime
= Efi2Time( &FileInfo
->CreateTime
);
287 statbuf
->st_atime
= Efi2Time( &FileInfo
->LastAccessTime
);
288 statbuf
->st_mtime
= Efi2Time( &FileInfo
->ModificationTime
);
289 Attributes
= FileInfo
->Attribute
;
290 newmode
= (mode_t
)(Attributes
<< S_EFISHIFT
) | S_ACC_READ
;
291 if((Attributes
& EFI_FILE_DIRECTORY
) == 0) {
293 if((Attributes
& EFI_FILE_READ_ONLY
) == 0) {
294 newmode
|= S_ACC_WRITE
;
300 statbuf
->st_mode
= newmode
;
301 Status
= RETURN_SUCCESS
;
304 Status
= RETURN_DEVICE_ERROR
;
306 errno
= EFI2errno(Status
);
309 if(FileInfo
!= NULL
) {
310 FreePool(FileInfo
); // Release the buffer allocated by the GetInfo function
312 return errno
? -1 : 0;
319 struct __filedes
*filp
,
321 void *argp
///< May be a pointer or a value
327 /** Open an abstract Shell File.
332 struct __filedes
*filp
,
340 SHELL_FILE_HANDLE FileHandle
;
341 GenericInstance
*Gip
;
343 RETURN_STATUS Status
;
346 EFIerrno
= RETURN_SUCCESS
;
348 //Attributes = Omode2EFI(mode);
351 // Convert oflags to Attributes
352 oflags
= filp
->Oflags
;
353 OpenMode
= Oflags2EFI(oflags
);
359 /* Do we care if the file already exists?
360 If O_TRUNC, then delete the file. It will be created anew subsequently.
361 If O_EXCL, then error if the file exists and O_CREAT is set.
363 !!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file
364 !!!!!!!!! instead of deleting and re-creating it.
366 if((oflags
& O_TRUNC
) || ((oflags
& (O_EXCL
| O_CREAT
)) == (O_EXCL
| O_CREAT
))) {
367 Status
= ShellIsFile( Path
);
368 if(Status
== RETURN_SUCCESS
) {
370 if(oflags
& O_TRUNC
) {
371 NPath
= AllocateZeroPool(1024);
374 EFIerrno
= RETURN_OUT_OF_RESOURCES
;
377 wcstombs(NPath
, Path
, 1024);
378 // We do a truncate by deleting the existing file and creating a new one.
379 if(unlink(NPath
) != 0) {
380 filp
->f_iflags
= 0; // Release our reservation on this FD
382 return -1; // errno and EFIerrno are already set.
386 else if((oflags
& (O_EXCL
| O_CREAT
)) == (O_EXCL
| O_CREAT
)) {
388 EFIerrno
= RETURN_ACCESS_DENIED
;
389 filp
->f_iflags
= 0; // Release our reservation on this FD
395 // Call the EFI Shell's Open function
396 Status
= ShellOpenFileByName( Path
, &FileHandle
, OpenMode
, Attributes
);
397 if(RETURN_ERROR(Status
)) {
398 filp
->f_iflags
= 0; // Release our reservation on this FD
399 // Set errno based upon Status
400 errno
= EFI2errno(Status
);
404 // Successfully got a regular File
405 filp
->f_iflags
|= S_IFREG
;
407 // Update the info in the fd
408 filp
->devdata
= (void *)FileHandle
;
410 Gip
= (GenericInstance
*)DevInstance
;
412 filp
->f_ops
= &Gip
->Abstraction
;
413 // filp->devdata = FileHandle;
418 #include <sys/poll.h>
419 /* Returns a bit mask describing which operations could be completed immediately.
421 For now, assume the file system, via the shell, is always ready.
423 (POLLIN | POLLRDNORM) The file system is ready to be read.
424 (POLLOUT) The file system is ready for output.
431 struct __filedes
*filp
,
438 RdyMask
= (UINT32
)filp
->Oflags
;
440 switch(RdyMask
& O_ACCMODE
) {
442 retval
= (POLLIN
| POLLRDNORM
);
450 retval
= (POLLIN
| POLLRDNORM
| POLLOUT
);
457 return (retval
& (events
| POLL_RETONLY
));
468 RETURN_STATUS Status
;
469 EFI_FILE_INFO
*NewFileInfo
;
470 EFI_FILE_INFO
*OldFileInfo
;
473 SHELL_FILE_HANDLE FileHandle
;
476 OldFd
= open(from
, O_RDWR
, 0);
478 FileHandle
= (SHELL_FILE_HANDLE
)gMD
->fdarray
[OldFd
].devdata
;
480 NewFileInfo
= malloc(sizeof(EFI_FILE_INFO
) + PATH_MAX
);
481 if(NewFileInfo
!= NULL
) {
482 OldFileInfo
= ShellGetFileInfo( FileHandle
);
483 if(OldFileInfo
!= NULL
) {
484 // Copy the Old file info into our new buffer, and free the old.
485 memcpy(OldFileInfo
, NewFileInfo
, sizeof(EFI_FILE_INFO
));
486 FreePool(OldFileInfo
);
487 // Strip off all but the file name portion of new
488 NewFn
= strrchr(to
, '/');
490 NewFn
= strrchr(to
, '\\');
495 // Convert new name from MBCS to WCS
496 (void)AsciiStrToUnicodeStr( NewFn
, gMD
->UString
);
497 // Copy the new file name into our new file info buffer
498 wcsncpy(NewFileInfo
->FileName
, gMD
->UString
, wcslen(gMD
->UString
)+1);
499 // Apply the new file name
500 Status
= ShellSetFileInfo(FileHandle
, NewFileInfo
);
502 if(Status
== EFI_SUCCESS
) {
503 // File has been successfully renamed. We are DONE!
506 errno
= EFI2errno( Status
);
524 struct __filedes
*filp
527 SHELL_FILE_HANDLE FileHandle
;
528 RETURN_STATUS Status
= RETURN_SUCCESS
;
529 EFI_FILE_INFO
*FileInfo
= NULL
;
531 BOOLEAN NoFile
= FALSE
;
533 errno
= 0; // Make it easier to see if we have an error later
535 FileHandle
= (SHELL_FILE_HANDLE
)filp
->devdata
;
537 FileInfo
= ShellGetFileInfo(FileHandle
);
538 if(FileInfo
!= NULL
) {
539 if((FileInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0) {
543 // See if the directory has any entries other than ".." and ".".
544 FreePool(FileInfo
); // Free up the buffer from ShellGetFileInfo()
545 Status
= ShellFindFirstFile( FileHandle
, &FileInfo
);
546 if(Status
== RETURN_SUCCESS
) {
549 Status
= ShellFindNextFile( FileHandle
, FileInfo
, &NoFile
);
550 if(Status
== RETURN_SUCCESS
) {
560 FreePool(FileInfo
); // Free buffer from ShellFindFirstFile()
562 // Directory is empty
563 Status
= ShellDeleteFile( &FileHandle
);
564 if(Status
== RETURN_SUCCESS
) {
565 EFIerrno
= RETURN_SUCCESS
;
567 /* ######## SUCCESSFUL RETURN ######## */
586 errno
= EFI2errno( Status
);
591 /** Construct an instance of the abstract Shell device.
593 Allocate the instance structure and populate it with the information for
599 IN EFI_HANDLE ImageHandle
,
600 IN EFI_SYSTEM_TABLE
*SystemTable
603 GenericInstance
*Stream
;
605 RETURN_STATUS Status
;
607 Stream
= (GenericInstance
*)AllocateZeroPool(sizeof(GenericInstance
));
609 return RETURN_OUT_OF_RESOURCES
;
612 Stream
->Cookie
= CON_COOKIE
;
613 Stream
->InstanceNum
= 1;
615 Stream
->Abstraction
.fo_close
= &da_ShellClose
;
616 Stream
->Abstraction
.fo_read
= &da_ShellRead
;
617 Stream
->Abstraction
.fo_write
= &da_ShellWrite
;
618 Stream
->Abstraction
.fo_fcntl
= &fnullop_fcntl
;
619 Stream
->Abstraction
.fo_poll
= &da_ShellPoll
;
620 Stream
->Abstraction
.fo_flush
= &fnullop_flush
;
621 Stream
->Abstraction
.fo_stat
= &da_ShellStat
;
622 Stream
->Abstraction
.fo_ioctl
= &fbadop_ioctl
;
623 Stream
->Abstraction
.fo_delete
= &da_ShellDelete
;
624 Stream
->Abstraction
.fo_rmdir
= &da_ShellRmdir
;
625 Stream
->Abstraction
.fo_mkdir
= &da_ShellMkdir
;
626 Stream
->Abstraction
.fo_rename
= &da_ShellRename
;
627 Stream
->Abstraction
.fo_lseek
= &da_ShellSeek
;
629 Node
= __DevRegister(NULL
, NULL
, &da_ShellOpen
, Stream
, 1, sizeof(GenericInstance
), O_RDWR
);
631 Stream
->Parent
= Node
;
639 IN EFI_HANDLE ImageHandle
,
640 IN EFI_SYSTEM_TABLE
*SystemTable
643 if(daDefaultDevice
!= NULL
) {
644 if(daDefaultDevice
->InstanceList
!= NULL
) {
645 FreePool(daDefaultDevice
->InstanceList
);
647 FreePool(daDefaultDevice
);
649 return RETURN_SUCCESS
;