*Update = TRUE;\r
*Size = NewInfo->FileSize;\r
}\r
+\r
+/**\r
+ Given an EFI_FILE_INFO object received in an EFI_FILE_PROTOCOL.SetInfo()\r
+ call, determine whether updating the last access time and/or the last\r
+ modification time of the file is necessary, relative to an EFI_FILE_INFO\r
+ object describing the current state of the file.\r
+\r
+ @param[in] Info The EFI_FILE_INFO describing the current state of\r
+ the file. The caller is responsible for populating\r
+ Info on input with VirtioFsFuseAttrToEfiFileInfo(),\r
+ from the current FUSE attributes of the file. The\r
+ Info->Size and Info->FileName members are ignored.\r
+\r
+ @param[in] NewInfo The EFI_FILE_INFO object received in the\r
+ EFI_FILE_PROTOCOL.SetInfo() call.\r
+\r
+ @param[out] UpdateAtime Set to TRUE on output if the last access time needs\r
+ to be updated. Set to FALSE otherwise.\r
+\r
+ @param[out] UpdateMtime Set to TRUE on output if the last modification time\r
+ needs to be updated. Set to FALSE otherwise.\r
+\r
+ @param[out] Atime If UpdateAtime is set to TRUE, then Atime provides\r
+ the last access timestamp to set (as seconds since\r
+ the Epoch). Otherwise, Atime is not written to.\r
+\r
+ @param[out] Mtime If UpdateMtime is set to TRUE, then Mtime provides\r
+ the last modification timestamp to set (as seconds\r
+ since the Epoch). Otherwise, Mtime is not written\r
+ to.\r
+\r
+ @retval EFI_SUCCESS Output parameters have been set successfully.\r
+\r
+ @retval EFI_ACCESS_DENIED NewInfo requests changing both CreateTime and\r
+ ModificationTime, but to values that differ from\r
+ each other. The Virtio Filesystem device does not\r
+ support this.\r
+**/\r
+EFI_STATUS\r
+VirtioFsGetFuseTimeUpdates (\r
+ IN EFI_FILE_INFO *Info,\r
+ IN EFI_FILE_INFO *NewInfo,\r
+ OUT BOOLEAN *UpdateAtime,\r
+ OUT BOOLEAN *UpdateMtime,\r
+ OUT UINT64 *Atime,\r
+ OUT UINT64 *Mtime\r
+ )\r
+{\r
+ EFI_TIME *Time[3];\r
+ EFI_TIME *NewTime[ARRAY_SIZE (Time)];\r
+ UINTN Idx;\r
+ STATIC CONST EFI_TIME ZeroTime = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r
+ BOOLEAN Change[ARRAY_SIZE (Time)];\r
+ UINT64 Seconds[ARRAY_SIZE (Time)];\r
+\r
+ Time[0] = &Info->CreateTime;\r
+ Time[1] = &Info->LastAccessTime;\r
+ Time[2] = &Info->ModificationTime;\r
+ NewTime[0] = &NewInfo->CreateTime;\r
+ NewTime[1] = &NewInfo->LastAccessTime;\r
+ NewTime[2] = &NewInfo->ModificationTime;\r
+\r
+ //\r
+ // Determine which timestamps differ from the current state. (A zero time\r
+ // means "don't update", per UEFI spec.) For each timestamp that's being\r
+ // changed, calculate the seconds since the Epoch.\r
+ //\r
+ for (Idx = 0; Idx < ARRAY_SIZE (Time); Idx++) {\r
+ if (CompareMem (NewTime[Idx], &ZeroTime, sizeof (EFI_TIME)) == 0 ||\r
+ CompareMem (NewTime[Idx], Time[Idx], sizeof (EFI_TIME)) == 0) {\r
+ Change[Idx] = FALSE;\r
+ } else {\r
+ Change[Idx] = TRUE;\r
+ Seconds[Idx] = EfiTimeToEpoch (NewTime[Idx]);\r
+ }\r
+ }\r
+\r
+ //\r
+ // If a change is requested for exactly one of CreateTime and\r
+ // ModificationTime, we'll change the last modification time. If changes are\r
+ // requested for both, and to the same timestamp, we'll similarly update the\r
+ // last modification time. If changes are requested for both, but to\r
+ // different timestamps, we reject the request.\r
+ //\r
+ if (Change[0] && Change[2] && Seconds[0] != Seconds[2]) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ *UpdateAtime = FALSE;\r
+ *UpdateMtime = FALSE;\r
+\r
+ if (Change[0]) {\r
+ *UpdateMtime = TRUE;\r
+ *Mtime = Seconds[0];\r
+ }\r
+ if (Change[1]) {\r
+ *UpdateAtime = TRUE;\r
+ *Atime = Seconds[1];\r
+ }\r
+ if (Change[2]) {\r
+ *UpdateMtime = TRUE;\r
+ *Mtime = Seconds[2];\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r