From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1jASVK-0002TN-AE for mharc-grub-devel@gnu.org; Sat, 07 Mar 2020 01:00:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:50044) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jASVE-0002S8-Jj for grub-devel@gnu.org; Sat, 07 Mar 2020 01:00:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jASVB-0004NE-NO for grub-devel@gnu.org; Sat, 07 Mar 2020 00:59:59 -0500 Received: from mail-qt1-x844.google.com ([2607:f8b0:4864:20::844]:46715) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1jASV9-0004J4-Jd for grub-devel@gnu.org; Sat, 07 Mar 2020 00:59:55 -0500 Received: by mail-qt1-x844.google.com with SMTP id x21so3394130qto.13 for ; Fri, 06 Mar 2020 21:59:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version; bh=i4pRr0v3ETjI3FmgwDk5mF34gYgMPyclm9iykPae4mA=; b=YHYcU+wjpr+DIsrWEzLGnXQX2xFvFlMT3GKgZ+nFzeBY8gjwS0QnnBibiAQSYo9XaR MY/dbrf36g7bBtGSP1zi/KCtBjsEWe9Q3+qpU6FY5Pz2IwCGGTQlNa0y9JjfvB2oSWWw oNfD7Swrp9OBUOAHnuvINEF78XYD0uTCgODdmoIa4dkwI2eXt3q3BvRnBoW/kSpG9RKK LoHUQNkmrnx+6yN7H/m0V1zYWlBBFb+WkfDBUern+X4dd/gLO0sDo6kR3dvzxwPbmz1G m0QEADb9kUU2woroakion0EckQC80IYTSk7IZfgRxnVtf/Gqpbk2SqEa5LcLRNA5saGr iCrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version; bh=i4pRr0v3ETjI3FmgwDk5mF34gYgMPyclm9iykPae4mA=; b=qTkgLmpcuv/ZEx9FVX2vEur3nT1sVCp5dcJEc663tH3jE8qAjDT66N9z2k79n6e9tV 5HlmYijWGQhsb7LkQ2GiGahGSldth5DohhPBGgubFjJ3agOnNaebuVJF/1wHD15a6c6h 48upbsMwJ8BicfuQqV4YOQ7BHn/+JsX/7H1UIVBEc8zlVuZCc5QtCFcaPEl5tVczNeef d2GPvzwDJoPFlvh2BNxUYGuB1hwJhRdbpINC9rh4aDVMYSfm/TSovPJXDv+ha/93UBZ2 P1T/X7Rd8iiRoICdyBR6CyxLjYgZqs3iWRs+yJiWuc59Jo02FkfrMIwitdbn5rFYpSGj 6BIg== X-Gm-Message-State: ANhLgQ1SQMNv50WTUnirKmcYIuOW/bWdcGAZS2B1IaGufzF9bw6aZYUW CwxO1PlsNhMIjgylAPujKDkFTCA6 X-Google-Smtp-Source: ADFU+vv0cu++mst+fHIRJEHeNpxy3LCqc/jnJkmUh/tNvR6+9nWZpC2UR2yla70Nx07lObyURq3mhg== X-Received: by 2002:ac8:4994:: with SMTP id f20mr6310392qtq.2.1583560794232; Fri, 06 Mar 2020 21:59:54 -0800 (PST) Received: from callisto ([2601:986:200:7341:384b:df90:fb2f:c5df]) by smtp.gmail.com with ESMTPSA id f128sm19037685qke.54.2020.03.06.21.59.53 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Mar 2020 21:59:53 -0800 (PST) From: David Michael To: grub-devel@gnu.org Subject: [PATCH v3 2/2] fat: Support file modification times Date: Sat, 07 Mar 2020 00:59:52 -0500 Message-ID: <87v9ngn1rb.fsf@gmail.com> MIME-Version: 1.0 Content-Type: text/plain X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::844 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Mar 2020 06:00:02 -0000 This allows comparing file ages on EFI system partitions. Signed-off-by: David Michael --- Changes since v2: * Added comments referencing the specs * Set errno when the timestamp is invalid I set errno rather than print to the console since it looks like most other file systems don't tend to write to the console. I also went with GRUB_ERR_OUT_OF_RANGE since that error only occurs when a time field is above the valid range, but maybe GRUB_ERR_BAD_FS belongs there. grub-core/fs/fat.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c index dc493add2..24a47e2df 100644 --- a/grub-core/fs/fat.c +++ b/grub-core/fs/fat.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifndef MODE_EXFAT #include #else @@ -730,6 +731,31 @@ grub_fat_iterate_dir_next (grub_fshelp_node_t node, return grub_errno ? : GRUB_ERR_EOF; } +/* Convert a timestamp in exFAT format to seconds since the UNIX epoch + according to sections 7.4.8 and 7.4.9 in the exFAT specification. + https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification */ +static int +grub_exfat_timestamp (grub_uint32_t field, grub_uint8_t msec, grub_int32_t *nix) { + struct grub_datetime datetime = { + .year = (field >> 25) + 1980, + .month = (field & 0x01E00000) >> 21, + .day = (field & 0x001F0000) >> 16, + .hour = (field & 0x0000F800) >> 11, + .minute = (field & 0x000007E0) >> 5, + .second = (field & 0x0000001F) * 2 + (msec >= 100 ? 1 : 0), + }; + + /* The conversion below allows seconds=60, so don't trust its validation. */ + if ((field & 0x1F) > 29) + return 0; + + /* Validate the 10-msec field even though it is rounded down to seconds. */ + if (msec > 199) + return 0; + + return grub_datetime2unixtime (&datetime, nix); +} + #else static grub_err_t @@ -857,6 +883,27 @@ grub_fat_iterate_dir_next (grub_fshelp_node_t node, return grub_errno ? : GRUB_ERR_EOF; } +/* Convert a date and time in FAT format to seconds since the UNIX epoch + according to sections 11.3.5 and 11.3.6 in ECMA-107. + https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-107.pdf */ +static int +grub_fat_timestamp (grub_uint16_t time, grub_uint16_t date, grub_int32_t *nix) { + struct grub_datetime datetime = { + .year = (date >> 9) + 1980, + .month = (date & 0x01E0) >> 5, + .day = (date & 0x001F), + .hour = (time >> 11), + .minute = (time & 0x07E0) >> 5, + .second = (time & 0x001F) * 2, + }; + + /* The conversion below allows seconds=60, so don't trust its validation. */ + if ((time & 0x1F) > 29) + return 0; + + return grub_datetime2unixtime (&datetime, nix); +} + #endif static grub_err_t lookup_file (grub_fshelp_node_t node, @@ -966,10 +1013,19 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, #ifdef MODE_EXFAT if (!ctxt.dir.have_stream) continue; + info.mtimeset = grub_exfat_timestamp (grub_le_to_cpu32 (ctxt.entry.type_specific.file.m_time), + ctxt.entry.type_specific.file.m_time_tenth, + &info.mtime); #else if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID) continue; + info.mtimeset = grub_fat_timestamp (grub_le_to_cpu16 (ctxt.dir.w_time), + grub_le_to_cpu16 (ctxt.dir.w_date), + &info.mtime); #endif + if (info.mtimeset == 0) + grub_error (GRUB_ERR_OUT_OF_RANGE, + "invalid modification timestamp for %s", path); if (hook (ctxt.filename, &info, hook_data)) break; -- 2.21.1