From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mout01.posteo.de (mout01.posteo.de [185.67.36.65]) by mx.groups.io with SMTP id smtpd.web08.35080.1659026585789443699 for ; Thu, 28 Jul 2022 09:43:06 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@posteo.de header.s=2017 header.b=e3kI9vp6; spf=pass (domain: posteo.de, ip: 185.67.36.65, mailfrom: mhaeuser@posteo.de) Received: from submission (posteo.de [185.67.36.169]) by mout01.posteo.de (Postfix) with ESMTPS id 32E9E240029 for ; Thu, 28 Jul 2022 18:43:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.de; s=2017; t=1659026583; bh=SnLQNlQeEEDDkdYvTxBkgEbHPkmLhZC41wHVUOvYdu8=; h=From:Subject:Date:Cc:To:From; b=e3kI9vp6GLyHMYDghhwLbqQriWx4pnyzZQLTdDybL2zFpM1Ak01owYaOtBz9Ud8D1 BvVl/DAQK67eErey+0gSYvxD4HwU3XuuMO7iE+FKqSYZhnzeGaFaJfcXndoxRZF18f s7adXH37ZHuwm0nSOEk0DfPY0Jf0SiCisFkV/vkx4Uui30TpoiM3kuYEj1vkhzECaT 2AUjtVlJ2/Kh2coOtC21HezYW0ZazVOKiRTQKX9SfEtjLihf6yIoR1ZY4A4xpKdOXU CPNjABeAk00V1Dxq2ca8gIpRBQrxTD1BgFRujd3ZMK16c/VQPFTk5q8JibFjiwmaK5 oa/ONWhXTTXbw== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4LtxKL0sYnz9rxN; Thu, 28 Jul 2022 18:43:02 +0200 (CEST) From: =?utf-8?Q?Marvin_H=C3=A4user?= Mime-Version: 1.0 (1.0) Subject: Re: [edk2-platforms][PATCH v4 1/2] Ext4Pkg: Add symbolic links support Date: Thu, 28 Jul 2022 16:43:01 +0000 Message-Id: References: <20220728152644.11435-2-savvamtr@gmail.com> Cc: devel@edk2.groups.io, Pedro Falcato , Vitaly Cheptsov In-Reply-To: <20220728152644.11435-2-savvamtr@gmail.com> To: Savva Mitrofanov Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Looks very nice, tyvm. I did add a few more comments, but nothing critical a= t all. Reviewed-by: Marvin H=C3=A4user as-is or with my commen= ts addressed, either works. > On 28. Jul 2022, at 17:26, Savva Mitrofanov wrote: >=20 > =EF=BB=BFBZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3677 >=20 > Provided support for symlink file type. Added routine which allows > reading and following them through recursive open() call. As a security > meausure implemented simple symlink loop check with nest level limit > equal 8. Also this patch moves Ext4Open functionality to internal > routine. >=20 > Cc: Marvin H=C3=A4user > Cc: Pedro Falcato > Cc: Vitaly Cheptsov > Signed-off-by: Savva Mitrofanov > --- > Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 13 +- > Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h | 98 +++++- > Features/Ext4Pkg/Ext4Dxe/File.c | 359 ++++++++++++++++++-- > Features/Ext4Pkg/Ext4Dxe/Inode.c | 53 +++ > 4 files changed, 485 insertions(+), 38 deletions(-) >=20 > diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dx= e/Ext4Disk.h > index a55cd2fa68ad..a73e3f8622f1 100644 > --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h > +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h > @@ -171,7 +171,7 @@ > #define EXT4_DIRTY_FL 0x00000100 > #define EXT4_COMPRBLK_FL 0x00000200 > #define EXT4_NOCOMPR_FL 0x00000400 > -#define EXT4_ECOMPR_FL 0x00000800 > +#define EXT4_ENCRYPT_FL 0x00000800 > #define EXT4_BTREE_FL 0x00001000 > #define EXT4_INDEX_FL 0x00002000 > #define EXT4_JOURNAL_DATA_FL 0x00004000 > @@ -332,11 +332,12 @@ STATIC_ASSERT ( > "ext4 block group descriptor struct has incorrect size" > ); >=20 > -#define EXT4_DBLOCKS 12 > -#define EXT4_IND_BLOCK 12 > -#define EXT4_DIND_BLOCK 13 > -#define EXT4_TIND_BLOCK 14 > -#define EXT4_NR_BLOCKS 15 > +#define EXT4_DBLOCKS 12 > +#define EXT4_IND_BLOCK 12 > +#define EXT4_DIND_BLOCK 13 > +#define EXT4_TIND_BLOCK 14 > +#define EXT4_NR_BLOCKS 15 > +#define EXT4_FAST_SYMLINK_MAX_SIZE EXT4_NR_BLOCKS * sizeof(UINT32) >=20 > #define EXT4_GOOD_OLD_INODE_SIZE 128 >=20 > diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe= /Ext4Dxe.h > index b1508482b0a7..c1df9d1149e4 100644 > --- a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h > +++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h > @@ -31,7 +31,9 @@ >=20 > #include "Ext4Disk.h" >=20 > +#define SYMLOOP_MAX 8 > #define EXT4_NAME_MAX 255 > +#define EFI_PATH_MAX 4096 >=20 > #define EXT4_DRIVER_VERSION 0x0000 >=20 > @@ -324,11 +326,11 @@ number of read bytes. > **/ > EFI_STATUS > Ext4Read ( > - IN EXT4_PARTITION *Partition, > - IN EXT4_FILE *File, > - OUT VOID *Buffer, > - IN UINT64 Offset, > - IN OUT UINTN *Length > + IN EXT4_PARTITION *Partition, > + IN EXT4_FILE *File, > + OUT VOID *Buffer, > + IN UINT64 Offset, > + IN OUT UINTN *Length > ); >=20 > /** > @@ -368,6 +370,7 @@ struct _Ext4File { >=20 > UINT64 OpenMode; > UINT64 Position; > + UINT32 SymLoops; >=20 > EXT4_PARTITION *Partition; >=20 > @@ -497,6 +500,45 @@ Ext4SetupFile ( > IN EXT4_PARTITION *Partition > ); >=20 > +/** > + Opens a new file relative to the source file's location. > + > + @param[out] FoundFile A pointer to the location to return the opened h= andle for the new > + file. > + @param[in] Source A pointer to the EXT4_FILE instance that is the f= ile > + handle to the source location. This would typica= lly be an open > + handle to a directory. > + @param[in] FileName The Null-terminated string of the name of the fi= le to be opened. > + The file name may contain the following path mod= ifiers: "\", ".", > + and "..". > + @param[in] OpenMode The mode to open the file. The only valid combin= ations that the > + file may be opened with are: Read, Read/Write, o= r Create/Read/Write. > + @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which ca= se these are the > + attribute bits for the newly created file. > + > + @retval EFI_SUCCESS The file was opened. > + @retval EFI_NOT_FOUND The specified file could not be found on t= he device. > + @retval EFI_NO_MEDIA The device has no medium. > + @retval EFI_MEDIA_CHANGED The device has a different medium in it or= the medium is no > + longer supported. > + @retval EFI_DEVICE_ERROR The device reported an error. > + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. > + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or o= pen a file for write > + when the media is write-protected. > + @retval EFI_ACCESS_DENIED The service denied access to the file. > + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to ope= n the file. > + @retval EFI_VOLUME_FULL The volume is full. > + > +**/ > +EFI_STATUS > +Ext4OpenInternal ( > + OUT EXT4_FILE **FoundFile, > + IN EXT4_FILE *Source, > + IN CHAR16 *FileName, > + IN UINT64 OpenMode, > + IN UINT64 Attributes > + ); > + > /** > Closes a file. >=20 > @@ -774,6 +816,30 @@ Ext4FileIsDir ( > IN CONST EXT4_FILE *File > ); >=20 > +/** > + Checks if a file is a symlink. > + > + @param[in] File Pointer to the opened file. > + > + @return BOOLEAN Whether file is a symlink > +**/ > +BOOLEAN > +Ext4FileIsSymlink ( > + IN CONST EXT4_FILE *File > + ); > + > +/** > + Detects if a symlink is a fast symlink. > + > + @param[in] File Pointer to the opened file. > + > + @return BOOLEAN Whether symlink is a fast symlink > +**/ > +BOOLEAN > +Ext4SymlinkIsFastSymlink ( > + IN CONST EXT4_FILE *File > + ); > + > /** > Checks if a file is a regular file. > @param[in] File Pointer to the opened file. > @@ -797,7 +863,7 @@ Ext4FileIsReg ( > it's a regular file or a directory, since most other file types= > don't make sense under UEFI. > **/ > -#define Ext4FileIsOpenable(File) (Ext4FileIsReg(File) || Ext4FileIsDir(Fi= le)) > +#define Ext4FileIsOpenable(File) (Ext4FileIsReg (File) || Ext4FileIsDir (= File) || Ext4FileIsSymlink (File)) >=20 > #define EXT4_INODE_HAS_FIELD(Inode, Field) = \ > (Inode->i_extra_isize + EXT4_GOOD_OLD_INODE_SIZE >=3D = \ > @@ -935,6 +1001,26 @@ Ext4ReadDir ( > IN OUT UINTN *OutLength > ); >=20 > +/** > + Reads a symlink file. > + > + @param[in] Partition Pointer to the ext4 partition. > + @param[in] File Pointer to the open symlink file. > + @param[out] Symlink Pointer to the output unicode symlink strin= g. > + > + @retval EFI_SUCCESS Symlink was read. > + @retval EFI_ACCESS_DENIED Symlink is encrypted. > + @retval EFI_OUT_OF_RESOURCES Memory allocation error. > + @retval EFI_INVALID_PARAMETER Symlink path has incorrect length > + @retval EFI_VOLUME_CORRUPTED Symlink read block size differ from inode= value > +**/ > +EFI_STATUS > +Ext4ReadSymlink ( > + IN EXT4_PARTITION *Partition, > + IN EXT4_FILE *File, > + OUT CHAR16 **Symlink > + ); > + > /** > Initialises the (empty) extents map, that will work as a cache of exten= ts. >=20 > diff --git a/Features/Ext4Pkg/Ext4Dxe/File.c b/Features/Ext4Pkg/Ext4Dxe/Fi= le.c > index ff1746d5640a..ae9230d6422b 100644 > --- a/Features/Ext4Pkg/Ext4Dxe/File.c > +++ b/Features/Ext4Pkg/Ext4Dxe/File.c > @@ -134,14 +134,224 @@ Ext4DirCanLookup ( > return (File->Inode->i_mode & EXT4_INO_PERM_EXEC_OWNER) =3D=3D EXT4_INO_= PERM_EXEC_OWNER; > } >=20 > +/** > + Reads a fast symlink file. > + > + @param[in] Partition Pointer to the ext4 partition. > + @param[in] File Pointer to the open symlink file. > + @param[out] AsciiSymlink Pointer to the output ascii symlink st= ring. > + @param[out] AsciiSymlinkSize Pointer to the output ascii symlink st= ring length. > + > + @retval EFI_SUCCESS Fast symlink was read. > + @retval EFI_OUT_OF_RESOURCES Memory allocation error. > +**/ > +STATIC > +EFI_STATUS > +Ext4ReadFastSymlink ( > + IN EXT4_PARTITION *Partition, > + IN EXT4_FILE *File, > + OUT CHAR8 **AsciiSymlink, > + OUT UINT32 *AsciiSymlinkSize > + ) > +{ > + UINT32 SymlinkSize; > + CHAR8 *AsciiSymlinkTmp; > + // > + // Fast-symlink's EXT4_INODE_SIZE is not necessarily validated when we c= hecked it in > + // Ext4SymlinkIsFastSymlink(), so truncate if necessary. > + // > + SymlinkSize =3D (UINT32)MIN (EXT4_INODE_SIZE (File->Inode), EXT4_FAST_S= YMLINK_MAX_SIZE); > + > + AsciiSymlinkTmp =3D AllocatePool (SymlinkSize + 1); > + if (AsciiSymlinkTmp =3D=3D NULL) { > + DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink ascii string buf= fer\n")); > + return EFI_OUT_OF_RESOURCES; > + } > + > + CopyMem (AsciiSymlinkTmp, File->Inode->i_data, SymlinkSize); > + > + // > + // Add null-terminator > + // > + AsciiSymlinkTmp[SymlinkSize] =3D '\0'; > + > + *AsciiSymlink =3D AsciiSymlinkTmp; > + *AsciiSymlinkSize =3D SymlinkSize + 1; > + > + return EFI_SUCCESS; > +} > + > +/** > + Reads a slow symlink file. > + > + @param[in] Partition Pointer to the ext4 partition. > + @param[in] File Pointer to the open symlink file. > + @param[out] AsciiSymlink Pointer to the output ascii symlink st= ring. > + @param[out] AsciiSymlinkSize Pointer to the output ascii symlink st= ring length. > + > + @retval EFI_SUCCESS Slow symlink was read. > + @retval EFI_OUT_OF_RESOURCES Memory allocation error. > + @retval EFI_INVALID_PARAMETER Slow symlink path has incorrect length > + @retval EFI_VOLUME_CORRUPTED Symlink read block size differ from inode= value > +**/ > +STATIC > +EFI_STATUS > +Ext4ReadSlowSymlink ( > + IN EXT4_PARTITION *Partition, > + IN EXT4_FILE *File, > + OUT CHAR8 **AsciiSymlink, > + OUT UINT32 *AsciiSymlinkSize > + ) > +{ > + EFI_STATUS Status; > + CHAR8 *SymlinkTmp; > + UINT64 SymlinkSizeTmp; > + UINT32 SymlinkAllocateSize; > + UINTN ReadSize; > + > + SymlinkSizeTmp =3D EXT4_INODE_SIZE (File->Inode); > + > + // > + // Allocate EXT4_INODE_SIZE + 1 > + // > + if (SymlinkSizeTmp > EFI_PATH_MAX - 1) { > + DEBUG (( > + DEBUG_FS, > + "[ext4] Error! Symlink path maximum length was hit!\n" > + )); > + return EFI_INVALID_PARAMETER; > + } > + > + SymlinkAllocateSize =3D (UINT32)SymlinkSizeTmp + 1; > + > + SymlinkTmp =3D AllocatePool (SymlinkAllocateSize); > + if (SymlinkTmp =3D=3D NULL) { > + DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink ascii string buf= fer\n")); > + return EFI_OUT_OF_RESOURCES; > + } > + > + ReadSize =3D (UINTN)SymlinkSizeTmp; > + Status =3D Ext4Read (Partition, File, SymlinkTmp, File->Position, &Re= adSize); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_FS, "[ext4] Failed to read symlink from blocks with Sta= tus %r\n", Status)); > + FreePool (SymlinkTmp); > + return Status; > + } > + > + File->Position +=3D ReadSize; > + > + // > + // Add null-terminator > + // > + SymlinkTmp[SymlinkSizeTmp] =3D '\0'; > + > + if (SymlinkSizeTmp !=3D ReadSize) { > + DEBUG (( > + DEBUG_FS, > + "[ext4] Error! The sz of the read block doesn't match the value fro= m the inode!\n" > + )); > + return EFI_VOLUME_CORRUPTED; > + } > + > + *AsciiSymlinkSize =3D SymlinkAllocateSize; > + *AsciiSymlink =3D SymlinkTmp; > + > + return EFI_SUCCESS; > +} > + > +/** > + Reads a symlink file. > + > + @param[in] Partition Pointer to the ext4 partition. > + @param[in] File Pointer to the open symlink file. > + @param[out] Symlink Pointer to the output unicode symlink strin= g. > + > + @retval EFI_SUCCESS Symlink was read. > + @retval EFI_ACCESS_DENIED Symlink is encrypted. > + @retval EFI_OUT_OF_RESOURCES Memory allocation error. > + @retval EFI_INVALID_PARAMETER Symlink path has incorrect length > + @retval EFI_VOLUME_CORRUPTED Symlink read block size differ from inode= value > +**/ > +EFI_STATUS > +Ext4ReadSymlink ( > + IN EXT4_PARTITION *Partition, > + IN EXT4_FILE *File, > + OUT CHAR16 **Symlink > + ) > +{ > + EFI_STATUS Status; > + CHAR8 *SymlinkTmp; > + UINT32 SymlinkSize; > + CHAR16 *Symlink16Tmp; > + CHAR16 *Needle; > + > + // > + // Assume that we alread read Inode via Ext4ReadInode > + // Skip reading, just check encryption flag > + // > + if ((File->Inode->i_flags & EXT4_ENCRYPT_FL) !=3D 0) { > + DEBUG ((DEBUG_FS, "[ext4] Error, symlink is encrypted\n")); > + return EFI_ACCESS_DENIED; > + } > + > + if (Ext4SymlinkIsFastSymlink (File)) { > + Status =3D Ext4ReadFastSymlink (Partition, File, &SymlinkTmp, &Symlin= kSize); > + } else { > + Status =3D Ext4ReadSlowSymlink (Partition, File, &SymlinkTmp, &Symlin= kSize); > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_FS, "[ext4] Symlink read error with Status %r\n", Statu= s)); > + return Status; > + } > + > + Symlink16Tmp =3D AllocateZeroPool (SymlinkSize * sizeof (CHAR16)); Any specific reason to use ZeroPool here, when the rest of the code doesn=E2= =80=99t? > + if (Symlink16Tmp =3D=3D NULL) { > + DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink unicode string b= uffer\n")); > + FreePool (SymlinkTmp); > + return EFI_OUT_OF_RESOURCES; > + } > + > + Status =3D AsciiStrToUnicodeStrS ( > + SymlinkTmp, > + Symlink16Tmp, > + SymlinkSize > + ); Can=E2=80=99t SymlinkTmp be free=E2=80=99d here? > + > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_FS, > + "[ext4] Failed to convert ascii symlink to unicode with Status %r\n= ", > + Status > + )); > + FreePool (Symlink16Tmp); > + FreePool (SymlinkTmp); > + return Status; > + } > + > + // > + // Convert to UEFI slashes > + // > + for (Needle =3D Symlink16Tmp; *Needle !=3D L'\0'; Needle++) { > + if (*Needle =3D=3D L'/') { > + *Needle =3D L'\\'; > + } > + } > + > + *Symlink =3D Symlink16Tmp; > + > + FreePool (SymlinkTmp); > + return Status; > +} > + > /** > Opens a new file relative to the source file's location. >=20 > - @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that= is the file > + @param[out] FoundFile A pointer to the location to return the opened h= andle for the new > + file. > + @param[in] Source A pointer to the EXT4_FILE instance that is the f= ile > handle to the source location. This would typical= ly be an open > handle to a directory. > - @param[out] NewHandle A pointer to the location to return the opened h= andle for the new > - file. > @param[in] FileName The Null-terminated string of the name of the fil= e to be opened. > The file name may contain the following path modi= fiers: "\", ".", > and "..". > @@ -165,13 +375,12 @@ Ext4DirCanLookup ( >=20 > **/ > EFI_STATUS > -EFIAPI > -Ext4Open ( > - IN EFI_FILE_PROTOCOL *This, > - OUT EFI_FILE_PROTOCOL **NewHandle, > - IN CHAR16 *FileName, > - IN UINT64 OpenMode, > - IN UINT64 Attributes > +Ext4OpenInternal ( > + OUT EXT4_FILE **FoundFile, > + IN EXT4_FILE *Source, > + IN CHAR16 *FileName, > + IN UINT64 OpenMode, > + IN UINT64 Attributes > ) > { > EXT4_FILE *Current; > @@ -180,13 +389,14 @@ Ext4Open ( > CHAR16 PathSegment[EXT4_NAME_MAX + 1]; > UINTN Length; > EXT4_FILE *File; > + CHAR16 *Symlink; > EFI_STATUS Status; >=20 > - Current =3D (EXT4_FILE *)This; > + Current =3D Source; > Partition =3D Current->Partition; > Level =3D 0; >=20 > - DEBUG ((DEBUG_FS, "[ext4] Ext4Open %s\n", FileName)); > + DEBUG ((DEBUG_FS, "[ext4] Ext4OpenInternal %s\n", FileName)); > // If the path starts with a backslash, we treat the root directory as t= he base directory > if (FileName[0] =3D=3D L'\\') { > FileName++; > @@ -194,6 +404,11 @@ Ext4Open ( > } >=20 > while (FileName[0] !=3D L'\0') { > + if (Partition->Root->SymLoops > SYMLOOP_MAX) { > + DEBUG ((DEBUG_FS, "[ext4] Symloop limit is hit !\n")); > + return EFI_ACCESS_DENIED; > + } > + > // Discard leading path separators > while (FileName[0] =3D=3D L'\\') { > FileName++; > @@ -238,18 +453,45 @@ Ext4Open ( > } >=20 > // Check if this is a valid file to open in EFI > - > - // What to do with symlinks? They're nonsense when absolute but may > - // be useful when they're relative. Right now, they're ignored, since= they > - // bring a lot of trouble for something that's not as useful in our c= ase. > - // If you want to link, use hard links. > - > if (!Ext4FileIsOpenable (File)) { > Ext4CloseInternal (File); > // This looks like an /okay/ status to return. > return EFI_ACCESS_DENIED; > } >=20 > + // > + // Reading symlink and then trying to follow it > + // > + if (Ext4FileIsSymlink (File)) { > + Partition->Root->SymLoops++; > + DEBUG ((DEBUG_FS, "[ext4] File %s is symlink, trying to read it\n",= PathSegment)); > + Status =3D Ext4ReadSymlink (Partition, File, &Symlink); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_FS, "[ext4] Error reading %s symlink!\n", PathSegme= nt)); > + return Status; > + } > + > + DEBUG ((DEBUG_FS, "[ext4] File %s is linked to %s\n", PathSegment, S= ymlink)); > + // > + // Close symlink file > + // > + Ext4CloseInternal (File); > + // > + // Open linked file by recursive call of Ext4OpenFile > + // > + Status =3D Ext4OpenInternal (FoundFile, Current, Symlink, OpenMode,= Attributes); > + FreePool (Symlink); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_FS, "[ext4] Error opening linked file %s\n", Symlin= k)); > + return Status; > + } > + > + // > + // Set File to newly opened > + // > + File =3D *FoundFile; > + } > + > if (Level !=3D 0) { > // Careful not to close the base directory > Ext4CloseInternal (Current); > @@ -273,12 +515,75 @@ Ext4Open ( > return EFI_ACCESS_DENIED; > } >=20 > - *NewHandle =3D &Current->Protocol; > + *FoundFile =3D Current; >=20 > DEBUG ((DEBUG_FS, "[ext4] Opened filename %s\n", Current->Dentry->Name))= ; > return EFI_SUCCESS; > } >=20 > +/** > + Opens a new file relative to the source file's location. > + @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that= is the file > + handle to the source location. This would typica= lly be an open > + handle to a directory. > + @param[out] NewHandle A pointer to the location to return the opened h= andle for the new > + file. > + @param[in] FileName The Null-terminated string of the name of the fi= le to be opened. > + The file name may contain the following path mod= ifiers: "\", ".", > + and "..". > + @param[in] OpenMode The mode to open the file. The only valid combin= ations that the > + file may be opened with are: Read, Read/Write, o= r Create/Read/Write. > + @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which ca= se these are the > + attribute bits for the newly created file. > + @retval EFI_SUCCESS The file was opened. > + @retval EFI_NOT_FOUND The specified file could not be found on t= he device. > + @retval EFI_NO_MEDIA The device has no medium. > + @retval EFI_MEDIA_CHANGED The device has a different medium in it or= the medium is no > + longer supported. > + @retval EFI_DEVICE_ERROR The device reported an error. > + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. > + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or o= pen a file for write > + when the media is write-protected. > + @retval EFI_ACCESS_DENIED The service denied access to the file. > + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to ope= n the file. > + @retval EFI_VOLUME_FULL The volume is full. > +**/ > +EFI_STATUS > +EFIAPI > +Ext4Open ( > + IN EFI_FILE_PROTOCOL *This, > + OUT EFI_FILE_PROTOCOL **NewHandle, > + IN CHAR16 *FileName, > + IN UINT64 OpenMode, > + IN UINT64 Attributes > + ) > +{ > + EFI_STATUS Status; > + EXT4_FILE *FoundFile; > + EXT4_FILE *Source; > + > + Source =3D (EXT4_FILE *)This; > + > + // > + // Reset SymLoops counter > + // > + Source->Partition->Root->SymLoops =3D 0; > + > + Status =3D Ext4OpenInternal ( > + &FoundFile, > + Source, > + FileName, > + OpenMode, > + Attributes > + ); > + > + if (!EFI_ERROR (Status)) { > + *NewHandle =3D &FoundFile->Protocol; > + } > + > + return Status; > +} > + > /** > Closes a specified file handle. >=20 > @@ -588,7 +893,7 @@ Ext4GetVolumeName ( >=20 > // s_volume_name is only valid on dynamic revision; old filesystems don'= t support this > if (Partition->SuperBlock.s_rev_level =3D=3D EXT4_DYNAMIC_REV) { > - CopyMem (TempVolName, (CONST CHAR8 *)Partition->SuperBlock.s_volume_n= ame, 16); > + CopyMem (TempVolName, Partition->SuperBlock.s_volume_name, 16); > TempVolName[16] =3D '\0'; >=20 > Status =3D UTF8StrToUCS2 (TempVolName, &VolumeName); > @@ -754,12 +1059,14 @@ Ext4GetInfo ( > OUT VOID *Buffer > ) > { > + EXT4_FILE *File; > EXT4_PARTITION *Partition; >=20 > - Partition =3D ((EXT4_FILE *)This)->Partition; > + File =3D (EXT4_FILE *)This; > + Partition =3D File->Partition; >=20 > if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { > - return Ext4GetFileInfo ((EXT4_FILE *)This, Buffer, BufferSize); > + return Ext4GetFileInfo (File, Buffer, BufferSize); > } >=20 > if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { > @@ -870,12 +1177,12 @@ Ext4SetInfo ( > ) > { > EXT4_FILE *File; > - EXT4_PARTITION *Part; > + EXT4_PARTITION *Partition; >=20 > - File =3D (EXT4_FILE *)This; > - Part =3D File->Partition; > + File =3D (EXT4_FILE *)This; > + Partition =3D File->Partition; >=20 > - if (Part->ReadOnly) { > + if (Partition->ReadOnly) { > return EFI_WRITE_PROTECTED; > } >=20 > diff --git a/Features/Ext4Pkg/Ext4Dxe/Inode.c b/Features/Ext4Pkg/Ext4Dxe/I= node.c > index 831f5946e870..e7a6b3225709 100644 > --- a/Features/Ext4Pkg/Ext4Dxe/Inode.c > +++ b/Features/Ext4Pkg/Ext4Dxe/Inode.c > @@ -255,6 +255,59 @@ Ext4FileIsDir ( > return (File->Inode->i_mode & EXT4_INO_TYPE_DIR) =3D=3D EXT4_INO_TYPE_DI= R; > } >=20 > +/** > + Checks if a file is a symlink. > + > + @param[in] File Pointer to the opened file. > + > + @return BOOLEAN Whether file is a symlink > +**/ > +BOOLEAN > +Ext4FileIsSymlink ( > + IN CONST EXT4_FILE *File > + ) > +{ > + return (File->Inode->i_mode & EXT4_INO_TYPE_SYMLINK) =3D=3D EXT4_INO_TY= PE_SYMLINK; > +} > + > +/** > + Detects if a symlink is a fast symlink. > + > + @param[in] File Pointer to the opened file. > + > + @return BOOLEAN Whether symlink is a fast symlink > +**/ > +BOOLEAN > +Ext4SymlinkIsFastSymlink ( > + IN CONST EXT4_FILE *File > + ) > +{ > + // > + // Detection logic of the fast-symlink splits into two behaviors - old a= nd new. > + // The old behavior is based on comparing the extended attribute blocks= > + // with the inode's i_blocks, and if it's zero we know the inode isn't s= toring > + // the link in filesystem blocks, so we look to the inode->i_data. > + // The new behavior is apparently needed only with the large EA inode f= eature. > + // In this case we check that inode size less than maximum fast symlink= size. > + // So, we revert to the old behavior if the large EA inode feature is n= ot set. > + // > + UINT32 FileAcl; > + UINT32 ExtAttrBlocks; > + > + if ((File->Inode->i_flags & EXT4_EA_INODE_FL) =3D=3D 0) { > + FileAcl =3D File->Inode->i_file_acl; > + if (EXT4_IS_64_BIT (File->Partition)) { > + FileAcl |=3D LShiftU64 (File->Inode->i_osd2.data_linux.l_i_file_acl= _high, 32); *If* you happen to do a new revision anyway, you could drop the shift (with a= comment!) if you want, because we don=E2=80=99t care about the actual value= , just whether any one bit is set. Don=E2=80=99t bother if there won=E2=80=99= t be a new revision anyway, though. :) > + } > + > + ExtAttrBlocks =3D FileAcl !=3D 0 ? (File->Partition->BlockSize >> 9) := 0; > + > + return File->Inode->i_blocks =3D=3D ExtAttrBlocks; > + } > + > + return EXT4_INODE_SIZE (File->Inode) <=3D EXT4_FAST_SYMLINK_MAX_SIZE; > +} > + > /** > Checks if a file is a regular file. > @param[in] File Pointer to the opened file. > --=20 > 2.37.1 >=20