[FREELDR] ArcGetFileInformation(): Set Information->FileName, Length, and Attributes for filesystems (#8420)

CORE-9023

Add support for all the supported filesystems: FAT/FATX, NTFS,
ISO, EXT, BTRFS, as well as for files loaded via PXE.

arc.h:
- Add `FILEATTRIBUTES` enumeration;
- Remove non-existing `CreateReadOnly` and `SupersedeReadOnly`
  `OPENMODE` values; add missing `CreateReadWrite`.
This commit is contained in:
Hermès Bélusca-Maïto
2025-10-04 15:58:37 +02:00
parent eec9ca1305
commit c7d4040767
12 changed files with 314 additions and 88 deletions

View File

@@ -71,6 +71,7 @@ typedef u64 __u64;
#define BTRFS_DEV_ITEMS_OBJECTID 1ULL
#define BTRFS_FT_UNKNOWN 0
#define BTRFS_FT_REG_FILE 1
#define BTRFS_FT_DIR 2
#define BTRFS_FT_SYMLINK 7
@@ -416,6 +417,9 @@ typedef struct {
u64 position;
struct btrfs_inode_item inode;
PBTRFS_INFO Volume;
} btrfs_file_info, * pbtrfs_file_info;
ULONG FileNameLength;
UCHAR Attributes;
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)];
} btrfs_file_info, *pbtrfs_file_info;
const DEVVTBL* BtrFsMount(ULONG DeviceId);

View File

@@ -220,11 +220,14 @@ typedef struct _EXT_VOLUME_INFO *PEXT_VOLUME_INFO;
typedef struct _EXT_FILE_INFO
{
ULONGLONG FileSize; // File size
ULONGLONG FilePointer; // File pointer
PULONG FileBlockList; // File block list
EXT_INODE Inode; // File's inode
PEXT_VOLUME_INFO Volume;
PULONG FileBlockList; // File block list
EXT_INODE Inode; // File inode
ULONGLONG FileSize; // File size
ULONGLONG FilePointer; // File pointer
ULONG FileNameLength;
UCHAR Attributes;
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)];
} EXT_FILE_INFO, *PEXT_FILE_INFO;
const DEVVTBL* ExtMount(ULONG DeviceId);

View File

@@ -143,33 +143,35 @@ typedef struct
} FATX_DIRENTRY, * PFATX_DIRENTRY;
#include <poppack.h>
typedef struct _FAT_VOLUME_INFO *PFAT_VOLUME_INFO;
#define FAT_ATTR_NORMAL 0x00
#define FAT_ATTR_READONLY 0x01
#define FAT_ATTR_HIDDEN 0x02
#define FAT_ATTR_SYSTEM 0x04
#define FAT_ATTR_VOLUMENAME 0x08
#define FAT_ATTR_DIRECTORY 0x10
#define FAT_ATTR_ARCHIVE 0x20
#define FAT_ATTR_LONG_NAME (FAT_ATTR_READONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLUMENAME)
typedef struct
{
PFAT_VOLUME_INFO Volume;
ULONG FileSize; /* File size */
ULONG FilePointer; /* File pointer */
ULONG CurrentCluster; /* The cluster for file pointer */
ULONG StartCluster; /* The first cluster for file */
UCHAR Attributes; /* File attributes */
} FAT_FILE_INFO, * PFAT_FILE_INFO;
#define ATTR_NORMAL 0x00
#define ATTR_READONLY 0x01
#define ATTR_HIDDEN 0x02
#define ATTR_SYSTEM 0x04
#define ATTR_VOLUMENAME 0x08
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
#define ATTR_LONG_NAME (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMENAME)
#define FAT12 1
#define FAT16 2
#define FAT32 3
#define FATX16 4
#define FATX32 5
#define FAT12 1
#define FAT16 2
#define FAT32 3
#define FATX16 4
#define FATX32 5
#define ISFATX(FT) ((FT) == FATX16 || (FT) == FATX32)
typedef struct _FAT_VOLUME_INFO *PFAT_VOLUME_INFO;
typedef struct _FAT_FILE_INFO
{
PFAT_VOLUME_INFO Volume;
ULONG FileSize; // File size
ULONG FilePointer; // File pointer
ULONG CurrentCluster; // Cluster for file pointer
ULONG StartCluster; // File first cluster
ULONG FileNameLength;
UCHAR Attributes;
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)];
} FAT_FILE_INFO, *PFAT_FILE_INFO;
const DEVVTBL* FatMount(ULONG DeviceId);

View File

