1 /** @file 2 Routines dealing with setting/getting file/volume info 3 4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials are licensed and made available 6 under the terms and conditions of the BSD License which accompanies this 7 distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 14 15 **/ 16 17 #include "Fat.h" 18 19 /** 20 21 Get the volume's info into Buffer. 22 23 @param Volume - FAT file system volume. 24 @param BufferSize - Size of Buffer. 25 @param Buffer - Buffer containing volume info. 26 27 @retval EFI_SUCCESS - Get the volume info successfully. 28 @retval EFI_BUFFER_TOO_SMALL - The buffer is too small. 29 30 **/ 31 EFI_STATUS 32 FatGetVolumeInfo ( 33 IN FAT_VOLUME *Volume, 34 IN OUT UINTN *BufferSize, 35 OUT VOID *Buffer 36 ); 37 38 /** 39 40 Set the volume's info. 41 42 @param Volume - FAT file system volume. 43 @param BufferSize - Size of Buffer. 44 @param Buffer - Buffer containing the new volume info. 45 46 @retval EFI_SUCCESS - Set the volume info successfully. 47 @retval EFI_BAD_BUFFER_SIZE - The buffer size is error. 48 @retval EFI_WRITE_PROTECTED - The volume is read only. 49 @return other - An error occurred when operation the disk. 50 51 **/ 52 EFI_STATUS 53 FatSetVolumeInfo ( 54 IN FAT_VOLUME *Volume, 55 IN UINTN BufferSize, 56 IN VOID *Buffer 57 ); 58 59 /** 60 61 Set or Get the some types info of the file into Buffer. 62 63 @param IsSet - TRUE:The access is set, else is get 64 @param FHand - The handle of file 65 @param Type - The type of the info 66 @param BufferSize - Size of Buffer 67 @param Buffer - Buffer containing volume info 68 69 @retval EFI_SUCCESS - Get the info successfully 70 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file 71 72 **/ 73 EFI_STATUS 74 FatSetOrGetInfo ( 75 IN BOOLEAN IsSet, 76 IN EFI_FILE_PROTOCOL *FHand, 77 IN EFI_GUID *Type, 78 IN OUT UINTN *BufferSize, 79 IN OUT VOID *Buffer 80 ); 81 82 /** 83 84 Get the open file's info into Buffer. 85 86 @param OFile - The open file. 87 @param BufferSize - Size of Buffer. 88 @param Buffer - Buffer containing file info. 89 90 @retval EFI_SUCCESS - Get the file info successfully. 91 @retval EFI_BUFFER_TOO_SMALL - The buffer is too small. 92 93 **/ 94 EFI_STATUS 95 FatGetFileInfo ( 96 IN FAT_OFILE *OFile, 97 IN OUT UINTN *BufferSize, 98 OUT VOID *Buffer 99 ) 100 { 101 return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer); 102 } 103 104 /** 105 106 Get the volume's info into Buffer. 107 108 @param Volume - FAT file system volume. 109 @param BufferSize - Size of Buffer. 110 @param Buffer - Buffer containing volume info. 111 112 @retval EFI_SUCCESS - Get the volume info successfully. 113 @retval EFI_BUFFER_TOO_SMALL - The buffer is too small. 114 115 **/ 116 EFI_STATUS 117 FatGetVolumeInfo ( 118 IN FAT_VOLUME *Volume, 119 IN OUT UINTN *BufferSize, 120 OUT VOID *Buffer 121 ) 122 { 123 UINTN Size; 124 UINTN NameSize; 125 UINTN ResultSize; 126 CHAR16 Name[FAT_NAME_LEN + 1]; 127 EFI_STATUS Status; 128 EFI_FILE_SYSTEM_INFO *Info; 129 UINT8 ClusterAlignment; 130 131 Size = SIZE_OF_EFI_FILE_SYSTEM_INFO; 132 Status = FatGetVolumeEntry (Volume, Name); 133 NameSize = StrSize (Name); 134 ResultSize = Size + NameSize; 135 ClusterAlignment = Volume->ClusterAlignment; 136 137 // 138 // If we don't have valid info, compute it now 139 // 140 FatComputeFreeInfo (Volume); 141 142 Status = EFI_BUFFER_TOO_SMALL; 143 if (*BufferSize >= ResultSize) { 144 Status = EFI_SUCCESS; 145 146 Info = Buffer; 147 ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO); 148 149 Info->Size = ResultSize; 150 Info->ReadOnly = Volume->ReadOnly; 151 Info->BlockSize = (UINT32) Volume->ClusterSize; 152 Info->VolumeSize = LShiftU64 (Volume->MaxCluster, ClusterAlignment); 153 Info->FreeSpace = LShiftU64 ( 154 Volume->FatInfoSector.FreeInfo.ClusterCount, 155 ClusterAlignment 156 ); 157 CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize); 158 } 159 160 *BufferSize = ResultSize; 161 return Status; 162 } 163 164 /** 165 166 Get the volume's label info into Buffer. 167 168 @param Volume - FAT file system volume. 169 @param BufferSize - Size of Buffer. 170 @param Buffer - Buffer containing volume's label info. 171 172 @retval EFI_SUCCESS - Get the volume's label info successfully. 173 @retval EFI_BUFFER_TOO_SMALL - The buffer is too small. 174 175 **/ 176 EFI_STATUS 177 FatGetVolumeLabelInfo ( 178 IN FAT_VOLUME *Volume, 179 IN OUT UINTN *BufferSize, 180 OUT VOID *Buffer 181 ) 182 { 183 UINTN Size; 184 UINTN NameSize; 185 UINTN ResultSize; 186 CHAR16 Name[FAT_NAME_LEN + 1]; 187 EFI_STATUS Status; 188 189 Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL; 190 Status = FatGetVolumeEntry (Volume, Name); 191 NameSize = StrSize (Name); 192 ResultSize = Size + NameSize; 193 194 Status = EFI_BUFFER_TOO_SMALL; 195 if (*BufferSize >= ResultSize) { 196 Status = EFI_SUCCESS; 197 CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize); 198 } 199 200 *BufferSize = ResultSize; 201 return Status; 202 } 203 204 /** 205 206 Set the volume's info. 207 208 @param Volume - FAT file system volume. 209 @param BufferSize - Size of Buffer. 210 @param Buffer - Buffer containing the new volume info. 211 212 @retval EFI_SUCCESS - Set the volume info successfully. 213 @retval EFI_BAD_BUFFER_SIZE - The buffer size is error. 214 @retval EFI_WRITE_PROTECTED - The volume is read only. 215 @return other - An error occurred when operation the disk. 216 217 **/ 218 EFI_STATUS 219 FatSetVolumeInfo ( 220 IN FAT_VOLUME *Volume, 221 IN UINTN BufferSize, 222 IN VOID *Buffer 223 ) 224 { 225 EFI_FILE_SYSTEM_INFO *Info; 226 227 Info = (EFI_FILE_SYSTEM_INFO *) Buffer; 228 229 if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) { 230 return EFI_BAD_BUFFER_SIZE; 231 } 232 233 return FatSetVolumeEntry (Volume, Info->VolumeLabel); 234 } 235 236 /** 237 238 Set the volume's label info. 239 240 @param Volume - FAT file system volume. 241 @param BufferSize - Size of Buffer. 242 @param Buffer - Buffer containing the new volume label info. 243 244 @retval EFI_SUCCESS - Set the volume label info successfully. 245 @retval EFI_WRITE_PROTECTED - The disk is write protected. 246 @retval EFI_BAD_BUFFER_SIZE - The buffer size is error. 247 @return other - An error occurred when operation the disk. 248 249 **/ 250 EFI_STATUS 251 FatSetVolumeLabelInfo ( 252 IN FAT_VOLUME *Volume, 253 IN UINTN BufferSize, 254 IN VOID *Buffer 255 ) 256 { 257 EFI_FILE_SYSTEM_VOLUME_LABEL *Info; 258 259 Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) Buffer; 260 261 if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 2) { 262 return EFI_BAD_BUFFER_SIZE; 263 } 264 265 return FatSetVolumeEntry (Volume, Info->VolumeLabel); 266 } 267 268 /** 269 270 Set the file info. 271 272 @param Volume - FAT file system volume. 273 @param IFile - The instance of the open file. 274 @param OFile - The open file. 275 @param BufferSize - Size of Buffer. 276 @param Buffer - Buffer containing the new file info. 277 278 @retval EFI_SUCCESS - Set the file info successfully. 279 @retval EFI_ACCESS_DENIED - It is the root directory 280 or the directory attribute bit can not change 281 or try to change a directory size 282 or something else. 283 @retval EFI_UNSUPPORTED - The new file size is larger than 4GB. 284 @retval EFI_WRITE_PROTECTED - The disk is write protected. 285 @retval EFI_BAD_BUFFER_SIZE - The buffer size is error. 286 @retval EFI_INVALID_PARAMETER - The time info or attributes info is error. 287 @retval EFI_OUT_OF_RESOURCES - Can not allocate new memory. 288 @retval EFI_VOLUME_CORRUPTED - The volume is corrupted. 289 @return other - An error occurred when operation the disk. 290 291 **/ 292 EFI_STATUS 293 FatSetFileInfo ( 294 IN FAT_VOLUME *Volume, 295 IN FAT_IFILE *IFile, 296 IN FAT_OFILE *OFile, 297 IN UINTN BufferSize, 298 IN VOID *Buffer 299 ) 300 { 301 EFI_STATUS Status; 302 EFI_FILE_INFO *NewInfo; 303 FAT_OFILE *DotOFile; 304 FAT_OFILE *Parent; 305 CHAR16 NewFileName[EFI_PATH_STRING_LENGTH]; 306 EFI_TIME ZeroTime; 307 FAT_DIRENT *DirEnt; 308 FAT_DIRENT *TempDirEnt; 309 UINT8 NewAttribute; 310 BOOLEAN ReadOnly; 311 312 ZeroMem (&ZeroTime, sizeof (EFI_TIME)); 313 Parent = OFile->Parent; 314 DirEnt = OFile->DirEnt; 315 // 316 // If this is the root directory, we can't make any updates 317 // 318 if (Parent == NULL) { 319 return EFI_ACCESS_DENIED; 320 } 321 // 322 // Make sure there's a valid input buffer 323 // 324 NewInfo = Buffer; 325 if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) { 326 return EFI_BAD_BUFFER_SIZE; 327 } 328 329 ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY)); 330 // 331 // if a zero time is specified, then the original time is preserved 332 // 333 if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) { 334 if (!FatIsValidTime (&NewInfo->CreateTime)) { 335 return EFI_INVALID_PARAMETER; 336 } 337 338 if (!ReadOnly) { 339 FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime); 340 } 341 } 342 343 if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) { 344 if (!FatIsValidTime (&NewInfo->ModificationTime)) { 345 return EFI_INVALID_PARAMETER; 346 } 347 348 if (!ReadOnly) { 349 FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime); 350 } 351 352 OFile->PreserveLastModification = TRUE; 353 } 354 355 if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) { 356 return EFI_INVALID_PARAMETER; 357 } 358 359 NewAttribute = (UINT8) NewInfo->Attribute; 360 // 361 // Can not change the directory attribute bit 362 // 363 if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) { 364 return EFI_ACCESS_DENIED; 365 } 366 // 367 // Set the current attributes even if the IFile->ReadOnly is TRUE 368 // 369 DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute); 370 // 371 // Open the filename and see if it refers to an existing file 372 // 373 Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName); 374 if (EFI_ERROR (Status)) { 375 return Status; 376 } 377 378 if (*NewFileName != 0) { 379 // 380 // File was not found. We do not allow rename of the current directory if 381 // there are open files below the current directory 382 // 383 if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) { 384 return EFI_ACCESS_DENIED; 385 } 386 387 if (ReadOnly) { 388 return EFI_ACCESS_DENIED; 389 } 390 391 Status = FatRemoveDirEnt (OFile->Parent, DirEnt); 392 if (EFI_ERROR (Status)) { 393 return Status; 394 } 395 // 396 // Create new dirent 397 // 398 Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt); 399 if (EFI_ERROR (Status)) { 400 return Status; 401 } 402 403 FatCloneDirEnt (TempDirEnt, DirEnt); 404 FatFreeDirEnt (DirEnt); 405 DirEnt = TempDirEnt; 406 DirEnt->OFile = OFile; 407 OFile->DirEnt = DirEnt; 408 OFile->Parent = Parent; 409 RemoveEntryList (&OFile->ChildLink); 410 InsertHeadList (&Parent->ChildHead, &OFile->ChildLink); 411 // 412 // If this is a directory, synchronize its dot directory entry 413 // 414 if (OFile->ODir != NULL) { 415 // 416 // Syncronize its dot entry 417 // 418 FatResetODirCursor (OFile); 419 ASSERT (OFile->Parent != NULL); 420 for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) { 421 Status = FatGetNextDirEnt (OFile, &DirEnt); 422 if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) { 423 return EFI_VOLUME_CORRUPTED; 424 } 425 426 FatCloneDirEnt (DirEnt, DotOFile->DirEnt); 427 Status = FatStoreDirEnt (OFile, DirEnt); 428 if (EFI_ERROR (Status)) { 429 return Status; 430 } 431 } 432 } 433 // 434 // If the file is renamed, we should append the ARCHIVE attribute 435 // 436 OFile->Archive = TRUE; 437 } else if (Parent != OFile) { 438 // 439 // filename is to a different filename that already exists 440 // 441 return EFI_ACCESS_DENIED; 442 } 443 // 444 // If the file size has changed, apply it 445 // 446 if (NewInfo->FileSize != OFile->FileSize) { 447 if (OFile->ODir != NULL || ReadOnly) { 448 // 449 // If this is a directory or the file is read only, we can't change the file size 450 // 451 return EFI_ACCESS_DENIED; 452 } 453 454 if (NewInfo->FileSize > OFile->FileSize) { 455 Status = FatExpandOFile (OFile, NewInfo->FileSize); 456 } else { 457 Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize); 458 } 459 460 if (EFI_ERROR (Status)) { 461 return Status; 462 } 463 464 FatUpdateDirEntClusterSizeInfo (OFile); 465 } 466 467 OFile->Dirty = TRUE; 468 return FatOFileFlush (OFile); 469 } 470 471 /** 472 473 Set or Get the some types info of the file into Buffer. 474 475 @param IsSet - TRUE:The access is set, else is get 476 @param FHand - The handle of file 477 @param Type - The type of the info 478 @param BufferSize - Size of Buffer 479 @param Buffer - Buffer containing volume info 480 481 @retval EFI_SUCCESS - Get the info successfully 482 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file 483 484 **/ 485 EFI_STATUS 486 FatSetOrGetInfo ( 487 IN BOOLEAN IsSet, 488 IN EFI_FILE_PROTOCOL *FHand, 489 IN EFI_GUID *Type, 490 IN OUT UINTN *BufferSize, 491 IN OUT VOID *Buffer 492 ) 493 { 494 FAT_IFILE *IFile; 495 FAT_OFILE *OFile; 496 FAT_VOLUME *Volume; 497 EFI_STATUS Status; 498 499 IFile = IFILE_FROM_FHAND (FHand); 500 OFile = IFile->OFile; 501 Volume = OFile->Volume; 502 503 Status = OFile->Error; 504 if (Status == EFI_NOT_FOUND) { 505 return EFI_DEVICE_ERROR; 506 } 507 508 FatWaitNonblockingTask (IFile); 509 510 FatAcquireLock (); 511 512 // 513 // Verify the file handle isn't in an error state 514 // 515 if (!EFI_ERROR (Status)) { 516 // 517 // Get the proper information based on the request 518 // 519 Status = EFI_UNSUPPORTED; 520 if (IsSet) { 521 if (CompareGuid (Type, &gEfiFileInfoGuid)) { 522 Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer); 523 } 524 525 if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) { 526 Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeInfo (Volume, *BufferSize, Buffer); 527 } 528 529 if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 530 Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer); 531 } 532 } else { 533 if (CompareGuid (Type, &gEfiFileInfoGuid)) { 534 Status = FatGetFileInfo (OFile, BufferSize, Buffer); 535 } 536 537 if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) { 538 Status = FatGetVolumeInfo (Volume, BufferSize, Buffer); 539 } 540 541 if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 542 Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer); 543 } 544 } 545 } 546 547 Status = FatCleanupVolume (Volume, NULL, Status, NULL); 548 549 FatReleaseLock (); 550 return Status; 551 } 552 553 /** 554 555 Get the some types info of the file into Buffer. 556 557 @param FHand - The handle of file. 558 @param Type - The type of the info. 559 @param BufferSize - Size of Buffer. 560 @param Buffer - Buffer containing volume info. 561 562 @retval EFI_SUCCESS - Get the info successfully. 563 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. 564 565 **/ 566 EFI_STATUS 567 EFIAPI 568 FatGetInfo ( 569 IN EFI_FILE_PROTOCOL *FHand, 570 IN EFI_GUID *Type, 571 IN OUT UINTN *BufferSize, 572 OUT VOID *Buffer 573 ) 574 { 575 return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer); 576 } 577 578 /** 579 580 Set the some types info of the file into Buffer. 581 582 @param FHand - The handle of file. 583 @param Type - The type of the info. 584 @param BufferSize - Size of Buffer 585 @param Buffer - Buffer containing volume info. 586 587 @retval EFI_SUCCESS - Set the info successfully. 588 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. 589 590 **/ 591 EFI_STATUS 592 EFIAPI 593 FatSetInfo ( 594 IN EFI_FILE_PROTOCOL *FHand, 595 IN EFI_GUID *Type, 596 IN UINTN BufferSize, 597 IN VOID *Buffer 598 ) 599 { 600 return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer); 601 } 602