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