@@ -89,13 +89,21 @@ typedef struct _PVD
} PVD, *PPVD;
#include <poppack.h>
#define ISO_ATTR_HIDDEN 0x01 // CD_ATTRIBUTE_HIDDEN
#define ISO_ATTR_DIRECTORY 0x02 // CD_ATTRIBUTE_DIRECTORY
#define ISO_ATTR_ASSOC 0x04 // CD_ATTRIBUTE_ASSOC
#define ISO_ATTR_MULTI 0x80 // CD_ATTRIBUTE_MULTI
typedef struct _ISO_FILE_INFO
{
// PISO_VOLUME_INFO Volume;
ULONG FileStart; // File start sector
ULONG FileSize; // File size
ULONG FilePointer; // File pointer
BOOLEAN Directory;
ULONG DriveNumber;
ULONG FileNameLength;
UCHAR Attributes;
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)];
} ISO_FILE_INFO, *PISO_FILE_INFO;
const DEVVTBL* IsoMount(ULONG DeviceId);

View File

@@ -65,6 +65,14 @@
#define NTFS_FILE_NAME_DOS 2
#define NTFS_FILE_NAME_WIN32_AND_DOS 3
#define NTFS_FILE_ATTR_NORMAL 0x00
#define NTFS_FILE_ATTR_READONLY 0x01
#define NTFS_FILE_ATTR_HIDDEN 0x02
#define NTFS_FILE_ATTR_SYSTEM 0x04
// 0x08, 0x10 are unused.
#define NTFS_FILE_ATTR_ARCHIVE 0x20
#define NTFS_FILE_ATTR_DIRECTORY 0x10000000
#define NTFS_MFT_MASK 0x0000FFFFFFFFFFFFULL
#include <pshpack1.h>
@@ -240,13 +248,14 @@ typedef struct
typedef struct _NTFS_VOLUME_INFO *PNTFS_VOLUME_INFO;
#include <pshpack1.h>
typedef struct
typedef struct _NTFS_FILE_HANDLE
{
PNTFS_ATTR_CONTEXT DataContext;
ULONGLONG Offset;
PNTFS_VOLUME_INFO Volume;
PNTFS_VOLUME_INFO Volume;
PNTFS_ATTR_CONTEXT DataContext;
ULONGLONG Offset;
ULONG FileNameLength;
UCHAR Attributes;
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)];
} NTFS_FILE_HANDLE, *PNTFS_FILE_HANDLE;
#include <poppack.h>
const DEVVTBL* NtfsMount(ULONG DeviceId);

View File

