• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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