Skip to content

Commit

Permalink
Fix GRUB 2.06 refusing to read filesystem due to zeroed out date field
Browse files Browse the repository at this point in the history
GRUB 2.06 added support for showing file modification times using `ls -l`.
The GRUB fat module now errors with GRUB_ERR_OUT_OF_RANGE if a file's
modification date + time reads as zero. This is a valid check, since the
DOS/FAT date format uses 1-based month and day values, so no valid date
can ever be encoded as `0x0000`.

I've update the firmware to return a hard-coded date for all date fields
on directory entries, and confirmed the device is readable again from a
GRUB 2.06 shell.

Fixes #11
  • Loading branch information
stecman committed Mar 12, 2022
1 parent 02ff203 commit 9660392
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 1 deletion.
11 changes: 11 additions & 0 deletions src/fat.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,15 @@ uint8_t fat_write_dir(const struct FatDirEntry *direntry, uint8_t* output)
memcpy(output, data, sizeof(struct FatDirEntry));

return sizeof(struct FatDirEntry);
}

/**
* For a good explanation of the DOS date/time format used here, see:
* https://stackoverflow.com/a/15763512
*/
uint16_t fat_date(const uint16_t year, const uint8_t month, const uint8_t day)
{
return ((year - 1980) << 9) | // Year is stored as an offset from 1980
(month << 5) |
(day);
}
7 changes: 6 additions & 1 deletion src/fat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@ uint8_t fat_write_lfn(const char* name, const struct FatDirEntry *direntry, uin
*
* Returns the number of bytes written to the output pointer (always 32)
*/
uint8_t fat_write_dir(const struct FatDirEntry *direntry, uint8_t* output);
uint8_t fat_write_dir(const struct FatDirEntry *direntry, uint8_t* output);

/**
* Return a date formatted for use in a directory entry's mdate, adate and cdate fields
*/
uint16_t fat_date(const uint16_t year, const uint8_t month, const uint8_t day);
8 changes: 8 additions & 0 deletions src/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ static struct VirtualFile _virtualFiles[] = {
*/
static void generate_dir_sector(uint8_t* output)
{
const uint16_t releaseDate = fat_date(2021, 5, 9);

for (uint8_t i = 0; i < COUNT_OF(_virtualFiles); ++i)
{
const char* longName = _virtualFiles[i].longName;
Expand All @@ -203,6 +205,12 @@ static void generate_dir_sector(uint8_t* output)
// Set sector automatically based on array index
entry->start = FILEDATA_START_CLUSTER + i;

// Set the file dates to something reasonable
// GRUB 2.06 refuses to read the filesystem if these are set to zero
entry->mdate = releaseDate;
entry->cdate = releaseDate;
entry->adate = releaseDate;

// Write long file name and actual directory entry
output += fat_write_lfn(longName, entry, output);
output += fat_write_dir(entry, output);
Expand Down

0 comments on commit 9660392

Please sign in to comment.