IN EFI_FILE_PROTOCOL *This\r
);\r
\r
+/**\r
+ Flush all modified data associated with a file to a device.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the\r
+ file handle to flush.\r
+\r
+ @retval EFI_SUCCESS The data was flushed.\r
+ @retval EFI_ACCESS_DENIED The file was opened read-only.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_FULL The volume is full.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsFlushFile (\r
IN EFI_FILE_PROTOCOL *This\r
);\r
\r
+/**\r
+ Close a specified file handle.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
+ handle to close.\r
+\r
+ @retval EFI_SUCCESS The file was closed.\r
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open\r
+ file handle.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsCloseFile (\r
/**\r
Open a file on the boot monitor file system.\r
\r
- @param[in] This The EFI_FILE_PROTOCOL parent handle.\r
+ The boot monitor file system does not allow for sub-directories. There is only\r
+ one directory, the root one. On any attempt to create a directory, the function\r
+ returns in error with the EFI_WRITE_PROTECTED error code.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
+ the file handle to source location.\r
@param[out] NewHandle A pointer to the location to return the opened\r
handle for the new file.\r
@param[in] FileName The Null-terminated string of the name of the file\r
directory in which to create a file could not be found.\r
@retval EFI_DEVICE_ERROR The device reported an error.\r
@retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible\r
- with the BootMon file system.\r
+ with the Boot Monitor file system.\r
@retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
\r
reported an error while performing the read\r
operation.\r
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
**/\r
EFIAPI\r
EFI_STATUS\r
OUT UINT64 *Position\r
);\r
\r
+/**\r
+ Write data to an open file.\r
+\r
+ The data is not written to the flash yet. It will be written when the file\r
+ will be either read, closed or flushed.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
+ is the file handle to write data to.\r
+ @param[in out] BufferSize On input, the size of the Buffer. On output, the\r
+ size of the data actually written. In both cases,\r
+ the size is measured in bytes.\r
+ @param[in] Buffer The buffer of data to write.\r
+\r
+ @retval EFI_SUCCESS The data was written.\r
+ @retval EFI_ACCESS_DENIED The file was opened read only.\r
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the buffer to store the\r
+ data to write.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsWriteFile (\r
IN EFI_FILE_PROTOCOL *This\r
);\r
\r
+/**\r
+ Close and delete a file from the boot monitor file system.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
+ handle to delete.\r
+\r
+ @retval EFI_SUCCESS The file was closed and deleted.\r
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open\r
+ file handle.\r
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsDelete (\r
IN EFI_FILE_PROTOCOL *This\r
);\r
\r
+/**\r
+ Set a file's current position.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
+ the file handle to set the requested position on.\r
+ @param[in] Position The byte position from the start of the file to set.\r
+\r
+ @retval EFI_SUCCESS The position was set.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsSetPosition (\r
IN UINT64 Position\r
);\r
\r
+/**\r
+ Return a file's current position.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
+ the file handle to get the current position on.\r
+ @param[out] Position The address to return the file's current position value.\r
+\r
+ @retval EFI_SUCCESS The position was returned.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsGetPosition(\r
OUT UINT64 *Position\r
);\r
\r
+/**\r
+ Set information about a file or a volume.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
+ is the file handle the information is for.\r
+ @param[in] InformationType The type identifier for the information being set :\r
+ EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or\r
+ EFI_FILE_SYSTEM_VOLUME_LABEL_ID\r
+ @param[in] BufferSize The size, in bytes, of Buffer.\r
+ @param[in] Buffer A pointer to the data buffer to write. The type of the\r
+ data inside the buffer is indicated by InformationType.\r
+\r
+ @retval EFI_SUCCESS The information was set.\r
+ @retval EFI_UNSUPPORTED The InformationType is not known.\r
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
+ to a file that is already present.\r
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
+ EFI_FILE_DIRECTORY Attribute.\r
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and\r
+ the file was opened in read-only mode and an\r
+ attempt is being made to modify a field other\r
+ than Attribute.\r
+ @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only\r
+ attribute.\r
+ @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by\r
+ the data inside the buffer.\r
+ @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsSetInfo (\r
//\r
// Internal API\r
//\r
+\r
+/**\r
+ Search for a file given its name coded in Ascii.\r
+\r
+ When searching through the files of the volume, if a file is currently not\r
+ open, its name was written on the media and is kept in RAM in the\r
+ "HwDescription.Footer.Filename[]" field of the file's description.\r
+\r
+ If a file is currently open, its name might not have been written on the\r
+ media yet, and as the "HwDescription" is a mirror in RAM of what is on the\r
+ media the "HwDescription.Footer.Filename[]" might be outdated. In that case,\r
+ the up to date name of the file is stored in the "Info" field of the file's\r
+ description.\r
+\r
+ @param[in] Instance Pointer to the description of the volume in which\r
+ the file has to be search for.\r
+ @param[in] AsciiFileName Name of the file.\r
+\r
+ @param[out] File Pointer to the description of the file if the\r
+ file was found.\r
+\r
+ @retval EFI_SUCCESS The file was found.\r
+ @retval EFI_NOT_FOUND The file was not found.\r
+\r
+**/\r
EFI_STATUS\r
BootMonGetFileFromAsciiFileName (\r
IN BOOTMON_FS_INSTANCE *Instance,\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ Instance->RootFile->Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
+\r
*Root = &Instance->RootFile->File;\r
\r
return EFI_SUCCESS;\r
\r
return EFI_UNSUPPORTED;\r
}\r
+\r
+STATIC\r
EFI_STATUS\r
GetFileSystemVolumeLabelInfo (\r
IN BOOTMON_FS_INSTANCE *Instance,\r
return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));\r
}\r
\r
+STATIC\r
EFI_STATUS\r
GetFilesystemInfo (\r
IN BOOTMON_FS_INSTANCE *Instance,\r
return Status;\r
}\r
\r
+STATIC\r
EFI_STATUS\r
GetFileInfo (\r
- IN BOOTMON_FS_INSTANCE *Instance,\r
- IN BOOTMON_FS_FILE *File,\r
- IN OUT UINTN *BufferSize,\r
- OUT VOID *Buffer\r
+ IN BOOTMON_FS_INSTANCE *Instance,\r
+ IN BOOTMON_FS_FILE *File,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
)\r
{\r
- EFI_FILE_INFO *Info;\r
- UINTN ResultSize;\r
- UINTN NameSize;\r
- UINTN Index;\r
+ EFI_FILE_INFO *Info;\r
+ UINTN ResultSize;\r
\r
- if (File == Instance->RootFile) {\r
- NameSize = 0;\r
- ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);\r
- } else {\r
- NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;\r
- ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));\r
- }\r
+ ResultSize = SIZE_OF_EFI_FILE_INFO + StrSize (File->Info->FileName);\r
\r
if (*BufferSize < ResultSize) {\r
*BufferSize = ResultSize;\r
\r
Info = Buffer;\r
\r
- // Zero out the structure\r
- ZeroMem (Info, ResultSize);\r
-\r
- // Fill in the structure\r
+ CopyMem (Info, File->Info, ResultSize);\r
+ // Size of the information\r
Info->Size = ResultSize;\r
\r
- if (File == Instance->RootFile) {\r
- Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
- Info->FileName[0] = L'\0';\r
- } else {\r
- Info->FileSize = BootMonFsGetImageLength (File);\r
- Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
-\r
- for (Index = 0; Index < NameSize; Index++) {\r
- Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];\r
- }\r
- }\r
-\r
*BufferSize = ResultSize;\r
\r
return EFI_SUCCESS;\r
return Status;\r
}\r
\r
+/**\r
+ Set the name of a file.\r
+\r
+ This is a helper function for SetFileInfo().\r
+\r
+ @param[in] Instance A pointer to the description of the volume\r
+ the file belongs to.\r
+ @param[in] File A pointer to the description of the file.\r
+ @param[in] FileName A pointer to the new name of the file.\r
+\r
+ @retval EFI_SUCCESS The name was set.\r
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
+ to a file that is already present.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
SetFileName (\r
- IN BOOTMON_FS_FILE *File,\r
- IN CHAR16 *FileNameUnicode\r
+ IN BOOTMON_FS_INSTANCE *Instance,\r
+ IN BOOTMON_FS_FILE *File,\r
+ IN CONST CHAR16 *FileName\r
)\r
{\r
- CHAR8 *FileNameAscii;\r
- UINT16 SavedChar;\r
- UINTN FileNameSize;\r
- BOOTMON_FS_FILE *SameFile;\r
- EFI_STATUS Status;\r
+ CHAR16 TruncFileName[MAX_NAME_LENGTH];\r
+ CHAR8 AsciiFileName[MAX_NAME_LENGTH];\r
+ BOOTMON_FS_FILE *SameFile;\r
\r
- // EFI Shell inserts '\' in front of the filename that must be stripped\r
- if (FileNameUnicode[0] == L'\\') {\r
- FileNameUnicode++;\r
+ // If the file path start with a \ strip it. The EFI Shell may\r
+ // insert a \ in front of the file name.\r
+ if (FileName[0] == L'\\') {\r
+ FileName++;\r
}\r
- //\r
- // Convert Unicode into Ascii\r
- //\r
- SavedChar = L'\0';\r
- FileNameSize = StrLen (FileNameUnicode) + 1;\r
- FileNameAscii = AllocatePool (FileNameSize * sizeof (CHAR8));\r
- if (FileNameAscii == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- // If Unicode string is too long then truncate it.\r
- if (FileNameSize > MAX_NAME_LENGTH) {\r
- SavedChar = FileNameUnicode[MAX_NAME_LENGTH - 1];\r
- FileNameUnicode[MAX_NAME_LENGTH - 1] = L'\0';\r
- }\r
- UnicodeStrToAsciiStr (FileNameUnicode, FileNameAscii);\r
- // If the unicode string was truncated then restore its original content.\r
- if (SavedChar != L'\0') {\r
- FileNameUnicode[MAX_NAME_LENGTH - 1] = SavedChar;\r
- }\r
-\r
- // If we're changing the file name\r
- if (AsciiStrCmp (FileNameAscii, File->HwDescription.Footer.Filename) == 0) {\r
- // No change to filename.\r
- Status = EFI_SUCCESS;\r
- } else if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
- // You can only change the filename if you open the file for write.\r
- Status = EFI_ACCESS_DENIED;\r
- } else if (BootMonGetFileFromAsciiFileName (\r
- File->Instance,\r
- File->HwDescription.Footer.Filename,\r
- &SameFile) != EFI_NOT_FOUND) {\r
+\r
+ StrnCpy (TruncFileName, FileName, MAX_NAME_LENGTH - 1);\r
+ TruncFileName[MAX_NAME_LENGTH - 1] = 0;\r
+ UnicodeStrToAsciiStr (TruncFileName, AsciiFileName);\r
+\r
+ if (BootMonGetFileFromAsciiFileName (\r
+ File->Instance,\r
+ AsciiFileName,\r
+ &SameFile\r
+ ) != EFI_NOT_FOUND) {\r
// A file with that name already exists.\r
- Status = EFI_ACCESS_DENIED;\r
+ return EFI_ACCESS_DENIED;\r
} else {\r
// OK, change the filename.\r
- AsciiStrCpy (FileNameAscii, File->HwDescription.Footer.Filename);\r
- Status = EFI_SUCCESS;\r
+ AsciiStrToUnicodeStr (AsciiFileName, File->Info->FileName);\r
+ return EFI_SUCCESS;\r
}\r
-\r
- FreePool (FileNameAscii);\r
- return Status;\r
}\r
\r
-// Set the file's size (NB "size", not "physical size"). If the change amounts\r
-// to an increase, simply do a write followed by a flush.\r
-// (This is a helper function for SetFileInfo.)\r
+/**\r
+ Set the size of a file.\r
+\r
+ This is a helper function for SetFileInfo().\r
+\r
+ @param[in] Instance A pointer to the description of the volume\r
+ the file belongs to.\r
+ @param[in] File A pointer to the description of the file.\r
+ @param[in] NewSize The requested new size for the file.\r
+\r
+ @retval EFI_SUCCESS The size was set.\r
+ @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
SetFileSize (\r
- IN BOOTMON_FS_INSTANCE *Instance,\r
- IN BOOTMON_FS_FILE *BootMonFsFile,\r
- IN UINTN NewSize\r
+ IN BOOTMON_FS_INSTANCE *Instance,\r
+ IN BOOTMON_FS_FILE *BootMonFsFile,\r
+ IN UINTN NewSize\r
)\r
{\r
- UINT64 StoredPosition;\r
- EFI_STATUS Status;\r
- EFI_FILE_PROTOCOL *File;\r
- CHAR8 Buffer;\r
- UINTN BufferSize;\r
- UINT32 OldSize;\r
-\r
- OldSize = BootMonFsFile->HwDescription.Region[0].Size;\r
-\r
- if (OldSize == NewSize) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- Buffer = 0;\r
- BufferSize = sizeof (Buffer);\r
+ EFI_STATUS Status;\r
+ UINT32 OldSize;\r
+ LIST_ENTRY *RegionToFlushLink;\r
+ LIST_ENTRY *NextRegionToFlushLink;\r
+ BOOTMON_FS_FILE_REGION *Region;\r
+ EFI_FILE_PROTOCOL *File;\r
+ CHAR8 *Buffer;\r
+ UINTN BufferSize;\r
+ UINT64 StoredPosition;\r
\r
- File = &BootMonFsFile->File;\r
+ OldSize = BootMonFsFile->Info->FileSize;\r
\r
- if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) {\r
- return EFI_ACCESS_DENIED;\r
- }\r
+ //\r
+ // In case of file truncation, force the regions waiting for writing to\r
+ // not overflow the new size of the file.\r
+ //\r
+ if (NewSize < OldSize) {\r
+ for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink);\r
+ !IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);\r
+ )\r
+ {\r
+ NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);\r
+ Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
+ if (Region->Offset > NewSize) {\r
+ RemoveEntryList (RegionToFlushLink);\r
+ FreePool (Region->Buffer);\r
+ FreePool (Region);\r
+ } else {\r
+ Region->Size = MIN (Region->Size, NewSize - Region->Offset);\r
+ }\r
+ RegionToFlushLink = NextRegionToFlushLink;\r
+ }\r
\r
- if (NewSize <= OldSize) {\r
- OldSize = NewSize;\r
- } else {\r
+ } else if (NewSize > OldSize) {\r
// Increasing a file's size is potentially complicated as it may require\r
// moving the image description on media. The simplest way to do it is to\r
// seek past the end of the file (which is valid in UEFI) and perform a\r
// Write.\r
+ File = &BootMonFsFile->File;\r
\r
// Save position\r
Status = File->GetPosition (File, &StoredPosition);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
-\r
- Status = File->SetPosition (File, NewSize - 1);\r
+ // Set position at the end of the file\r
+ Status = File->SetPosition (File, OldSize);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- Status = File->Write (File, &BufferSize, &Buffer);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+\r
+ BufferSize = NewSize - OldSize;\r
+ Buffer = AllocateZeroPool (BufferSize);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- // Restore saved position\r
- Status = File->SetPosition (File, NewSize - 1);\r
+ Status = File->Write (File, &BufferSize, Buffer);\r
+ FreePool (Buffer);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- Status = File->Flush (File);\r
+ // Restore saved position\r
+ Status = File->SetPosition (File, StoredPosition);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
+\r
+ BootMonFsFile->Info->FileSize = NewSize;\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Set information about a file.\r
+\r
+ @param[in] Instance A pointer to the description of the volume\r
+ the file belongs to.\r
+ @param[in] File A pointer to the description of the file.\r
+ @param[in] Info A pointer to the file information to write.\r
+\r
+ @retval EFI_SUCCESS The information was set.\r
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
+ EFI_FILE_DIRECTORY Attribute.\r
+ @retval EFI_ACCESS_DENIED The file was opened in read-only mode and an\r
+ attempt is being made to modify a field other\r
+ than Attribute.\r
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
+ to a file that is already present.\r
+ @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only\r
+ attribute.\r
+ @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request\r
+ failed.\r
+\r
+**/\r
+STATIC\r
EFI_STATUS\r
SetFileInfo (\r
- IN BOOTMON_FS_INSTANCE *Instance,\r
- IN BOOTMON_FS_FILE *File,\r
- IN UINTN BufferSize,\r
- IN EFI_FILE_INFO *Info\r
+ IN BOOTMON_FS_INSTANCE *Instance,\r
+ IN BOOTMON_FS_FILE *File,\r
+ IN EFI_FILE_INFO *Info\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
+ BOOLEAN FileSizeIsDifferent;\r
+ BOOLEAN FileNameIsDifferent;\r
+ BOOLEAN TimeIsDifferent;\r
\r
- Status = EFI_SUCCESS;\r
+ //\r
+ // A directory can not be changed to a file and a file can\r
+ // not be changed to a directory.\r
+ //\r
+ if ((Info->Attribute & EFI_FILE_DIRECTORY) !=\r
+ (File->Info->Attribute & EFI_FILE_DIRECTORY) ) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
\r
- // Note that a call to this function on a file opened read-only is only\r
- // invalid if it actually changes fields, so we don't immediately fail if the\r
- // OpenMode is wrong.\r
- // Also note that the only fields supported are filename and size, others are\r
- // ignored.\r
+ FileSizeIsDifferent = (Info->FileSize != File->Info->FileSize);\r
+ FileNameIsDifferent = (StrnCmp (\r
+ Info->FileName,\r
+ File->Info->FileName,\r
+ MAX_NAME_LENGTH - 1\r
+ ) != 0);\r
+ //\r
+ // Check if the CreateTime, LastAccess or ModificationTime\r
+ // have been changed. The file system does not support file\r
+ // timestamps thus the three times in "File->Info" are\r
+ // always equal to zero. The following comparison actually\r
+ // checks if all three times are still equal to 0 or not.\r
+ //\r
+ TimeIsDifferent = CompareMem (\r
+ &Info->CreateTime,\r
+ &File->Info->CreateTime,\r
+ 3 * sizeof (EFI_TIME)\r
+ ) != 0;\r
\r
- if (File != Instance->RootFile) {\r
- if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+ //\r
+ // For a file opened in read-only mode, only the Attribute field can be\r
+ // modified. The root directory open mode is forced to read-only at opening\r
+ // thus the following test protects the root directory to be somehow modified.\r
+ //\r
+ if (File->OpenMode == EFI_FILE_MODE_READ) {\r
+ if (FileSizeIsDifferent || FileNameIsDifferent || TimeIsDifferent) {\r
return EFI_ACCESS_DENIED;\r
}\r
+ }\r
+\r
+ if (TimeIsDifferent) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
\r
- Status = SetFileName (File, Info->FileName);\r
+ if (FileSizeIsDifferent) {\r
+ Status = SetFileSize (Instance, File, Info->FileSize);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+ }\r
\r
- // Update file size\r
- Status = SetFileSize (Instance, File, Info->FileSize);\r
+ //\r
+ // Note down in RAM the Attribute field but we can not\r
+ // ask to store it in flash for the time being.\r
+ //\r
+ File->Info->Attribute = Info->Attribute;\r
+\r
+ if (FileNameIsDifferent) {\r
+ Status = SetFileName (Instance, File, Info->FileName);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
- return Status;\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
EFIAPI\r
BOOTMON_FS_FILE *File;\r
BOOTMON_FS_INSTANCE *Instance;\r
\r
- File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (File == NULL) {\r
- return EFI_DEVICE_ERROR;\r
+ if ((This == NULL) ||\r
+ (InformationType == NULL) ||\r
+ (BufferSize == NULL) ||\r
+ ((Buffer == NULL) && (*BufferSize > 0)) ) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
+ File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+ if (File->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
Instance = File->Instance;\r
\r
// If the instance has not been initialized yet then do it ...\r
return Status;\r
}\r
\r
+/**\r
+ Set information about a file or a volume.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
+ is the file handle the information is for.\r
+ @param[in] InformationType The type identifier for the information being set :\r
+ EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or\r
+ EFI_FILE_SYSTEM_VOLUME_LABEL_ID\r
+ @param[in] BufferSize The size, in bytes, of Buffer.\r
+ @param[in] Buffer A pointer to the data buffer to write. The type of the\r
+ data inside the buffer is indicated by InformationType.\r
+\r
+ @retval EFI_SUCCESS The information was set.\r
+ @retval EFI_UNSUPPORTED The InformationType is not known.\r
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
+ to a file that is already present.\r
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
+ EFI_FILE_DIRECTORY Attribute.\r
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and\r
+ the file was opened in read-only mode and an\r
+ attempt is being made to modify a field other\r
+ than Attribute.\r
+ @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only\r
+ attribute.\r
+ @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by\r
+ the data inside the buffer.\r
+ @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsSetInfo (\r
IN VOID *Buffer\r
)\r
{\r
- EFI_STATUS Status;\r
- BOOTMON_FS_FILE *File;\r
- BOOTMON_FS_INSTANCE *Instance;\r
+ BOOTMON_FS_FILE *File;\r
+ EFI_FILE_INFO *Info;\r
+ EFI_FILE_SYSTEM_INFO *SystemInfo;\r
+\r
+ if ((This == NULL) ||\r
+ (InformationType == NULL) ||\r
+ (Buffer == NULL) ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (File == NULL) {\r
- return EFI_DEVICE_ERROR;\r
+ if (File->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- Instance = File->Instance;\r
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+ Info = Buffer;\r
+ if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (BufferSize < Info->Size) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+ return (SetFileInfo (File->Instance, File, Info));\r
+ }\r
\r
- if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
- Status = SetFileInfo (Instance, File, BufferSize, (EFI_FILE_INFO *) Buffer);\r
- } else {\r
- // The only writable field in the other two information types\r
- // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the\r
- // filesystem volume label. This can be retrieved with GetInfo, but it is\r
- // hard-coded into this driver, not stored on media.\r
- Status = EFI_UNSUPPORTED;\r
+ //\r
+ // The only writable field in the other two information types\r
+ // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the\r
+ // filesystem volume label. This can be retrieved with GetInfo, but it is\r
+ // hard-coded into this driver, not stored on media.\r
+ //\r
+\r
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
+ SystemInfo = Buffer;\r
+ if (SystemInfo->Size <\r
+ (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (BufferSize < SystemInfo->Size) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+ return EFI_WRITE_PROTECTED;\r
}\r
\r
- return Status;\r
+ if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
}\r
\r
EFIAPI\r
BootMonFsFlushFile\r
};\r
\r
+/**\r
+ Search for a file given its name coded in Ascii.\r
+\r
+ When searching through the files of the volume, if a file is currently not\r
+ open, its name was written on the media and is kept in RAM in the\r
+ "HwDescription.Footer.Filename[]" field of the file's description.\r
+\r
+ If a file is currently open, its name might not have been written on the\r
+ media yet, and as the "HwDescription" is a mirror in RAM of what is on the\r
+ media the "HwDescription.Footer.Filename[]" might be outdated. In that case,\r
+ the up to date name of the file is stored in the "Info" field of the file's\r
+ description.\r
+\r
+ @param[in] Instance Pointer to the description of the volume in which\r
+ the file has to be search for.\r
+ @param[in] AsciiFileName Name of the file.\r
+\r
+ @param[out] File Pointer to the description of the file if the\r
+ file was found.\r
+\r
+ @retval EFI_SUCCESS The file was found.\r
+ @retval EFI_NOT_FOUND The file was not found.\r
+\r
+**/\r
EFI_STATUS\r
BootMonGetFileFromAsciiFileName (\r
IN BOOTMON_FS_INSTANCE *Instance,\r
OUT BOOTMON_FS_FILE **File\r
)\r
{\r
- LIST_ENTRY *Entry;\r
- BOOTMON_FS_FILE *FileEntry;\r
-\r
- // Remove the leading '\\'\r
- if (*AsciiFileName == '\\') {\r
- AsciiFileName++;\r
- }\r
+ LIST_ENTRY *Entry;\r
+ BOOTMON_FS_FILE *FileEntry;\r
+ CHAR8 OpenFileAsciiFileName[MAX_NAME_LENGTH];\r
+ CHAR8 *AsciiFileNameToCompare;\r
\r
// Go through all the files in the list and return the file handle\r
for (Entry = GetFirstNode (&Instance->RootFile->Link);\r
- !IsNull (&Instance->RootFile->Link, Entry);\r
- Entry = GetNextNode (&Instance->RootFile->Link, Entry)\r
- )\r
+ !IsNull (&Instance->RootFile->Link, Entry);\r
+ Entry = GetNextNode (&Instance->RootFile->Link, Entry)\r
+ )\r
{\r
FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);\r
- if (AsciiStrCmp (FileEntry->HwDescription.Footer.Filename, AsciiFileName) == 0) {\r
+ if (FileEntry->Info != NULL) {\r
+ UnicodeStrToAsciiStr (FileEntry->Info->FileName, OpenFileAsciiFileName);\r
+ AsciiFileNameToCompare = OpenFileAsciiFileName;\r
+ } else {\r
+ AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename;\r
+ }\r
+\r
+ if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) {\r
*File = FileEntry;\r
return EFI_SUCCESS;\r
}\r
BOOTMON_FS_INSTANCE *Instance;\r
EFI_STATUS Status;\r
UINTN VolumeNameSize;\r
+ EFI_FILE_INFO *Info;\r
\r
Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));\r
if (Instance == NULL) {\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
);\r
if (EFI_ERROR (Status)) {\r
- FreePool (Instance);\r
- return Status;\r
+ goto Error;\r
}\r
\r
Status = gBS->OpenProtocol (\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
);\r
if (EFI_ERROR (Status)) {\r
- FreePool (Instance);\r
- return Status;\r
+ goto Error;\r
}\r
\r
//\r
// Initialize the root file\r
Status = BootMonFsCreateFile (Instance, &Instance->RootFile);\r
if (EFI_ERROR (Status)) {\r
- FreePool (Instance);\r
- return Status;\r
+ goto Error;\r
}\r
\r
+ Info = AllocateZeroPool (sizeof (EFI_FILE_INFO));\r
+ if (Info == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+ Instance->RootFile->Info = Info;\r
+\r
// Initialize the DevicePath of the Instance\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
);\r
if (EFI_ERROR (Status)) {\r
- FreePool (Instance);\r
- return Status;\r
+ goto Error;\r
}\r
\r
//\r
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,\r
NULL\r
);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
\r
InsertTailList (&mInstances, &Instance->Link);\r
\r
+ return EFI_SUCCESS;\r
+\r
+Error:\r
+\r
+ if (Instance->RootFile != NULL) {\r
+ if (Instance->RootFile->Info != NULL) {\r
+ FreePool (Instance->RootFile->Info);\r
+ }\r
+ FreePool (Instance->RootFile);\r
+ }\r
+ FreePool (Instance);\r
+\r
return Status;\r
}\r
\r
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,\r
NULL);\r
\r
+ FreePool (Instance->RootFile->Info);\r
+ FreePool (Instance->RootFile);\r
+ FreePool (Instance);\r
+\r
return Status;\r
}\r
\r
\r
EFI_FILE_PROTOCOL File;\r
\r
+ //\r
+ // The following fields are relevant only if the file is open.\r
+ //\r
+\r
+ EFI_FILE_INFO *Info;\r
UINT64 Position;\r
- // If the file needs to be flushed then this list contain the memory buffer that creates this file\r
+ // If the file needs to be flushed then this list contain the memory\r
+ // buffer that creates this file\r
LIST_ENTRY RegionToFlushLink;\r
UINT64 OpenMode;\r
} BOOTMON_FS_FILE;\r
\r
Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));\r
\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
Status = DiskIo->WriteDisk (DiskIo,\r
MediaId,\r
File->HwDescAddress,\r
return Status;\r
}\r
\r
-// Flush file data that will extend the file's length. Update and, if necessary,\r
-// move the image description.\r
-// We need to pass the file's starting position on media (FileStart), because\r
-// if the file hasn't been flushed before its Description->BlockStart won't\r
-// have been initialised.\r
-// FileStart must be aligned to the media's block size.\r
-// Note that this function uses DiskIo to flush, so call BlockIo->FlushBlocks()\r
-// after calling it.\r
+/**\r
+ Write the description of a file to storage media.\r
+\r
+ This function uses DiskIo to write to the media, so call BlockIo->FlushBlocks()\r
+ after calling it to ensure the data are written on the media.\r
+\r
+ @param[in] File Description of the file whose description on the\r
+ storage media has to be updated.\r
+ @param[in] FileName Name of the file. Its length is assumed to be\r
+ lower than MAX_NAME_LENGTH.\r
+ @param[in] DataSize Number of data bytes of the file.\r
+ @param[in] FileStart File's starting position on media. FileStart must\r
+ be aligned to the media's block size.\r
+\r
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the write operation.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
-FlushAppendRegion (\r
- IN BOOTMON_FS_FILE *File,\r
- IN BOOTMON_FS_FILE_REGION *Region,\r
- IN UINT64 NewFileSize,\r
- IN UINT64 FileStart\r
+WriteFileDescription (\r
+ IN BOOTMON_FS_FILE *File,\r
+ IN CHAR8 *FileName,\r
+ IN UINT32 DataSize,\r
+ IN UINT64 FileStart\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_DISK_IO_PROTOCOL *DiskIo;\r
- UINTN BlockSize;\r
- HW_IMAGE_DESCRIPTION *Description;\r
-\r
- DiskIo = File->Instance->DiskIo;\r
+ EFI_STATUS Status;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ UINTN BlockSize;\r
+ UINT32 FileSize;\r
+ HW_IMAGE_DESCRIPTION *Description;\r
\r
+ DiskIo = File->Instance->DiskIo;\r
BlockSize = File->Instance->BlockIo->Media->BlockSize;\r
-\r
ASSERT (FileStart % BlockSize == 0);\r
\r
- // Only invalidate the Image Description of files that have already been\r
- // written in Flash\r
- if (File->HwDescAddress != 0) {\r
- Status = InvalidateImageDescription (File);\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
//\r
- // Update File Description\r
+ // Construct the file description\r
//\r
+\r
+ FileSize = DataSize + sizeof (HW_IMAGE_DESCRIPTION);\r
Description = &File->HwDescription;\r
Description->Attributes = 1;\r
Description->BlockStart = FileStart / BlockSize;\r
- Description->BlockEnd = Description->BlockStart + (NewFileSize / BlockSize);\r
- Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;\r
- Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;\r
+ Description->BlockEnd = Description->BlockStart + (FileSize / BlockSize);\r
+ AsciiStrCpy (Description->Footer.Filename, FileName);\r
+\r
#ifdef MDE_CPU_ARM\r
+ Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;\r
Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;\r
- Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;\r
#else\r
+ Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;\r
Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2;\r
- Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;\r
#endif\r
+ Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;\r
+ Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;\r
Description->RegionCount = 1;\r
Description->Region[0].Checksum = 0;\r
Description->Region[0].Offset = Description->BlockStart * BlockSize;\r
- Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);\r
+ Description->Region[0].Size = DataSize;\r
\r
Status = BootMonFsComputeFooterChecksum (Description);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- // Write the new file data\r
- Status = DiskIo->WriteDisk (\r
- DiskIo,\r
- File->Instance->Media->MediaId,\r
- FileStart + Region->Offset,\r
- Region->Size,\r
- Region->Buffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- // Round the file size up to the nearest block size\r
- if ((NewFileSize % BlockSize) > 0) {\r
- NewFileSize += BlockSize - (NewFileSize % BlockSize);\r
- }\r
-\r
- File->HwDescAddress = (FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION);\r
+ File->HwDescAddress = ((Description->BlockEnd + 1) * BlockSize) - sizeof (HW_IMAGE_DESCRIPTION);\r
\r
// Update the file description on the media\r
Status = DiskIo->WriteDisk (\r
return Status;\r
}\r
\r
-BOOLEAN\r
-BootMonFsFileNeedFlush (\r
- IN BOOTMON_FS_FILE *File\r
- )\r
-{\r
- return !IsListEmpty (&File->RegionToFlushLink);\r
-}\r
-\r
// Find a space on media for a file that has not yet been flushed to disk.\r
// Just returns the first space that's big enough.\r
// This function could easily be adapted to:\r
EFI_STATUS\r
BootMonFsFindSpaceForNewFile (\r
IN BOOTMON_FS_FILE *File,\r
+ IN UINT64 FileSize,\r
OUT UINT64 *FileStart\r
)\r
{\r
BOOTMON_FS_FILE *RootFile;\r
BOOTMON_FS_FILE *FileEntry;\r
UINTN BlockSize;\r
- UINT64 FileSize;\r
EFI_BLOCK_IO_MEDIA *Media;\r
\r
Media = File->Instance->BlockIo->Media;\r
BlockSize = Media->BlockSize;\r
RootFile = File->Instance->RootFile;\r
\r
- if (IsListEmpty (&RootFile->Link)) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
// This function must only be called for file which has not been flushed into\r
// Flash yet\r
ASSERT (File->HwDescription.RegionCount == 0);\r
\r
- // Find out how big the file will be\r
- FileSize = BootMonFsGetImageLength (File);\r
- // Add the file header to the file\r
- FileSize += sizeof (HW_IMAGE_DESCRIPTION);\r
-\r
*FileStart = 0;\r
// Go through all the files in the list\r
for (FileLink = GetFirstNode (&RootFile->Link);\r
}\r
}\r
\r
+/**\r
+ Flush all modified data associated with a file to a device.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the\r
+ file handle to flush.\r
+\r
+ @retval EFI_SUCCESS The data was flushed.\r
+ @retval EFI_ACCESS_DENIED The file was opened read-only.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_FULL The volume is full.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsFlushFile (\r
{\r
EFI_STATUS Status;\r
BOOTMON_FS_INSTANCE *Instance;\r
+ EFI_FILE_INFO *Info;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ UINTN BlockSize;\r
+ CHAR8 AsciiFileName[MAX_NAME_LENGTH];\r
LIST_ENTRY *RegionToFlushLink;\r
BOOTMON_FS_FILE *File;\r
BOOTMON_FS_FILE *NextFile;\r
BOOTMON_FS_FILE_REGION *Region;\r
LIST_ENTRY *FileLink;\r
UINTN CurrentPhysicalSize;\r
- UINTN BlockSize;\r
UINT64 FileStart;\r
UINT64 FileEnd;\r
UINT64 RegionStart;\r
UINT64 RegionEnd;\r
+ UINT64 NewDataSize;\r
UINT64 NewFileSize;\r
UINT64 EndOfAppendSpace;\r
BOOLEAN HasSpace;\r
- EFI_DISK_IO_PROTOCOL *DiskIo;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
\r
- Status = EFI_SUCCESS;\r
- FileStart = 0;\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (File == NULL) {\r
+ if (File->Info == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Check if the file needs to be flushed\r
- if (!BootMonFsFileNeedFlush (File)) {\r
- return Status;\r
+ if (File->OpenMode == EFI_FILE_MODE_READ) {\r
+ return EFI_ACCESS_DENIED;\r
}\r
\r
- Instance = File->Instance;\r
- BlockIo = Instance->BlockIo;\r
- DiskIo = Instance->DiskIo;\r
- BlockSize = BlockIo->Media->BlockSize;\r
+ Instance = File->Instance;\r
+ Info = File->Info;\r
+ BlockIo = Instance->BlockIo;\r
+ Media = BlockIo->Media;\r
+ DiskIo = Instance->DiskIo;\r
+ BlockSize = Media->BlockSize;\r
+\r
+ UnicodeStrToAsciiStr (Info->FileName, AsciiFileName);\r
\r
// If the file doesn't exist then find a space for it\r
if (File->HwDescription.RegionCount == 0) {\r
- Status = BootMonFsFindSpaceForNewFile (File, &FileStart);\r
- // FileStart has changed so we need to recompute RegionEnd\r
+ Status = BootMonFsFindSpaceForNewFile (\r
+ File,\r
+ Info->FileSize + sizeof (HW_IMAGE_DESCRIPTION),\r
+ &FileStart\r
+ );\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
} else {\r
FileStart = File->HwDescription.BlockStart * BlockSize;\r
}\r
-\r
// FileEnd is the current NOR address of the end of the file's data\r
FileEnd = FileStart + File->HwDescription.Region[0].Size;\r
\r
)\r
{\r
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
+ if (Region->Size == 0) {\r
+ continue;\r
+ }\r
\r
// RegionStart and RegionEnd are the the intended NOR address of the\r
// start and end of the region\r
- RegionStart = FileStart + Region->Offset;\r
- RegionEnd = RegionStart + Region->Size;\r
+ RegionStart = FileStart + Region->Offset;\r
+ RegionEnd = RegionStart + Region->Size;\r
\r
if (RegionEnd < FileEnd) {\r
// Handle regions representing edits to existing portions of the file\r
// Write the region data straight into the file\r
Status = DiskIo->WriteDisk (DiskIo,\r
- BlockIo->Media->MediaId,\r
+ Media->MediaId,\r
RegionStart,\r
Region->Size,\r
Region->Buffer\r
\r
// Check if there is space to append the new region\r
HasSpace = FALSE;\r
- NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);\r
+ NewDataSize = RegionEnd - FileStart;\r
+ NewFileSize = NewDataSize + sizeof (HW_IMAGE_DESCRIPTION);\r
CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);\r
if (NewFileSize <= CurrentPhysicalSize) {\r
HasSpace = TRUE;\r
EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;\r
} else {\r
// We are flushing the last file.\r
- EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;\r
+ EndOfAppendSpace = (Media->LastBlock + 1) * BlockSize;\r
}\r
if (EndOfAppendSpace - FileStart >= NewFileSize) {\r
HasSpace = TRUE;\r
}\r
\r
if (HasSpace == TRUE) {\r
- Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);\r
+ // Invalidate the current image description of the file if any.\r
+ if (File->HwDescAddress != 0) {\r
+ Status = InvalidateImageDescription (File);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ // Write the new file data\r
+ Status = DiskIo->WriteDisk (\r
+ DiskIo,\r
+ Media->MediaId,\r
+ RegionStart,\r
+ Region->Size,\r
+ Region->Buffer\r
+ );\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+\r
+ Status = WriteFileDescription (File, AsciiFileName, NewDataSize, FileStart);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
} else {\r
// There isn't a space for the file.\r
// Options here are to move the file or fragment it. However as files\r
}\r
\r
FreeFileRegions (File);\r
+ Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
+\r
+ if ((AsciiStrCmp (AsciiFileName, File->HwDescription.Footer.Filename) != 0) ||\r
+ (Info->FileSize != File->HwDescription.Region[0].Size) ) {\r
+ Status = WriteFileDescription (File, AsciiFileName, Info->FileSize, FileStart);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
\r
// Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by\r
// calling FlushBlocks on the same device's BlockIo).\r
BlockIo->FlushBlocks (BlockIo);\r
\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
- Closes a file on the Nor Flash FS volume.\r
+ Close a specified file handle.\r
\r
- @param This The EFI_FILE_PROTOCOL to close.\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
+ handle to close.\r
\r
- @return Always returns EFI_SUCCESS.\r
+ @retval EFI_SUCCESS The file was closed.\r
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open\r
+ file handle.\r
\r
**/\r
EFIAPI\r
IN EFI_FILE_PROTOCOL *This\r
)\r
{\r
- // Flush the file if needed\r
- This->Flush (This);\r
- return EFI_SUCCESS;\r
-}\r
+ BOOTMON_FS_FILE *File;\r
\r
-// Create a new instance of BOOTMON_FS_FILE.\r
-// Uses BootMonFsCreateFile to\r
-STATIC\r
-EFI_STATUS\r
-CreateNewFile (\r
- IN BOOTMON_FS_INSTANCE *Instance,\r
- IN CHAR8* AsciiFileName,\r
- OUT BOOTMON_FS_FILE **NewHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BOOTMON_FS_FILE *File;\r
-\r
- Status = BootMonFsCreateFile (Instance, &File);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Remove the leading '\\'\r
- if (*AsciiFileName == '\\') {\r
- AsciiFileName++;\r
+ File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+ if (File->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Set the file name\r
- CopyMem (File->HwDescription.Footer.Filename, AsciiFileName, MAX_NAME_LENGTH);\r
-\r
- // Add the file to list of files of the File System\r
- InsertHeadList (&Instance->RootFile->Link, &File->Link);\r
+ // In the case of a file and not the root directory\r
+ if (This != &File->Instance->RootFile->File) {\r
+ This->Flush (This);\r
+ FreePool (File->Info);\r
+ File->Info = NULL;\r
+ }\r
\r
- *NewHandle = File;\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
CHAR16 *Path;\r
CHAR16 *Separator;\r
CHAR8 *AsciiFileName;\r
+ EFI_FILE_INFO *Info;\r
\r
if (This == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+ if (Directory->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
if ((FileName == NULL) || (NewHandle == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (Directory == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
Instance = Directory->Instance;\r
\r
//\r
}\r
Path = (CHAR16*)Buf;\r
AsciiFileName = NULL;\r
+ Info = NULL;\r
\r
//\r
// Handle single periods, double periods and convert forward slashes '/'\r
goto Error;\r
}\r
\r
+ //\r
+ // Allocate a buffer to store the characteristics of the file while the\r
+ // file is open. We allocate the maximum size to not have to reallocate\r
+ // if the file name is changed.\r
+ //\r
+ Info = AllocateZeroPool (\r
+ SIZE_OF_EFI_FILE_INFO + (sizeof (CHAR16) * MAX_NAME_LENGTH));\r
+ if (Info == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
//\r
// Open or create a file in the root directory.\r
//\r
goto Error;\r
}\r
\r
- Status = CreateNewFile (Instance, AsciiFileName, &File);\r
- if (!EFI_ERROR (Status)) {\r
- File->OpenMode = OpenMode;\r
- *NewHandle = &File->File;\r
- File->Position = 0;\r
+ Status = BootMonFsCreateFile (Instance, &File);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
}\r
+ InsertHeadList (&Instance->RootFile->Link, &File->Link);\r
+ Info->Attribute = Attributes;\r
} else {\r
//\r
- // The file already exists.\r
+ // File already open, not supported yet.\r
//\r
- File->OpenMode = OpenMode;\r
- *NewHandle = &File->File;\r
- File->Position = 0;\r
+ if (File->Info != NULL) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Error;\r
+ }\r
}\r
+\r
+ Info->FileSize = BootMonFsGetImageLength (File);\r
+ Info->PhysicalSize = BootMonFsGetPhysicalSize (File);\r
+ AsciiStrToUnicodeStr (AsciiFileName, Info->FileName);\r
+\r
+ File->Info = Info;\r
+ Info = NULL;\r
+ File->Position = 0;\r
+ File->OpenMode = OpenMode;\r
+\r
+ *NewHandle = &File->File;\r
}\r
\r
Error:\r
if (AsciiFileName != NULL) {\r
FreePool (AsciiFileName);\r
}\r
+ if (Info != NULL) {\r
+ FreePool (Info);\r
+ }\r
\r
return Status;\r
}\r
// You can't delete the root directory\r
return EFI_WARN_DELETE_FAILURE;\r
}\r
+\r
+/**\r
+ Close and delete a file from the boot monitor file system.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
+ handle to delete.\r
+\r
+ @retval EFI_SUCCESS The file was closed and deleted.\r
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open\r
+ file handle.\r
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsDelete (\r
BOOTMON_FS_FILE *File;\r
LIST_ENTRY *RegionToFlushLink;\r
BOOTMON_FS_FILE_REGION *Region;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
- UINT8 *EmptyBuffer;\r
\r
- File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (File == NULL) {\r
- return EFI_DEVICE_ERROR;\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- Status = EFI_SUCCESS;\r
+ File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+ if (File->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- if (BootMonFsFileNeedFlush (File)) {\r
+ if (!IsListEmpty (&File->RegionToFlushLink)) {\r
// Free the entries from the Buffer List\r
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
do {\r
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
\r
- // Get Next entry\r
+ //\r
+ // Get next element of the list before deleting the region description\r
+ // that contain the LIST_ENTRY structure.\r
+ //\r
RegionToFlushLink = RemoveEntryList (RegionToFlushLink);\r
\r
// Free the buffers\r
\r
// If (RegionCount is greater than 0) then the file already exists\r
if (File->HwDescription.RegionCount > 0) {\r
- BlockIo = File->Instance->BlockIo;\r
-\r
- // Create an empty buffer\r
- EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);\r
- if (EmptyBuffer == NULL) {\r
- FreePool (File);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
// Invalidate the last Block\r
Status = InvalidateImageDescription (File);\r
ASSERT_EFI_ERROR (Status);\r
-\r
- FreePool (EmptyBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_WARN_DELETE_FAILURE;\r
+ }\r
}\r
\r
// Remove the entry from the list\r
RemoveEntryList (&File->Link);\r
+ FreePool (File->Info);\r
FreePool (File);\r
- return Status;\r
-}\r
\r
+ return EFI_SUCCESS;\r
+}\r
reported an error while performing the read\r
operation.\r
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
**/\r
EFIAPI\r
EFI_STATUS\r
EFI_STATUS Status;\r
UINTN RemainingFileSize;\r
\r
- // Ensure the file has been written in Flash before reading it.\r
- // This keeps the code simple and avoids having to manage a non-flushed file.\r
- BootMonFsFlushFile (This);\r
-\r
+ if ((This == NULL) ||\r
+ (BufferSize == NULL) ||\r
+ (Buffer == NULL) ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (File == NULL) {\r
+ if (File->Info == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Instance = File->Instance;\r
- DiskIo = Instance->DiskIo;\r
- Media = Instance->Media;\r
+ // Ensure the file has been written in Flash before reading it.\r
+ // This keeps the code simple and avoids having to manage a non-flushed file.\r
+ BootMonFsFlushFile (This);\r
+\r
+ Instance = File->Instance;\r
+ DiskIo = Instance->DiskIo;\r
+ Media = Instance->Media;\r
FileStart = (Media->LowestAlignedLba + File->HwDescription.BlockStart) * Media->BlockSize;\r
\r
- if (File->Position >= File->HwDescription.Region[0].Size) {\r
+ if (File->Position >= File->Info->FileSize) {\r
// The entire file has been read or the position has been\r
// set past the end of the file.\r
*BufferSize = 0;\r
- if (File->Position > File->HwDescription.Region[0].Size) {\r
+ if (File->Position > File->Info->FileSize) {\r
return EFI_DEVICE_ERROR;\r
} else {\r
return EFI_SUCCESS;\r
}\r
\r
// This driver assumes that the entire file is in region 0.\r
- RemainingFileSize = File->HwDescription.Region[0].Size - File->Position;\r
+ RemainingFileSize = File->Info->FileSize - File->Position;\r
\r
// If read would go past end of file, truncate the read\r
if (*BufferSize > RemainingFileSize) {\r
return Status;\r
}\r
\r
-// Inserts an entry into the write chain\r
+/**\r
+ Write data to an open file.\r
+\r
+ The data is not written to the flash yet. It will be written when the file\r
+ will be either read, closed or flushed.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
+ is the file handle to write data to.\r
+ @param[in out] BufferSize On input, the size of the Buffer. On output, the\r
+ size of the data actually written. In both cases,\r
+ the size is measured in bytes.\r
+ @param[in] Buffer The buffer of data to write.\r
+\r
+ @retval EFI_SUCCESS The data was written.\r
+ @retval EFI_ACCESS_DENIED The file was opened read only.\r
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the buffer to store the\r
+ data to write.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsWriteFile (\r
BOOTMON_FS_FILE *File;\r
BOOTMON_FS_FILE_REGION *Region;\r
\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
- if (File == NULL) {\r
+ if (File->Info == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+ if (File->OpenMode == EFI_FILE_MODE_READ) {\r
return EFI_ACCESS_DENIED;\r
}\r
\r
// Allocate and initialize the memory region\r
Region = (BOOTMON_FS_FILE_REGION*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE_REGION));\r
if (Region == NULL) {\r
+ *BufferSize = 0;\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- Region->Buffer = AllocateCopyPool (*BufferSize, Buffer);\r
+ Region->Buffer = AllocateCopyPool (*BufferSize, Buffer);\r
if (Region->Buffer == NULL) {\r
+ *BufferSize = 0;\r
FreePool (Region);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- Region->Size = *BufferSize;\r
-\r
+ Region->Size = *BufferSize;\r
Region->Offset = File->Position;\r
\r
InsertTailList (&File->RegionToFlushLink, &Region->Link);\r
\r
File->Position += *BufferSize;\r
\r
+ if (File->Position > File->Info->FileSize) {\r
+ File->Info->FileSize = File->Position;\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Set a file's current position.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
+ the file handle to set the requested position on.\r
+ @param[in] Position The byte position from the start of the file to set.\r
+\r
+ @retval EFI_SUCCESS The position was set.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsSetPosition (\r
IN UINT64 Position\r
)\r
{\r
- BOOTMON_FS_FILE *File;\r
+ BOOTMON_FS_FILE *File;\r
\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+ if (File->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
+ //\r
// UEFI Spec section 12.5:\r
// "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to\r
- // be set to the end of the file."\r
+ // be set to the end of the file."\r
+ //\r
if (Position == 0xFFFFFFFFFFFFFFFF) {\r
- File->Position = BootMonFsGetImageLength (File);\r
- } else {\r
- // NB: Seeking past the end of the file is valid.\r
- File->Position = Position;\r
+ Position = File->Info->FileSize;\r
}\r
\r
+ File->Position = Position;\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Return a file's current position.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
+ the file handle to get the current position on.\r
+ @param[out] Position The address to return the file's current position value.\r
+\r
+ @retval EFI_SUCCESS The position was returned.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFIAPI\r
EFI_STATUS\r
BootMonFsGetPosition (\r
IN EFI_FILE_PROTOCOL *This,\r
OUT UINT64 *Position\r
- ) {\r
+ )\r
+{\r
BOOTMON_FS_FILE *File;\r
\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
+ if (File->Info == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Position == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
*Position = File->Position;\r
+\r
return EFI_SUCCESS;\r
}\r