@@ -8,6 +8,7 @@
/* Some code was taken from u-boot, https://github.com/u-boot/u-boot/tree/master/fs/btrfs */
#include <freeldr.h>
#include "fs/stat.h"
#include <debug.h>
DBG_DEFAULT_CHANNEL(FILESYSTEM);
@@ -1051,15 +1052,16 @@ static inline const char *skip_current_directories(const char *cur)
static u64 btrfs_lookup_path(PBTRFS_INFO BtrFsInfo,
const struct btrfs_root_item *root, u64 inr, const char *path,
u8 *type_p, struct btrfs_inode_item *inode_item_p, int symlink_limit)
u8 *type_p, struct btrfs_inode_item *inode_item_p, int symlink_limit,
_Out_opt_ PCHAR filename_buffer, _Inout_ PULONG filename_length)
{
struct btrfs_dir_item item;
struct btrfs_inode_item inode_item;
u8 type = BTRFS_FT_DIR;
int len, have_inode = 0;
const char *cur = path;
struct btrfs_disk_key key;
char *link_target = NULL;
const char *last_elem;
int last_elem_len;
if (*cur == '/' || *cur == '\\')
{
@@ -1078,6 +1080,10 @@ static u64 btrfs_lookup_path(PBTRFS_INFO BtrFsInfo,
return INVALID_INODE;
}
/* Save the pointer/length of the current path element */
last_elem = cur;
last_elem_len = len;
if (len == 1 && cur[0] == '.')
break;
@@ -1109,6 +1115,8 @@ static u64 btrfs_lookup_path(PBTRFS_INFO BtrFsInfo,
if (type == BTRFS_FT_SYMLINK && symlink_limit >= 0)
{
char *link_target = NULL;
if (!symlink_limit)
{
TRACE("%s: Too much symlinks!\n");
@@ -1119,7 +1127,9 @@ static u64 btrfs_lookup_path(PBTRFS_INFO BtrFsInfo,
if (!btrfs_readlink(BtrFsInfo, root, item.location.objectid, &link_target))
return INVALID_INODE;
inr = btrfs_lookup_path(BtrFsInfo, root, inr, link_target, &type, &inode_item, symlink_limit - 1);
inr = btrfs_lookup_path(BtrFsInfo, root, inr, link_target,
&type, &inode_item, symlink_limit - 1,
NULL, NULL);
FrLdrTempFree(link_target, TAG_BTRFS_LINK);
@@ -1144,6 +1154,7 @@ static u64 btrfs_lookup_path(PBTRFS_INFO BtrFsInfo,
{
if (!have_inode)
{
struct btrfs_disk_key key;
key.objectid = inr;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
@@ -1155,6 +1166,13 @@ static u64 btrfs_lookup_path(PBTRFS_INFO BtrFsInfo,
*inode_item_p = inode_item;
}
if (filename_buffer)
{
/* Copy the file name, perhaps truncated */
*filename_length = min(*filename_length, last_elem_len);
RtlCopyMemory(filename_buffer, last_elem, *filename_length);
}
return inr;
}
@@ -1176,6 +1194,14 @@ ARC_STATUS BtrFsGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Information->EndingAddress.QuadPart = phandle->inode.size;
Information->CurrentAddress.QuadPart = phandle->position;
/* Set the ARC file attributes */
Information->Attributes = phandle->Attributes;
/* Copy the file name, perhaps truncated, and NUL-terminated */
Information->FileNameLength = min(phandle->FileNameLength, sizeof(Information->FileName) - 1);
RtlCopyMemory(Information->FileName, phandle->FileName, Information->FileNameLength);
Information->FileName[Information->FileNameLength] = ANSI_NULL;
TRACE("BtrFsGetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
@@ -1186,6 +1212,7 @@ ARC_STATUS BtrFsOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
{
PBTRFS_INFO BtrFsInfo;
ULONG DeviceId;
ULONG FileNameLength;
u64 inr;
u8 type;
@@ -1202,22 +1229,43 @@ ARC_STATUS BtrFsOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
DeviceId = FsGetDeviceId(*FileId);
BtrFsInfo = BtrFsVolumes[DeviceId];
temp_file_info.FileNameLength = 0;
temp_file_info.FileName[0] = ANSI_NULL;
FileNameLength = sizeof(temp_file_info.FileName) - 1;
inr = btrfs_lookup_path(BtrFsInfo, &BtrFsInfo->FsRoot,
BtrFsInfo->FsRoot.root_dirid,
Path, &type, &temp_file_info.inode, 40);
Path, &type, &temp_file_info.inode, 40,
temp_file_info.FileName, &FileNameLength);
if (inr == INVALID_INODE)
{
TRACE("Cannot lookup file %s\n", Path);
return ENOENT;
}
if (type != BTRFS_FT_REG_FILE)
{
TRACE("Not a regular file: %s\n", Path);
return EISDIR;
}
temp_file_info.FileNameLength = FileNameLength;
/* Map the attributes to ARC file attributes. NOTE: We don't look
* at the "user.DOSATTRIB" (EA_DOSATTRIB) WinBtrfs-compatible XATTR. */
temp_file_info.Attributes = 0;
if (!(temp_file_info.inode.mode & (_S_IWUSR | _S_IWGRP | _S_IWOTH)))
temp_file_info.Attributes |= ReadOnlyFile;
if (_S_ISDIR(temp_file_info.inode.mode))
temp_file_info.Attributes |= DirectoryFile;
/* Set hidden attribute for all entries starting with '.' */
if ((temp_file_info.FileNameLength >= 2 && temp_file_info.FileName[0] == '.') &&
((temp_file_info.FileNameLength == 2 && temp_file_info.FileName[1] != '.') ||
temp_file_info.FileNameLength >= 3))
{
temp_file_info.Attributes |= HiddenFile;
}
TRACE("found inode inr=%llu size=%llu\n", inr, temp_file_info.inode.size);
temp_file_info.inr = inr;

View File

@@ -111,7 +111,7 @@ PEXT_FILE_INFO ExtOpenFile(PEXT_VOLUME_INFO Volume, PCSTR FileName)
PEXT_FILE_INFO FileHandle;
CHAR SymLinkPath[EXT_DIR_ENTRY_MAX_NAME_LENGTH];
CHAR FullPath[EXT_DIR_ENTRY_MAX_NAME_LENGTH * 2];
ULONG_PTR Index;
SIZE_T Index;
TRACE("ExtOpenFile() FileName = \"%s\"\n", FileName);
@@ -209,8 +209,8 @@ PEXT_FILE_INFO ExtOpenFile(PEXT_VOLUME_INFO Volume, PCSTR FileName)
*/
BOOLEAN ExtLookupFile(PEXT_VOLUME_INFO Volume, PCSTR FileName, PEXT_FILE_INFO ExtFileInfo)
{
UINT32 i;
ULONG NumberOfPathParts;
ULONG i;
CHAR PathPart[261];
PVOID DirectoryBuffer;
ULONG DirectoryInode = EXT_ROOT_INODE;
@@ -302,18 +302,41 @@ BOOLEAN ExtLookupFile(PEXT_VOLUME_INFO Volume, PCSTR FileName, PEXT_FILE_INFO Ex
ExtFileInfo->FilePointer = 0;
ExtFileInfo->FileSize = ExtGetInodeFileSize(&InodeData);
RtlCopyMemory(&ExtFileInfo->Inode, &InodeData, sizeof(EXT_INODE));
RtlCopyMemory(&ExtFileInfo->Inode, &InodeData, sizeof(InodeData));
/* Map the attributes to ARC file attributes */
ExtFileInfo->Attributes = 0;
if (!(InodeData.Mode & (_S_IWUSR | _S_IWGRP | _S_IWOTH)))
ExtFileInfo->Attributes |= ReadOnlyFile;
if (_S_ISDIR(InodeData.Mode))
ExtFileInfo->Attributes |= DirectoryFile;
/* Set hidden attribute for all entries starting with '.' */
if ((DirectoryEntry.NameLen >= 2 && DirectoryEntry.Name[0] == '.') &&
((DirectoryEntry.NameLen == 2 && DirectoryEntry.Name[1] != '.') ||
DirectoryEntry.NameLen >= 3))
{
ExtFileInfo->Attributes |= HiddenFile;
}
/* Copy the file name, perhaps truncated */
ExtFileInfo->FileNameLength = DirectoryEntry.NameLen; // (ULONG)strlen(PathPart);
ExtFileInfo->FileNameLength = min(ExtFileInfo->FileNameLength, sizeof(ExtFileInfo->FileName) - 1);
RtlCopyMemory(ExtFileInfo->FileName, DirectoryEntry.Name /*PathPart*/, ExtFileInfo->FileNameLength);
return TRUE;
}
BOOLEAN ExtSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT_DIR_ENTRY DirectoryEntry)
{
ULONG CurrentOffset = 0;
PEXT_DIR_ENTRY CurrentDirectoryEntry;
PEXT_DIR_ENTRY CurrentDirectoryEntry;
ULONG CurrentOffset = 0;
SIZE_T FileNameLen;
TRACE("ExtSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = \"%s\"\n", DirectoryBuffer, DirectorySize, FileName);
FileNameLen = strlen(FileName);
while (CurrentOffset < DirectorySize)
{
CurrentDirectoryEntry = (PEXT_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
@@ -342,11 +365,10 @@ BOOLEAN ExtSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySi
}
TRACE("\"\n\n");
if (strlen(FileName) == CurrentDirectoryEntry->NameLen &&
!_strnicmp(FileName, CurrentDirectoryEntry->Name, CurrentDirectoryEntry->NameLen))
if ((FileNameLen == CurrentDirectoryEntry->NameLen) &&
(_strnicmp(FileName, CurrentDirectoryEntry->Name, FileNameLen) == 0))
{
RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT_DIR_ENTRY));
return TRUE;
}
@@ -1285,6 +1307,14 @@ ARC_STATUS ExtGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
Information->EndingAddress.QuadPart = FileHandle->FileSize;
Information->CurrentAddress.QuadPart = FileHandle->FilePointer;
/* Set the ARC file attributes */
Information->Attributes = FileHandle->Attributes;
/* Copy the file name, perhaps truncated, and NUL-terminated */
Information->FileNameLength = min(FileHandle->FileNameLength, sizeof(Information->FileName) - 1);
RtlCopyMemory(Information->FileName, FileHandle->FileName, Information->FileNameLength);
Information->FileName[Information->FileNameLength] = ANSI_NULL;
TRACE("ExtGetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);

View File

@@ -14,7 +14,6 @@ DBG_DEFAULT_CHANNEL(FILESYSTEM);
ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONGLONG PartitionSectorCount);
PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG* EntryCountPointer, BOOLEAN RootDirectory);
BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG EntryCount, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer);
ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer);
void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry);
static BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer);
@@ -503,7 +502,7 @@ PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, U
return DirectoryBuffer->Data;
}
BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
static BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
{
ULONG EntryCount;
ULONG CurrentEntry;
@@ -557,7 +556,7 @@ BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID Directory
// Check if this is a LFN entry
// If so it needs special handling
//
if (DirEntry->Attr == ATTR_LONG_NAME)
if (DirEntry->Attr == FAT_ATTR_LONG_NAME)
{
//
// Check to see if this is a deleted LFN entry, if so continue
@@ -640,7 +639,7 @@ BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID Directory
// Check for the volume label attribute
// and skip over this entry if found
//
if (DirEntry->Attr & ATTR_VOLUMENAME)
if (DirEntry->Attr & FAT_ATTR_VOLUMENAME)
{
RtlZeroMemory(ShortNameBuffer, 13 * sizeof(UCHAR));
RtlZeroMemory(LfnNameBuffer, 261 * sizeof(UCHAR));
@@ -667,8 +666,7 @@ BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID Directory
//
// See if the file name matches either the short or long name
//
if (((strlen(FileName) == strlen(LfnNameBuffer)) && (_stricmp(FileName, LfnNameBuffer) == 0)) ||
((strlen(FileName) == strlen(ShortNameBuffer)) && (_stricmp(FileName, ShortNameBuffer) == 0)))
if ((_stricmp(FileName, LfnNameBuffer) == 0) || (_stricmp(FileName, ShortNameBuffer) == 0))
{
//
// We found the entry, now fill in the FAT_FILE_INFO struct
@@ -681,7 +679,9 @@ BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID Directory
FatFileInfoPointer->StartCluster = StartCluster;
TRACE("MSDOS Directory Entry:\n");
TRACE("FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n", DirEntry->FileName[0], DirEntry->FileName[1], DirEntry->FileName[2], DirEntry->FileName[3], DirEntry->FileName[4], DirEntry->FileName[5], DirEntry->FileName[6], DirEntry->FileName[7], DirEntry->FileName[8], DirEntry->FileName[9], DirEntry->FileName[10]);
TRACE("FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n",
DirEntry->FileName[0], DirEntry->FileName[1], DirEntry->FileName[2], DirEntry->FileName[3], DirEntry->FileName[4],
DirEntry->FileName[5], DirEntry->FileName[6], DirEntry->FileName[7], DirEntry->FileName[8], DirEntry->FileName[9], DirEntry->FileName[10]);
TRACE("Attr = 0x%x\n", DirEntry->Attr);
TRACE("ReservedNT = 0x%x\n", DirEntry->ReservedNT);
TRACE("TimeInTenths = %d\n", DirEntry->TimeInTenths);
@@ -734,8 +734,8 @@ static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID D
{
continue;
}
if (FileNameLen == DirEntry->FileNameSize &&
0 == _strnicmp(FileName, DirEntry->FileName, FileNameLen))
if ((FileNameLen == DirEntry->FileNameSize) &&
(_strnicmp(FileName, DirEntry->FileName, FileNameLen) == 0))
{
/*
* We found the entry, now fill in the FAT_FILE_INFO struct
@@ -773,8 +773,8 @@ static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID D
*/
ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer)
{
UINT32 i;
ULONG NumberOfPathParts;
ULONG i;
CHAR PathPart[261];
PVOID DirectoryBuffer;
ULONG DirectoryStartCluster = 0;
@@ -788,6 +788,8 @@ ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO
/* Skip leading path separator, if any */
if (*FileName == '\\' || *FileName == '/')
++FileName;
PathPart[0] = ANSI_NULL;
//
// Figure out how many sub-directories we are nested in
//
@@ -847,7 +849,7 @@ ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO
//
// Check if current entry is a directory
//
if (!(FatFileInfo.Attributes & ATTR_DIRECTORY))
if (!(FatFileInfo.Attributes & FAT_ATTR_DIRECTORY))
{
return ENOTDIR;
}
@@ -855,7 +857,25 @@ ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO
}
}
RtlCopyMemory(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO));
RtlCopyMemory(FatFileInfoPointer, &FatFileInfo, sizeof(FatFileInfo));
/* Re-map the attributes to ARC file attributes */
FatFileInfoPointer->Attributes = 0;
if (FatFileInfo.Attributes & FAT_ATTR_READONLY)
FatFileInfoPointer->Attributes |= ReadOnlyFile;
if (FatFileInfo.Attributes & FAT_ATTR_HIDDEN)
FatFileInfoPointer->Attributes |= HiddenFile;
if (FatFileInfo.Attributes & FAT_ATTR_SYSTEM)
FatFileInfoPointer->Attributes |= SystemFile;
if (FatFileInfo.Attributes & FAT_ATTR_ARCHIVE)
FatFileInfoPointer->Attributes |= ArchiveFile;
if (FatFileInfo.Attributes & FAT_ATTR_DIRECTORY)
FatFileInfoPointer->Attributes |= DirectoryFile;
/* Copy the file name, perhaps truncated */
FatFileInfoPointer->FileNameLength = (ULONG)strlen(PathPart);
FatFileInfoPointer->FileNameLength = min(FatFileInfoPointer->FileNameLength, sizeof(FatFileInfoPointer->FileName) - 1);
RtlCopyMemory(FatFileInfoPointer->FileName, PathPart, FatFileInfoPointer->FileNameLength);
return ESUCCESS;
}
@@ -1411,6 +1431,14 @@ ARC_STATUS FatGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
Information->EndingAddress.LowPart = FileHandle->FileSize;
Information->CurrentAddress.LowPart = FileHandle->FilePointer;
/* Set the ARC file attributes */
Information->Attributes = FileHandle->Attributes;
/* Copy the file name, perhaps truncated, and NUL-terminated */
Information->FileNameLength = min(FileHandle->FileNameLength, sizeof(Information->FileName) - 1);
RtlCopyMemory(Information->FileName, FileHandle->FileName, Information->FileNameLength);
Information->FileName[Information->FileNameLength] = ANSI_NULL;
TRACE("FatGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
@@ -1442,7 +1470,7 @@ ARC_STATUS FatOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
//
// Check if caller opened what he expected (dir vs file)
//
IsDirectory = (TempFileInfo.Attributes & ATTR_DIRECTORY) != 0;
IsDirectory = !!(TempFileInfo.Attributes & DirectoryFile);
if (IsDirectory && OpenMode != OpenDirectory)
return EISDIR;
else if (!IsDirectory && OpenMode != OpenReadOnly)

View File

@@ -101,16 +101,14 @@ static BOOLEAN IsoSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG Dire
Name[i] = ANSI_NULL;
TRACE("Name '%s'\n", Name);
if (strlen(FileName) == strlen(Name) && _stricmp(FileName, Name) == 0)
if (_stricmp(FileName, Name) == 0)
{
IsoFileInfoPointer->FileStart = Record->ExtentLocationL;
IsoFileInfoPointer->FileSize = Record->DataLengthL;
IsoFileInfoPointer->FilePointer = 0;
IsoFileInfoPointer->Directory = !!(Record->FileFlags & 0x02);
IsoFileInfoPointer->Attributes = Record->FileFlags;
return TRUE;
}
}
}
@@ -187,6 +185,7 @@ static ARC_STATUS IsoLookupFile(PCSTR FileName, ULONG DeviceId, PISO_FILE_INFO I
CHAR* PathPart;
ARC_STATUS Status;
BOOLEAN DoFullLookup;
UCHAR FileAttributes;
TRACE("IsoLookupFile() FileName = %s\n", FileName);
@@ -226,6 +225,7 @@ static ARC_STATUS IsoLookupFile(PCSTR FileName, ULONG DeviceId, PISO_FILE_INFO I
/* Skip leading path separator, if any */
if (*FileName == '\\' || *FileName == '/')
++FileName;
PathPart[0] = ANSI_NULL;
/* Figure out how many sub-directories we are nested in */
NumberOfPathParts = FsGetNumPathParts(FileName);
@@ -298,6 +298,19 @@ static ARC_STATUS IsoLookupFile(PCSTR FileName, ULONG DeviceId, PISO_FILE_INFO I
}
}
/* Re-map the attributes to ARC file attributes */
FileAttributes = IsoFileInfo->Attributes;
IsoFileInfo->Attributes = ReadOnlyFile;
if (FileAttributes & ISO_ATTR_HIDDEN)
IsoFileInfo->Attributes |= HiddenFile;
if (FileAttributes & ISO_ATTR_DIRECTORY)
IsoFileInfo->Attributes |= DirectoryFile;
/* Copy the file name, perhaps truncated */
IsoFileInfo->FileNameLength = (ULONG)strlen(PathPart);
IsoFileInfo->FileNameLength = min(IsoFileInfo->FileNameLength, sizeof(IsoFileInfo->FileName) - 1);
RtlCopyMemory(IsoFileInfo->FileName, PathPart, IsoFileInfo->FileNameLength);
return ESUCCESS;
}
@@ -318,6 +331,14 @@ ARC_STATUS IsoGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
Information->EndingAddress.LowPart = FileHandle->FileSize;
Information->CurrentAddress.LowPart = FileHandle->FilePointer;
/* Set the ARC file attributes */
Information->Attributes = FileHandle->Attributes;
/* Copy the file name, perhaps truncated, and NUL-terminated */
Information->FileNameLength = min(FileHandle->FileNameLength, sizeof(Information->FileName) - 1);
RtlCopyMemory(Information->FileName, FileHandle->FileName, Information->FileNameLength);
Information->FileName[Information->FileNameLength] = ANSI_NULL;
TRACE("IsoGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);

View File

@@ -509,7 +509,11 @@ VOID NtfsPrintFile(PNTFS_INDEX_ENTRY IndexEntry)
}
#endif
static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
static BOOLEAN
NtfsCompareFileName(
_In_ PCCH FileName,
_In_ SIZE_T FileNameLen,
_In_ PNTFS_INDEX_ENTRY IndexEntry)
{
PWCHAR EntryFileName;
UCHAR EntryFileNameLength;
@@ -522,7 +526,7 @@ static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
NtfsPrintFile(IndexEntry);
#endif
if (strlen(FileName) != EntryFileNameLength)
if (FileNameLen != EntryFileNameLength)
return FALSE;
/*
@@ -540,7 +544,13 @@ static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
return TRUE;
}
static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, PCHAR FileName, ULONGLONG *OutMFTIndex)
static BOOLEAN
NtfsFindMftRecord(
_In_ PNTFS_VOLUME_INFO Volume,
_In_ ULONGLONG MFTIndex,
_In_ PCSTR FileName,
_Out_ PULONGLONG OutMFTIndex,
_Out_ PULONG FileAttributes)
{
PNTFS_MFT_RECORD MftRecord;
//ULONG Magic;
@@ -555,6 +565,9 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
PNTFS_INDEX_ENTRY IndexEntry, IndexEntryEnd;
ULONG RecordOffset;
ULONG IndexBlockSize;
SIZE_T FileNameLen;
FileNameLen = strlen(FileName);
MftRecord = FrLdrTempAlloc(Volume->MftRecordSize, TAG_NTFS_MFT);
if (MftRecord == NULL)
@@ -592,14 +605,15 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
while (IndexEntry < IndexEntryEnd &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
{
if (NtfsCompareFileName(FileName, IndexEntry))
if (NtfsCompareFileName(FileName, FileNameLen, IndexEntry))
{
*OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
*FileAttributes = IndexEntry->FileName.FileAttributes;
FrLdrTempFree(IndexRecord, TAG_NTFS_INDEX_REC);
FrLdrTempFree(MftRecord, TAG_NTFS_MFT);
return TRUE;
}
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
}
if (IndexRoot->IndexHeader.Flags & NTFS_LARGE_INDEX)
@@ -670,19 +684,20 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
/* FIXME */
IndexEntry = (PNTFS_INDEX_ENTRY)(IndexRecord + 0x18 + *(USHORT *)(IndexRecord + 0x18));
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexBlockSize);
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexBlockSize);
while (IndexEntry < IndexEntryEnd &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
{
if (NtfsCompareFileName(FileName, IndexEntry))
if (NtfsCompareFileName(FileName, FileNameLen, IndexEntry))
{
TRACE("File found\n");
*OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
*FileAttributes = IndexEntry->FileName.FileAttributes;
NtfsReleaseAttributeContext(IndexAllocationCtx);
FrLdrTempFree(BitmapData, TAG_NTFS_BITMAP);
FrLdrTempFree(IndexRecord, TAG_NTFS_INDEX_REC);
FrLdrTempFree(MftRecord, TAG_NTFS_MFT);
NtfsReleaseAttributeContext(IndexAllocationCtx);
return TRUE;
}
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
@@ -706,12 +721,13 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
return FALSE;
}
static BOOLEAN NtfsLookupFile(PNTFS_VOLUME_INFO Volume, PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_ATTR_CONTEXT *DataContext)
static BOOLEAN NtfsLookupFile(PNTFS_VOLUME_INFO Volume, PCSTR FileName, PNTFS_MFT_RECORD MftRecord, PNTFS_FILE_HANDLE FileHandle)
{
ULONG NumberOfPathParts;
CHAR PathPart[261];
ULONG i;
ULONGLONG CurrentMFTIndex;
UCHAR i;
ULONG FileAttributes;
CHAR PathPart[261];
TRACE("NtfsLookupFile() FileName = %s\n", FileName);
@@ -720,7 +736,9 @@ static BOOLEAN NtfsLookupFile(PNTFS_VOLUME_INFO Volume, PCSTR FileName, PNTFS_MF
/* Skip leading path separator, if any */
if (*FileName == '\\' || *FileName == '/')
++FileName;
PathPart[0] = ANSI_NULL;
/* Figure out how many sub-directories we are nested in and loop once for each part */
NumberOfPathParts = FsGetNumPathParts(FileName);
for (i = 0; i < NumberOfPathParts; i++)
{
@@ -731,7 +749,7 @@ static BOOLEAN NtfsLookupFile(PNTFS_VOLUME_INFO Volume, PCSTR FileName, PNTFS_MF
FileName++;
TRACE("- Lookup: %s\n", PathPart);
if (!NtfsFindMftRecord(Volume, CurrentMFTIndex, PathPart, &CurrentMFTIndex))
if (!NtfsFindMftRecord(Volume, CurrentMFTIndex, PathPart, &CurrentMFTIndex, &FileAttributes))
{
TRACE("- Failed\n");
return FALSE;
@@ -745,13 +763,31 @@ static BOOLEAN NtfsLookupFile(PNTFS_VOLUME_INFO Volume, PCSTR FileName, PNTFS_MF
return FALSE;
}
*DataContext = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_DATA, L"");
if (*DataContext == NULL)
FileHandle->DataContext = NtfsFindAttribute(Volume, MftRecord, NTFS_ATTR_TYPE_DATA, L"");
if (FileHandle->DataContext == NULL)
{
TRACE("NtfsLookupFile: Can't find data attribute\n");
return FALSE;
}
/* Map the attributes to ARC file attributes */
FileHandle->Attributes = 0;
if (FileAttributes & NTFS_FILE_ATTR_READONLY)
FileHandle->Attributes |= ReadOnlyFile;
if (FileAttributes & NTFS_FILE_ATTR_HIDDEN)
FileHandle->Attributes |= HiddenFile;
if (FileAttributes & NTFS_FILE_ATTR_SYSTEM)
FileHandle->Attributes |= SystemFile;
if (FileAttributes & NTFS_FILE_ATTR_ARCHIVE)
FileHandle->Attributes |= ArchiveFile;
if (FileAttributes & NTFS_FILE_ATTR_DIRECTORY)
FileHandle->Attributes |= DirectoryFile;
/* Copy the file name, perhaps truncated */
FileHandle->FileNameLength = (ULONG)strlen(PathPart);
FileHandle->FileNameLength = min(FileHandle->FileNameLength, sizeof(FileHandle->FileName) - 1);
RtlCopyMemory(FileHandle->FileName, PathPart, FileHandle->FileNameLength);
return TRUE;
}
@@ -773,6 +809,14 @@ ARC_STATUS NtfsGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
Information->EndingAddress.QuadPart = NtfsGetAttributeSize(&FileHandle->DataContext->Record);
Information->CurrentAddress.QuadPart = FileHandle->Offset;
/* Set the ARC file attributes */
Information->Attributes = FileHandle->Attributes;
/* Copy the file name, perhaps truncated, and NUL-terminated */
Information->FileNameLength = min(FileHandle->FileNameLength, sizeof(Information->FileName) - 1);
RtlCopyMemory(Information->FileName, FileHandle->FileName, Information->FileNameLength);
Information->FileName[Information->FileNameLength] = ANSI_NULL;
TRACE("NtfsGetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
@@ -816,7 +860,7 @@ ARC_STATUS NtfsOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
// Search file entry
//
MftRecord = (PNTFS_MFT_RECORD)(FileHandle + 1);
if (!NtfsLookupFile(Volume, Path, MftRecord, &FileHandle->DataContext))
if (!NtfsLookupFile(Volume, Path, MftRecord, FileHandle))
{
FrLdrTempFree(FileHandle, TAG_NTFS_FILE);
return ENOENT;

View File

@@ -131,6 +131,8 @@ static ARC_STATUS PxeClose(ULONG FileId)
static ARC_STATUS PxeGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
{
PCSTR FileName;
if (_OpenFile == NO_FILE || FileId != _OpenFile)
return EBADF;
@@ -140,6 +142,23 @@ static ARC_STATUS PxeGetFileInformation(ULONG FileId, FILEINFORMATION* Informati
Information->Type = NetworkPeripheral;
/* Set the ARC file attributes */
Information->Attributes = ReadOnlyFile;
/* Search for the last path separator. Slashes are used as separators,
* for supporting TFTP servers on POSIX systems (see PxeOpen()) */
FileName = strrchr(_OpenFileName, '/');
if (FileName)
++FileName; // Go past it.
else
FileName = _OpenFileName; // No separator: file name without directory.
/* Copy the file name, perhaps truncated, and NUL-terminated */
Information->FileNameLength = (ULONG)strlen(FileName);
Information->FileNameLength = min(Information->FileNameLength, sizeof(Information->FileName) - 1);
RtlCopyMemory(Information->FileName, FileName, Information->FileNameLength);
Information->FileName[Information->FileNameLength] = ANSI_NULL;
TRACE("PxeGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
@@ -165,7 +184,8 @@ static ARC_STATUS PxeOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
++Path;
/* Retrieve the path length without NULL terminator */
PathLen = min(strlen(Path), sizeof(_OpenFileName) - 1);
PathLen = strlen(Path);
PathLen = min(PathLen, sizeof(_OpenFileName) - 1);
/* Lowercase the path and always use slashes as separators,
* for supporting TFTP servers on POSIX systems */

View File

@@ -66,14 +66,23 @@ typedef enum _OPENMODE
OpenWriteOnly,
OpenReadWrite,
CreateWriteOnly,
CreateReadOnly,
CreateReadWrite,
SupersedeWriteOnly,
SupersedeReadOnly,
SupersedeReadWrite,
OpenDirectory,
CreateDirectory,
} OPENMODE;
typedef enum _FILEATTRIBUTES
{
ReadOnlyFile = 0x01,
HiddenFile = 0x02,
SystemFile = 0x04,
ArchiveFile = 0x08,
DirectoryFile = 0x10,
DeleteFile = 0x20
} FILEATTRIBUTES;
typedef enum _IDENTIFIER_FLAG
{
Failed = 0x01,
@@ -225,7 +234,7 @@ typedef struct _FILEINFORMATION
CONFIGURATION_TYPE Type;
ULONG FileNameLength;
UCHAR Attributes;
CHAR Filename[32];
CHAR FileName[32];
} FILEINFORMATION;
typedef