diff --git a/boot/freeldr/freeldr/include/fs/btrfs.h b/boot/freeldr/freeldr/include/fs/btrfs.h index 1cea4f36500..7fae5e3006f 100644 --- a/boot/freeldr/freeldr/include/fs/btrfs.h +++ b/boot/freeldr/freeldr/include/fs/btrfs.h @@ -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); diff --git a/boot/freeldr/freeldr/include/fs/ext.h b/boot/freeldr/freeldr/include/fs/ext.h index d72dabb5c30..e5eb9f51d1c 100644 --- a/boot/freeldr/freeldr/include/fs/ext.h +++ b/boot/freeldr/freeldr/include/fs/ext.h @@ -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); diff --git a/boot/freeldr/freeldr/include/fs/fat.h b/boot/freeldr/freeldr/include/fs/fat.h index 85e2998ecb8..efe164fd411 100644 --- a/boot/freeldr/freeldr/include/fs/fat.h +++ b/boot/freeldr/freeldr/include/fs/fat.h @@ -143,33 +143,35 @@ typedef struct } FATX_DIRENTRY, * PFATX_DIRENTRY; #include -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); diff --git a/boot/freeldr/freeldr/include/fs/iso.h b/boot/freeldr/freeldr/include/fs/iso.h index 0e53f7c41bc..caea4d134c3 100644 --- a/boot/freeldr/freeldr/include/fs/iso.h +++ b/boot/freeldr/freeldr/include/fs/iso.h @@ -89,13 +89,21 @@ typedef struct _PVD } PVD, *PPVD; #include +#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); diff --git a/boot/freeldr/freeldr/include/fs/ntfs.h b/boot/freeldr/freeldr/include/fs/ntfs.h index 9aad54904d7..77a5f8233b5 100644 --- a/boot/freeldr/freeldr/include/fs/ntfs.h +++ b/boot/freeldr/freeldr/include/fs/ntfs.h @@ -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 @@ -240,13 +248,14 @@ typedef struct typedef struct _NTFS_VOLUME_INFO *PNTFS_VOLUME_INFO; -#include -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 const DEVVTBL* NtfsMount(ULONG DeviceId); diff --git a/boot/freeldr/freeldr/lib/fs/btrfs.c b/boot/freeldr/freeldr/lib/fs/btrfs.c index 33cfb6e9d9f..0af831c3b8d 100644 --- a/boot/freeldr/freeldr/lib/fs/btrfs.c +++ b/boot/freeldr/freeldr/lib/fs/btrfs.c @@ -8,6 +8,7 @@ /* Some code was taken from u-boot, https://github.com/u-boot/u-boot/tree/master/fs/btrfs */ #include +#include "fs/stat.h" #include 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; diff --git a/boot/freeldr/freeldr/lib/fs/ext.c b/boot/freeldr/freeldr/lib/fs/ext.c index c0ce7fcc6cd..78b1764b4d7 100644 --- a/boot/freeldr/freeldr/lib/fs/ext.c +++ b/boot/freeldr/freeldr/lib/fs/ext.c @@ -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); diff --git a/boot/freeldr/freeldr/lib/fs/fat.c b/boot/freeldr/freeldr/lib/fs/fat.c index 5cb4a67ad8b..fab247b8438 100644 --- a/boot/freeldr/freeldr/lib/fs/fat.c +++ b/boot/freeldr/freeldr/lib/fs/fat.c @@ -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) diff --git a/boot/freeldr/freeldr/lib/fs/iso.c b/boot/freeldr/freeldr/lib/fs/iso.c index 55ea802ebd2..d903d1fe3e1 100644 --- a/boot/freeldr/freeldr/lib/fs/iso.c +++ b/boot/freeldr/freeldr/lib/fs/iso.c @@ -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); diff --git a/boot/freeldr/freeldr/lib/fs/ntfs.c b/boot/freeldr/freeldr/lib/fs/ntfs.c index 06da1d6aa4e..af78249eadb 100644 --- a/boot/freeldr/freeldr/lib/fs/ntfs.c +++ b/boot/freeldr/freeldr/lib/fs/ntfs.c @@ -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; diff --git a/boot/freeldr/freeldr/lib/fs/pxe.c b/boot/freeldr/freeldr/lib/fs/pxe.c index 05dc7518a6e..2fd2cd1e2a6 100644 --- a/boot/freeldr/freeldr/lib/fs/pxe.c +++ b/boot/freeldr/freeldr/lib/fs/pxe.c @@ -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 */ diff --git a/sdk/include/reactos/arc/arc.h b/sdk/include/reactos/arc/arc.h index 32fa97157ed..89a443e3cfb 100644 --- a/sdk/include/reactos/arc/arc.h +++ b/sdk/include/reactos/arc/arc.h @@ -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