1 /** @file
2 Abstract device driver for the UEFI Shell-hosted environment.
3
4 In a Shell-hosted environment, this is the driver that is called
5 when no other driver matches.
6
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.
12
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.
15
16 **/
17 #include <Uefi.h>
18 #include <Library/BaseLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/ShellLib.h>
22
23 #include <LibConfig.h>
24
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <wctype.h>
30 #include <wchar.h>
31 #include <sys/fcntl.h>
32 #include <sys/filio.h>
33 #include <sys/syslimits.h>
34 #include <unistd.h>
35 #include <kfile.h>
36 #include <Device/Device.h>
37 #include <MainData.h>
38 #include <Efi/SysEfi.h>
39
40 /** EFI Shell specific operations for close().
41
42 @param[in] Fp Pointer to a file descriptor structure.
43
44 @retval 0 Successful completion.
45 @retval -1 Operation failed. Further information is specified by errno.
46 **/
47 static
48 int
49 EFIAPI
da_ShellClose(IN struct __filedes * Fp)50 da_ShellClose(
51 IN struct __filedes *Fp
52 )
53 {
54 EFIerrno = ShellCloseFile( (SHELL_FILE_HANDLE *)&Fp->devdata);
55 if(RETURN_ERROR(EFIerrno)) {
56 return -1;
57 }
58 return 0;
59 }
60
61 /** EFI Shell specific operations for deleting a file or directory.
62
63 @param[in] filp Pointer to a file descriptor structure.
64
65 @retval 0 Successful completion.
66 @retval -1 Operation failed. Further information is specified by errno.
67 **/
68 static
69 int
70 EFIAPI
da_ShellDelete(struct __filedes * filp)71 da_ShellDelete(
72 struct __filedes *filp
73 )
74 {
75 RETURN_STATUS Status;
76
77 Status = ShellDeleteFile( (SHELL_FILE_HANDLE *)&filp->devdata);
78 if(Status != RETURN_SUCCESS) {
79 errno = EFI2errno(Status);
80 EFIerrno = Status;
81 return -1;
82 }
83 return 0;
84 }
85
86 /** EFI Shell specific operations for setting the position within a file.
87
88 @param[in] filp Pointer to a file descriptor structure.
89 @param[in] offset Relative position to move to.
90 @param[in] whence Specifies the location offset is relative to: Beginning, Current, End.
91
92 @return Returns the new file position or EOF if the seek failed.
93 **/
94 static
95 off_t
96 EFIAPI
da_ShellSeek(struct __filedes * filp,off_t offset,int whence)97 da_ShellSeek(
98 struct __filedes *filp,
99 off_t offset,
100 int whence
101 )
102 {
103 __off_t CurPos = -1;
104 RETURN_STATUS Status = RETURN_SUCCESS;
105 SHELL_FILE_HANDLE FileHandle;
106
107 FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
108
109 if(whence != SEEK_SET) {
110 // We are doing a relative seek
111 if(whence == SEEK_END) {
112 // seeking relative to EOF, so position there first.
113 Status = ShellSetFilePosition( FileHandle, 0xFFFFFFFFFFFFFFFFULL);
114 }
115 if(Status == RETURN_SUCCESS) {
116 // Now, determine our current position.
117 Status = ShellGetFilePosition( FileHandle, (UINT64 *)&CurPos);
118 }
119 }
120 else {
121 CurPos = 0; // offset is an absolute position for SEEK_SET
122 if(offset < 0) {
123 Status = RETURN_INVALID_PARAMETER;
124 }
125 }
126 if(Status == RETURN_SUCCESS) {
127 /* CurPos now indicates the point we are seeking from, so seek... */
128 Status = ShellSetFilePosition( FileHandle, (UINT64)(CurPos + offset));
129 if(Status == RETURN_SUCCESS) {
130 // Now, determine our final position.
131 Status = ShellGetFilePosition( FileHandle, (UINT64 *)&CurPos);
132 }
133 }
134 if(Status != RETURN_SUCCESS) {
135 if(Status == EFI_UNSUPPORTED) {
136 errno = EISDIR;
137 }
138 else {
139 errno = EFI2errno(Status);
140 }
141 EFIerrno = Status;
142 CurPos = EOF;
143 }
144 return CurPos;
145 }
146
147 /** The directory path is created with the access permissions specified by
148 perms.
149
150 The directory is closed after it is created.
151
152 @param[in] path The directory to be created.
153 @param[in] perms Access permissions for the new directory.
154
155 @retval 0 The directory was created successfully.
156 @retval -1 An error occurred and an error code is stored in errno.
157 **/
158 static
159 int
160 EFIAPI
da_ShellMkdir(const char * path,__mode_t perms)161 da_ShellMkdir(
162 const char *path,
163 __mode_t perms
164 )
165 {
166 UINT64 TempAttr;
167 SHELL_FILE_HANDLE FileHandle;
168 RETURN_STATUS Status;
169 EFI_FILE_INFO *FileInfo;
170 wchar_t *NewPath;
171 int retval = -1;
172
173 // Convert name from MBCS to WCS and change '/' to '\\'
174 NewPath = NormalizePath( path);
175
176 if(NewPath != NULL) {
177 Status = ShellCreateDirectory( NewPath, &FileHandle);
178 if(Status == RETURN_SUCCESS) {
179 FileInfo = ShellGetFileInfo( FileHandle);
180 Status = RETURN_ABORTED; // In case ShellGetFileInfo() failed
181 if(FileInfo != NULL) {
182 TempAttr = FileInfo->Attribute & (EFI_FILE_RESERVED | EFI_FILE_DIRECTORY);
183 FileInfo->Attribute = TempAttr | Omode2EFI(perms);
184 Status = ShellSetFileInfo( FileHandle, FileInfo);
185 FreePool(FileInfo);
186 if(Status == RETURN_SUCCESS) {
187 (void)ShellCloseFile(&FileHandle);
188 retval = 0;
189 }
190 }
191 }
192 errno = EFI2errno(Status);
193 EFIerrno = Status;
194 free(NewPath);
195 }
196 return retval;
197 }
198
199 /** EFI Shell specific operations for reading from a file.
200
201 @param[in] filp Pointer to a file descriptor structure.
202 @param[in] offset Offset into the file to begin reading at, or NULL.
203 @param[in] BufferSize Number of bytes in Buffer. Max number of bytes to read.
204 @param[in] Buffer Pointer to a buffer to receive the read data.
205
206 @return Returns the number of bytes successfully read,
207 or -1 if the operation failed. Further information is specified by errno.
208 **/
209 static
210 ssize_t
211 EFIAPI
da_ShellRead(IN OUT struct __filedes * filp,IN OUT off_t * offset,IN size_t BufferSize,OUT VOID * Buffer)212 da_ShellRead(
213 IN OUT struct __filedes *filp,
214 IN OUT off_t *offset,
215 IN size_t BufferSize,
216 OUT VOID *Buffer
217 )
218 {
219 ssize_t BufSize;
220 SHELL_FILE_HANDLE FileHandle;
221 RETURN_STATUS Status;
222
223 if(offset != NULL) {
224 BufSize = (ssize_t)da_ShellSeek(filp, *offset, SEEK_SET);
225 if(BufSize >= 0) {
226 filp->f_offset = BufSize;
227 }
228 }
229
230 BufSize = (ssize_t)BufferSize;
231 FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
232
233 Status = ShellReadFile( FileHandle, (UINTN *)&BufSize, Buffer);
234 if(Status != RETURN_SUCCESS) {
235 EFIerrno = Status;
236 errno = EFI2errno(Status);
237 if(Status == RETURN_BUFFER_TOO_SMALL) {
238 BufSize = -BufSize;
239 }
240 else {
241 BufSize = -1;
242 }
243 }
244 else {
245 filp->f_offset += BufSize; // Advance to where we want to read next.
246 }
247 return BufSize;
248 }
249
250 /** EFI Shell specific operations for writing to a file.
251
252 @param[in] filp Pointer to a file descriptor structure.
253 @param[in] offset Offset into the file to begin writing at, or NULL.
254 @param[in] BufferSize Number of bytes in Buffer. Max number of bytes to write.
255 @param[in] Buffer Pointer to a buffer containing the data to be written.
256
257 @return Returns the number of bytes successfully written,
258 or -1 if the operation failed. Further information is specified by errno.
259 **/
260 static
261 ssize_t
262 EFIAPI
da_ShellWrite(IN struct __filedes * filp,IN off_t * offset,IN size_t BufferSize,IN const void * Buffer)263 da_ShellWrite(
264 IN struct __filedes *filp,
265 IN off_t *offset,
266 IN size_t BufferSize,
267 IN const void *Buffer
268 )
269 {
270 ssize_t BufSize;
271 SHELL_FILE_HANDLE FileHandle;
272 RETURN_STATUS Status;
273 off_t Position = 0;
274 int How = SEEK_SET;
275
276
277 if((offset != NULL) || (filp->Oflags & O_APPEND)) {
278 if(filp->Oflags & O_APPEND) {
279 Position = 0;
280 How = SEEK_END;
281 }
282 else {
283 Position = *offset;
284 How = SEEK_SET;
285 }
286 BufSize = (ssize_t)da_ShellSeek(filp, Position, How);
287 if(BufSize >= 0) {
288 filp->f_offset = BufSize;
289 }
290 }
291
292 BufSize = (ssize_t)BufferSize;
293 FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
294
295 Status = ShellWriteFile( FileHandle, (UINTN *)&BufSize, (void *)Buffer);
296
297 if(Status != RETURN_SUCCESS) {
298 EFIerrno = Status;
299 errno = EFI2errno(Status);
300 if(Status == EFI_UNSUPPORTED) {
301 errno = EISDIR;
302 }
303 BufSize = -1;
304 }
305 else {
306 filp->f_offset += BufSize; // Advance to where we want to write next.
307 }
308
309 return BufSize;
310 }
311
312 /** EFI Shell specific operations for getting information about an open file.
313
314 @param[in] filp Pointer to a file descriptor structure.
315 @param[out] statbuf Buffer in which to store the file status.
316 @param[in] Something This parameter is not used by this device.
317
318 @retval 0 Successful completion.
319 @retval -1 Operation failed. Further information is specified by errno.
320 **/
321 static
322 int
323 EFIAPI
da_ShellStat(struct __filedes * filp,struct stat * statbuf,void * Something)324 da_ShellStat(
325 struct __filedes *filp,
326 struct stat *statbuf,
327 void *Something
328 )
329 {
330 SHELL_FILE_HANDLE FileHandle;
331 EFI_FILE_INFO *FileInfo = NULL;
332 UINT64 Attributes;
333 RETURN_STATUS Status;
334 mode_t newmode;
335
336 FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
337
338 FileInfo = ShellGetFileInfo( FileHandle);
339
340 if(FileInfo != NULL) {
341 // Got the info, now populate statbuf with it
342 statbuf->st_blksize = S_BLKSIZE;
343 statbuf->st_size = FileInfo->FileSize;
344 statbuf->st_physsize = FileInfo->PhysicalSize;
345 statbuf->st_birthtime = Efi2Time( &FileInfo->CreateTime);
346 statbuf->st_atime = Efi2Time( &FileInfo->LastAccessTime);
347 statbuf->st_mtime = Efi2Time( &FileInfo->ModificationTime);
348 Attributes = FileInfo->Attribute;
349 newmode = (mode_t)(Attributes << S_EFISHIFT) | S_ACC_READ;
350 if((Attributes & EFI_FILE_DIRECTORY) == 0) {
351 newmode |= _S_IFREG;
352 if((Attributes & EFI_FILE_READ_ONLY) == 0) {
353 newmode |= S_ACC_WRITE;
354 }
355 }
356 else {
357 newmode |= _S_IFDIR;
358 }
359 statbuf->st_mode = newmode;
360 Status = RETURN_SUCCESS;
361 }
362 else {
363 Status = RETURN_DEVICE_ERROR;
364 errno = EIO;
365 }
366 EFIerrno = Status;
367
368 if(FileInfo != NULL) {
369 FreePool(FileInfo); // Release the buffer allocated by the GetInfo function
370 }
371 return (Status == RETURN_SUCCESS)? 0 : -1;
372 }
373
374 /** EFI Shell specific operations for low-level control of a file or device.
375
376 @param[in] filp Pointer to a file descriptor structure.
377 @param[in] cmd The command this ioctl is to perform.
378 @param[in,out] argp Zero or more arguments as needed by the command.
379
380 @retval 0 Successful completion.
381 @retval -1 Operation failed. Further information is specified by errno.
382 **/
383 static
384 int
385 EFIAPI
da_ShellIoctl(struct __filedes * filp,ULONGN cmd,va_list argp)386 da_ShellIoctl(
387 struct __filedes *filp,
388 ULONGN cmd,
389 va_list argp
390 )
391 {
392 EFI_FILE_INFO *FileInfo = NULL;
393 SHELL_FILE_HANDLE FileHandle;
394 RETURN_STATUS Status = RETURN_SUCCESS;
395 int retval = 0;
396
397 FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
398
399 FileInfo = ShellGetFileInfo( FileHandle);
400
401 if(FileInfo != NULL) {
402 if( cmd == (ULONGN)FIOSETIME) {
403 struct timeval *TV;
404 EFI_TIME *ET;
405 int mod = 0;
406
407 TV = va_arg(argp, struct timeval*);
408 if(TV[0].tv_sec != 0) {
409 ET = Time2Efi(TV[0].tv_sec);
410 if(ET != NULL) {
411 (void) memcpy(&FileInfo->LastAccessTime, ET, sizeof(EFI_TIME));
412 FileInfo->LastAccessTime.Nanosecond = TV[0].tv_usec * 1000;
413 free(ET);
414 ++mod;
415 }
416 }
417 if(TV[1].tv_sec != 0) {
418 ET = Time2Efi(TV[1].tv_sec);
419 if(ET != NULL) {
420 (void) memcpy(&FileInfo->ModificationTime, ET, sizeof(EFI_TIME));
421 FileInfo->ModificationTime.Nanosecond = TV[1].tv_usec * 1000;
422 free(ET);
423 ++mod;
424 }
425 }
426 /* Set access and modification times */
427 Status = ShellSetFileInfo(FileHandle, FileInfo);
428 errno = EFI2errno(Status);
429 }
430 }
431 else {
432 Status = RETURN_DEVICE_ERROR;
433 errno = EIO;
434 }
435 if(RETURN_ERROR(Status)) {
436 retval = -1;
437 }
438 EFIerrno = Status;
439
440 if(FileInfo != NULL) {
441 FreePool(FileInfo); // Release the buffer allocated by the GetInfo function
442 }
443 return retval;
444 }
445
446 /** EFI Shell specific operations for opening a file or directory.
447
448 @param[in] DevNode Pointer to a device descriptor
449 @param[in] filp Pointer to a file descriptor structure.
450 @param[in] DevInstance Not used by this device.
451 @param[in] Path File-system path to the file or directory.
452 @param[in] MPath Device or Map name on which Path resides.
453
454 @return Returns a file descriptor for the newly opened file,
455 or -1 if the Operation failed. Further information is specified by errno.
456 **/
457 int
458 EFIAPI
da_ShellOpen(DeviceNode * DevNode,struct __filedes * filp,int DevInstance,wchar_t * Path,wchar_t * MPath)459 da_ShellOpen(
460 DeviceNode *DevNode,
461 struct __filedes *filp,
462 int DevInstance, /* Not used by Shell */
463 wchar_t *Path,
464 wchar_t *MPath
465 )
466 {
467 UINT64 OpenMode;
468 UINT64 Attributes;
469 SHELL_FILE_HANDLE FileHandle;
470 GenericInstance *Gip;
471 char *NPath;
472 wchar_t *WPath;
473 RETURN_STATUS Status;
474 int oflags;
475 int retval;
476
477 EFIerrno = RETURN_SUCCESS;
478
479 //Attributes = Omode2EFI(mode);
480 Attributes = 0;
481
482 // Convert oflags to Attributes
483 oflags = filp->Oflags;
484 OpenMode = Oflags2EFI(oflags);
485 if(OpenMode == 0) {
486 errno = EINVAL;
487 return -1;
488 }
489
490 /* Re-create the full mapped path for the shell. */
491 if(MPath != NULL) {
492 WPath = AllocateZeroPool(PATH_MAX * sizeof(wchar_t) + 1);
493 if(WPath == NULL) {
494 errno = ENOMEM;
495 EFIerrno = RETURN_OUT_OF_RESOURCES;
496 return -1;
497 }
498 wcsncpy(WPath, MPath, NAME_MAX); /* Get the Map Name */
499 wcsncat(WPath, Path, (PATH_MAX - NAME_MAX)); /* Append the path */
500 }
501 else {
502 WPath = Path;
503 }
504
505 retval = -1; /* Initially assume failure. */
506
507 /* Do we care if the file already exists?
508 If O_TRUNC, then delete the file. It will be created anew subsequently.
509 If O_EXCL, then error if the file exists and O_CREAT is set.
510
511 !!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file
512 !!!!!!!!! instead of deleting and re-creating it.
513 */
514 do { /* Do fake exception handling */
515 if((oflags & O_TRUNC) || ((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
516 Status = ShellIsFile( WPath );
517 if(Status == RETURN_SUCCESS) {
518 // The file exists
519 if(oflags & O_TRUNC) {
520 NPath = AllocateZeroPool(PATH_MAX);
521 if(NPath == NULL) {
522 errno = ENOMEM;
523 EFIerrno = RETURN_OUT_OF_RESOURCES;
524 break;
525 }
526 wcstombs(NPath, WPath, PATH_MAX);
527 // We do a truncate by deleting the existing file and creating a new one.
528 if(unlink(NPath) != 0) {
529 filp->f_iflags = 0; // Release our reservation on this FD
530 FreePool(NPath);
531 break;
532 }
533 FreePool(NPath);
534 }
535 else if((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
536 errno = EEXIST;
537 EFIerrno = RETURN_ACCESS_DENIED;
538 filp->f_iflags = 0; // Release our reservation on this FD
539 break;
540 }
541 }
542 }
543
544 // Call the EFI Shell's Open function
545 Status = ShellOpenFileByName( WPath, &FileHandle, OpenMode, Attributes);
546 if(RETURN_ERROR(Status)) {
547 filp->f_iflags = 0; // Release our reservation on this FD
548 // Set errno based upon Status
549 errno = EFI2errno(Status);
550 EFIerrno = Status;
551 break;
552 }
553 retval = 0;
554 // Successfully got a regular File
555 filp->f_iflags |= S_IFREG;
556
557 // Update the info in the fd
558 filp->devdata = (void *)FileHandle;
559
560 Gip = (GenericInstance *)DevNode->InstanceList;
561 filp->f_offset = 0;
562 filp->f_ops = &Gip->Abstraction;
563 // filp->devdata = FileHandle;
564 } while(FALSE);
565
566 /* If we get this far, WPath is not NULL.
567 If MPath is not NULL, then WPath was allocated so we need to free it.
568 */
569 if(MPath != NULL) {
570 FreePool(WPath);
571 }
572 return retval;
573 }
574
575 #include <sys/poll.h>
576 /** Returns a bit mask describing which operations could be completed immediately.
577
578 For now, assume the file system, via the shell, is always ready.
579
580 (POLLIN | POLLRDNORM) The file system is ready to be read.
581 (POLLOUT) The file system is ready for output.
582
583 @param[in] filp Pointer to a file descriptor structure.
584 @param[in] events Bit mask describing which operations to check.
585
586 @return The returned value is a bit mask describing which operations
587 could be completed immediately, without blocking.
588 **/
589 static
590 short
591 EFIAPI
da_ShellPoll(struct __filedes * filp,short events)592 da_ShellPoll(
593 struct __filedes *filp,
594 short events
595 )
596 {
597 UINT32 RdyMask;
598 short retval = 0;
599
600 RdyMask = (UINT32)filp->Oflags;
601
602 switch(RdyMask & O_ACCMODE) {
603 case O_RDONLY:
604 retval = (POLLIN | POLLRDNORM);
605 break;
606
607 case O_WRONLY:
608 retval = POLLOUT;
609 break;
610
611 case O_RDWR:
612 retval = (POLLIN | POLLRDNORM | POLLOUT);
613 break;
614
615 default:
616 retval = POLLERR;
617 break;
618 }
619 return (retval & (events | POLL_RETONLY));
620 }
621
622 /** EFI Shell specific operations for renaming a file.
623
624 @param[in] from Name of the file to be renamed.
625 @param[in] to New name for the file.
626
627 @retval 0 Successful completion.
628 @retval -1 Operation failed. Further information is specified by errno.
629 **/
630 static
631 int
632 EFIAPI
da_ShellRename(const char * from,const char * to)633 da_ShellRename(
634 const char *from,
635 const char *to
636 )
637 {
638 RETURN_STATUS Status;
639 EFI_FILE_INFO *NewFileInfo;
640 EFI_FILE_INFO *OldFileInfo;
641 wchar_t *NewFn;
642 int OldFd;
643 SHELL_FILE_HANDLE FileHandle;
644 wchar_t *NormalizedPath;
645
646 // Open old file
647 OldFd = open(from, O_RDWR, 0);
648 if(OldFd >= 0) {
649 FileHandle = (SHELL_FILE_HANDLE)gMD->fdarray[OldFd].devdata;
650
651 NewFileInfo = malloc(sizeof(EFI_FILE_INFO) + PATH_MAX);
652 if(NewFileInfo != NULL) {
653 OldFileInfo = ShellGetFileInfo( FileHandle);
654 if(OldFileInfo != NULL) {
655 // Copy the Old file info into our new buffer, and free the old.
656 memcpy(NewFileInfo, OldFileInfo, sizeof(EFI_FILE_INFO));
657 FreePool(OldFileInfo);
658 // Normalize path and convert to WCS.
659 NormalizedPath = NormalizePath(to);
660 if (NormalizedPath != NULL) {
661 // Strip off all but the file name portion of new
662 NewFn = GetFileNameFromPath(NormalizedPath);
663 // Copy the new file name into our new file info buffer
664 wcsncpy(NewFileInfo->FileName, NewFn, wcslen(NewFn) + 1);
665 // Update the size of the structure.
666 NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFn);
667 // Apply the new file name
668 Status = ShellSetFileInfo(FileHandle, NewFileInfo);
669 free(NormalizedPath);
670 free(NewFileInfo);
671 if(Status == EFI_SUCCESS) {
672 // File has been successfully renamed. We are DONE!
673 return 0;
674 }
675 errno = EFI2errno( Status );
676 EFIerrno = Status;
677 }
678 else {
679 free(NewFileInfo);
680 errno = ENOMEM;
681 }
682 }
683 else {
684 free(NewFileInfo);
685 errno = EIO;
686 }
687 }
688 else {
689 errno = ENOMEM;
690 }
691 }
692 return -1;
693 }
694
695 /** EFI Shell specific operations for deleting directories.
696
697 @param[in] filp Pointer to a file descriptor structure.
698
699 @retval 0 Successful completion.
700 @retval -1 Operation failed. Further information is specified by errno.
701 **/
702 static
703 int
704 EFIAPI
da_ShellRmdir(struct __filedes * filp)705 da_ShellRmdir(
706 struct __filedes *filp
707 )
708 {
709 SHELL_FILE_HANDLE FileHandle;
710 RETURN_STATUS Status = RETURN_SUCCESS;
711 EFI_FILE_INFO *FileInfo;
712 int OldErrno;
713 int Count = 0;
714 BOOLEAN NoFile = FALSE;
715
716 OldErrno = errno; // Save the original value
717 errno = 0; // Make it easier to see if we have an error later
718
719 FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
720
721 FileInfo = ShellGetFileInfo(FileHandle);
722 if(FileInfo != NULL) {
723 if((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
724 errno = ENOTDIR;
725 }
726 else {
727 FreePool(FileInfo); // Free up the buffer from ShellGetFileInfo()
728 // See if the directory has any entries other than ".." and ".".
729 Status = ShellFindFirstFile( FileHandle, &FileInfo);
730 if(Status == RETURN_SUCCESS) {
731 ++Count;
732 while(Count < 3) {
733 Status = ShellFindNextFile( FileHandle, FileInfo, &NoFile);
734 if(Status == RETURN_SUCCESS) {
735 if(NoFile) {
736 break;
737 }
738 ++Count;
739 }
740 else {
741 Count = 99;
742 }
743 }
744 /* Count == 99 and FileInfo is allocated if ShellFindNextFile failed.
745 ShellFindNextFile has freed FileInfo itself if it sets NoFile TRUE.
746 */
747 if((! NoFile) || (Count == 99)) {
748 free(FileInfo); // Free buffer from ShellFindFirstFile()
749 }
750 if(Count < 3) {
751 // Directory is empty
752 Status = ShellDeleteFile( &FileHandle);
753 if(Status == RETURN_SUCCESS) {
754 EFIerrno = RETURN_SUCCESS;
755 errno = OldErrno; // Restore the original value
756 return 0;
757 /* ######## SUCCESSFUL RETURN ######## */
758 }
759 /* FileInfo is freed and FileHandle closed. */
760 }
761 else {
762 if(Count == 99) {
763 errno = EIO;
764 }
765 else {
766 errno = ENOTEMPTY;
767 }
768 }
769 }
770 }
771 }
772 else {
773 errno = EIO;
774 }
775 ShellCloseFile( &FileHandle);
776 EFIerrno = Status;
777 if(errno == 0) {
778 errno = EFI2errno( Status );
779 }
780 return -1;
781 }
782
783 /** Construct an instance of the abstract Shell device.
784
785 Allocate the instance structure and populate it with the information for
786 the device.
787
788 @param[in] ImageHandle This application's image handle.
789 @param[in] SystemTable Pointer to the UEFI System Table.
790
791 @retval RETURN_SUCCESS Successful completion.
792 @retval RETURN_OUT_OF_RESOURCES Failed to allocate memory for new device.
793 @retval RETURN_INVALID_PARAMETER A default device has already been created.
794 **/
795 RETURN_STATUS
796 EFIAPI
__ctor_DevShell(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)797 __ctor_DevShell(
798 IN EFI_HANDLE ImageHandle,
799 IN EFI_SYSTEM_TABLE *SystemTable
800 )
801 {
802 GenericInstance *Stream;
803 DeviceNode *Node;
804 RETURN_STATUS Status;
805
806 Stream = (GenericInstance *)AllocateZeroPool(sizeof(GenericInstance));
807 if(Stream == NULL) {
808 return RETURN_OUT_OF_RESOURCES;
809 }
810
811 Stream->Cookie = CON_COOKIE;
812 Stream->InstanceNum = 1;
813 Stream->Dev = NULL;
814 Stream->Abstraction.fo_close = &da_ShellClose;
815 Stream->Abstraction.fo_read = &da_ShellRead;
816 Stream->Abstraction.fo_write = &da_ShellWrite;
817 Stream->Abstraction.fo_fcntl = &fnullop_fcntl;
818 Stream->Abstraction.fo_poll = &da_ShellPoll;
819 Stream->Abstraction.fo_flush = &fnullop_flush;
820 Stream->Abstraction.fo_stat = &da_ShellStat;
821 Stream->Abstraction.fo_ioctl = &da_ShellIoctl;
822 Stream->Abstraction.fo_delete = &da_ShellDelete;
823 Stream->Abstraction.fo_rmdir = &da_ShellRmdir;
824 Stream->Abstraction.fo_mkdir = &da_ShellMkdir;
825 Stream->Abstraction.fo_rename = &da_ShellRename;
826 Stream->Abstraction.fo_lseek = &da_ShellSeek;
827
828 Node = __DevRegister(NULL, NULL, &da_ShellOpen, Stream, 1, sizeof(GenericInstance), O_RDWR);
829 Status = EFIerrno;
830 Stream->Parent = Node;
831
832 return Status;
833 }
834
835 /** Destructor for previously constructed EFI Shell device instances.
836
837 @param[in] ImageHandle This application's image handle.
838 @param[in] SystemTable Pointer to the UEFI System Table.
839
840 @retval 0 Successful completion is always returned.
841 **/
842 RETURN_STATUS
843 EFIAPI
__dtor_DevShell(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)844 __dtor_DevShell(
845 IN EFI_HANDLE ImageHandle,
846 IN EFI_SYSTEM_TABLE *SystemTable
847 )
848 {
849 if(daDefaultDevice != NULL) {
850 if(daDefaultDevice->InstanceList != NULL) {
851 FreePool(daDefaultDevice->InstanceList);
852 }
853 FreePool(daDefaultDevice);
854 }
855 return RETURN_SUCCESS;
856 }
857