VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/efi/efivarstorevfs.cpp

Last change on this file was 103412, checked in by vboxsync, 3 months ago

Runtime/efivarstorevfs.cpp: Fix using the wrong time object, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.5 KB
Line 
1/* $Id: efivarstorevfs.cpp 103412 2024-02-19 07:13:29Z vboxsync $ */
2/** @file
3 * IPRT - Expose a EFI variable store as a Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2021-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_FS
42#include <iprt/efi.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/crc.h>
47#include <iprt/file.h>
48#include <iprt/err.h>
49#include <iprt/log.h>
50#include <iprt/mem.h>
51#include <iprt/string.h>
52#include <iprt/uuid.h>
53#include <iprt/utf16.h>
54#include <iprt/vfs.h>
55#include <iprt/vfslowlevel.h>
56#include <iprt/formats/efi-fv.h>
57#include <iprt/formats/efi-varstore.h>
58
59
60/*********************************************************************************************************************************
61* Defined Constants And Macros *
62*********************************************************************************************************************************/
63
64
65/*********************************************************************************************************************************
66* Structures and Typedefs *
67*********************************************************************************************************************************/
68/** Pointer to the varstore filesystem data. */
69typedef struct RTEFIVARSTORE *PRTEFIVARSTORE;
70
71
72/**
73 * EFI variable entry.
74 */
75typedef struct RTEFIVAR
76{
77 /** Pointer to the owning variable store. */
78 PRTEFIVARSTORE pVarStore;
79 /** Offset of the variable data located in the backing image - 0 if not written yet. */
80 uint64_t offVarData;
81 /** Pointer to the in memory data, NULL if not yet read. */
82 void *pvData;
83 /** Monotonic counter value. */
84 uint64_t cMonotonic;
85 /** Size of the variable data in bytes. */
86 uint32_t cbData;
87 /** Index of the assoicated public key. */
88 uint32_t idPubKey;
89 /** Attributes for the variable. */
90 uint32_t fAttr;
91 /** Flag whether the variable was deleted. */
92 bool fDeleted;
93 /** Name of the variable. */
94 char *pszName;
95 /** The raw EFI timestamp as read from the header. */
96 EFI_TIME EfiTimestamp;
97 /** The creation/update time. */
98 RTTIMESPEC Time;
99 /** The vendor UUID of the variable. */
100 RTUUID Uuid;
101} RTEFIVAR;
102/** Pointer to an EFI variable. */
103typedef RTEFIVAR *PRTEFIVAR;
104
105
106/**
107 * EFI GUID entry.
108 */
109typedef struct RTEFIGUID
110{
111 /** The UUID representation of the GUID. */
112 RTUUID Uuid;
113 /** Pointer to the array of indices into RTEFIVARSTORE::paVars. */
114 uint32_t *paidxVars;
115 /** Number of valid indices in the array. */
116 uint32_t cVars;
117 /** Maximum number of indices the array can hold. */
118 uint32_t cVarsMax;
119} RTEFIGUID;
120/** Pointer to an EFI variable. */
121typedef RTEFIGUID *PRTEFIGUID;
122
123
124/**
125 * EFI variable store filesystem volume.
126 */
127typedef struct RTEFIVARSTORE
128{
129 /** Handle to itself. */
130 RTVFS hVfsSelf;
131 /** The file, partition, or whatever backing the volume has. */
132 RTVFSFILE hVfsBacking;
133 /** The size of the backing thingy. */
134 uint64_t cbBacking;
135
136 /** RTVFSMNT_F_XXX. */
137 uint32_t fMntFlags;
138 /** RTEFIVARSTOREVFS_F_XXX (currently none defined). */
139 uint32_t fVarStoreFlags;
140
141 /** Size of the variable store (minus the header). */
142 uint64_t cbVarStore;
143 /** Start offset into the backing image where the variable data starts. */
144 uint64_t offStoreData;
145 /** Flag whether the variable store uses authenticated variables. */
146 bool fAuth;
147 /** Number of bytes occupied by existing variables. */
148 uint64_t cbVarData;
149
150 /** Pointer to the array of variables sorted by start offset. */
151 PRTEFIVAR paVars;
152 /** Number of valid variables in the array. */
153 uint32_t cVars;
154 /** Maximum number of variables the array can hold. */
155 uint32_t cVarsMax;
156
157 /** Pointer to the array of vendor GUIDS. */
158 PRTEFIGUID paGuids;
159 /** Number of valid GUIDS in the array. */
160 uint32_t cGuids;
161 /** Maximum number of GUIDS the array can hold. */
162 uint32_t cGuidsMax;
163
164} RTEFIVARSTORE;
165
166
167/**
168 * Variable store directory type.
169 */
170typedef enum RTEFIVARSTOREDIRTYPE
171{
172 /** Invalid directory type. */
173 RTEFIVARSTOREDIRTYPE_INVALID = 0,
174 /** Root directory type. */
175 RTEFIVARSTOREDIRTYPE_ROOT,
176 /** 'by-name' directory. */
177 RTEFIVARSTOREDIRTYPE_BY_NAME,
178 /** 'by-uuid' directory. */
179 RTEFIVARSTOREDIRTYPE_BY_GUID,
180 /** 'raw' directory. */
181 RTEFIVARSTOREDIRTYPE_RAW,
182 /** Specific 'by-uuid/{...}' directory. */
183 RTEFIVARSTOREDIRTYPE_GUID,
184 /** Specific 'raw/{...}' directory. */
185 RTEFIVARSTOREDIRTYPE_RAW_ENTRY,
186 /** 32bit blowup hack. */
187 RTEFIVARSTOREDIRTYPE_32BIT_HACK = 0x7fffffff
188} RTEFIVARSTOREDIRTYPE;
189
190
191/**
192 * EFI variable store directory entry.
193 */
194typedef struct RTEFIVARSTOREDIRENTRY
195{
196 /** Name of the directory if constant. */
197 const char *pszName;
198 /** Size of the name. */
199 size_t cbName;
200 /** Entry type. */
201 RTEFIVARSTOREDIRTYPE enmType;
202 /** Parent entry type. */
203 RTEFIVARSTOREDIRTYPE enmParentType;
204} RTEFIVARSTOREDIRENTRY;
205/** Pointer to a EFI variable store directory entry. */
206typedef RTEFIVARSTOREDIRENTRY *PRTEFIVARSTOREDIRENTRY;
207/** Pointer to a const EFI variable store directory entry. */
208typedef const RTEFIVARSTOREDIRENTRY *PCRTEFIVARSTOREDIRENTRY;
209
210
211/**
212 * Variable store directory.
213 */
214typedef struct RTEFIVARSTOREDIR
215{
216 /* Flag whether we reached the end of directory entries. */
217 bool fNoMoreFiles;
218 /** The index of the next item to read. */
219 uint32_t idxNext;
220 /** Directory entry. */
221 PCRTEFIVARSTOREDIRENTRY pEntry;
222 /** The variable store associated with this directory. */
223 PRTEFIVARSTORE pVarStore;
224 /** Time when the directory was created. */
225 RTTIMESPEC Time;
226 /** Pointer to the GUID entry, only valid for RTEFIVARSTOREDIRTYPE_GUID. */
227 PRTEFIGUID pGuid;
228 /** The variable ID, only valid for RTEFIVARSTOREDIRTYPE_RAW_ENTRY. */
229 uint32_t idVar;
230} RTEFIVARSTOREDIR;
231/** Pointer to an Variable store directory. */
232typedef RTEFIVARSTOREDIR *PRTEFIVARSTOREDIR;
233
234
235/**
236 * File type.
237 */
238typedef enum RTEFIVARSTOREFILETYPE
239{
240 /** Invalid type, do not use. */
241 RTEFIVARSTOREFILETYPE_INVALID = 0,
242 /** File accesses the data portion of the variable. */
243 RTEFIVARSTOREFILETYPE_DATA,
244 /** File accesses the attributes of the variable. */
245 RTEFIVARSTOREFILETYPE_ATTR,
246 /** File accesses the UUID of the variable. */
247 RTEFIVARSTOREFILETYPE_UUID,
248 /** File accesses the public key index of the variable. */
249 RTEFIVARSTOREFILETYPE_PUBKEY,
250 /** File accesses the raw EFI Time of the variable. */
251 RTEFIVARSTOREFILETYPE_TIME,
252 /** The monotonic counter (deprecated). */
253 RTEFIVARSTOREFILETYPE_MONOTONIC,
254 /** 32bit hack. */
255 RTEFIVARSTOREFILETYPE_32BIT_HACK = 0x7fffffff
256} RTEFIVARSTOREFILETYPE;
257
258
259/**
260 * Raw file type entry.
261 */
262typedef struct RTEFIVARSTOREFILERAWENTRY
263{
264 /** Name of the entry. */
265 const char *pszName;
266 /** The associated file type. */
267 RTEFIVARSTOREFILETYPE enmType;
268 /** File size of the object, 0 if dynamic. */
269 size_t cbObject;
270 /** Offset of the item in the variable header. */
271 uint32_t offObject;
272} RTEFIVARSTOREFILERAWENTRY;
273/** Pointer to a raw file type entry. */
274typedef RTEFIVARSTOREFILERAWENTRY *PRTEFIVARSTOREFILERAWENTRY;
275/** Pointer to a const file type entry. */
276typedef const RTEFIVARSTOREFILERAWENTRY *PCRTEFIVARSTOREFILERAWENTRY;
277
278
279/**
280 * Open file instance.
281 */
282typedef struct RTEFIVARFILE
283{
284 /** The file type. */
285 PCRTEFIVARSTOREFILERAWENTRY pEntry;
286 /** Variable store this file belongs to. */
287 PRTEFIVARSTORE pVarStore;
288 /** The underlying variable structure. */
289 PRTEFIVAR pVar;
290 /** Current offset into the file for I/O. */
291 RTFOFF offFile;
292} RTEFIVARFILE;
293/** Pointer to an open file instance. */
294typedef RTEFIVARFILE *PRTEFIVARFILE;
295
296
297/**
298 * Directories.
299 */
300static const RTEFIVARSTOREDIRENTRY g_aDirs[] =
301{
302 { NULL, 0, RTEFIVARSTOREDIRTYPE_ROOT, RTEFIVARSTOREDIRTYPE_ROOT },
303 { RT_STR_TUPLE("by-name"), RTEFIVARSTOREDIRTYPE_BY_NAME, RTEFIVARSTOREDIRTYPE_ROOT },
304 { RT_STR_TUPLE("by-uuid"), RTEFIVARSTOREDIRTYPE_BY_GUID, RTEFIVARSTOREDIRTYPE_ROOT },
305 { RT_STR_TUPLE("raw"), RTEFIVARSTOREDIRTYPE_RAW, RTEFIVARSTOREDIRTYPE_ROOT },
306 { NULL, 0, RTEFIVARSTOREDIRTYPE_GUID, RTEFIVARSTOREDIRTYPE_BY_GUID },
307 { NULL, 0, RTEFIVARSTOREDIRTYPE_RAW_ENTRY, RTEFIVARSTOREDIRTYPE_RAW },
308};
309
310
311/**
312 * Raw files for accessing specific items in the variable header.
313 */
314static const RTEFIVARSTOREFILERAWENTRY g_aRawFiles[] =
315{
316 { "attr", RTEFIVARSTOREFILETYPE_ATTR, sizeof(uint32_t), RT_UOFFSETOF(RTEFIVAR, fAttr) },
317 { "data", RTEFIVARSTOREFILETYPE_DATA, 0, 0 },
318 { "uuid", RTEFIVARSTOREFILETYPE_UUID, sizeof(RTUUID), RT_UOFFSETOF(RTEFIVAR, Uuid) },
319 { "pubkey", RTEFIVARSTOREFILETYPE_PUBKEY, sizeof(uint32_t), RT_UOFFSETOF(RTEFIVAR, idPubKey) },
320 { "time", RTEFIVARSTOREFILETYPE_TIME, sizeof(EFI_TIME), RT_UOFFSETOF(RTEFIVAR, EfiTimestamp) },
321 { "monotonic", RTEFIVARSTOREFILETYPE_MONOTONIC, sizeof(uint64_t), RT_UOFFSETOF(RTEFIVAR, cMonotonic) }
322};
323
324#define RTEFIVARSTORE_FILE_ENTRY_DATA 1
325
326
327/*********************************************************************************************************************************
328* Internal Functions *
329*********************************************************************************************************************************/
330static int rtEfiVarStore_NewDirByType(PRTEFIVARSTORE pThis, RTEFIVARSTOREDIRTYPE enmDirType,
331 PRTEFIGUID pGuid, uint32_t idVar, PRTVFSOBJ phVfsObj);
332
333
334#ifdef LOG_ENABLED
335
336/**
337 * Logs a firmware volume header.
338 *
339 * @param pFvHdr The firmware volume header.
340 */
341static void rtEfiVarStoreFvHdr_Log(PCEFI_FIRMWARE_VOLUME_HEADER pFvHdr)
342{
343 if (LogIs2Enabled())
344 {
345 Log2(("EfiVarStore: Volume Header:\n"));
346 Log2(("EfiVarStore: abZeroVec %#.*Rhxs\n", sizeof(pFvHdr->abZeroVec), &pFvHdr->abZeroVec[0]));
347 Log2(("EfiVarStore: GuidFilesystem %#.*Rhxs\n", sizeof(pFvHdr->GuidFilesystem), &pFvHdr->GuidFilesystem));
348 Log2(("EfiVarStore: cbFv %#RX64\n", RT_LE2H_U64(pFvHdr->cbFv)));
349 Log2(("EfiVarStore: u32Signature %#RX32\n", RT_LE2H_U32(pFvHdr->u32Signature)));
350 Log2(("EfiVarStore: fAttr %#RX32\n", RT_LE2H_U32(pFvHdr->fAttr)));
351 Log2(("EfiVarStore: cbFvHdr %#RX16\n", RT_LE2H_U16(pFvHdr->cbFvHdr)));
352 Log2(("EfiVarStore: u16Chksum %#RX16\n", RT_LE2H_U16(pFvHdr->u16Chksum)));
353 Log2(("EfiVarStore: offExtHdr %#RX16\n", RT_LE2H_U16(pFvHdr->offExtHdr)));
354 Log2(("EfiVarStore: bRsvd %#RX8\n", pFvHdr->bRsvd));
355 Log2(("EfiVarStore: bRevision %#RX8\n", pFvHdr->bRevision));
356 }
357}
358
359
360/**
361 * Logs a variable store header.
362 *
363 * @param pStoreHdr The variable store header.
364 */
365static void rtEfiVarStoreHdr_Log(PCEFI_VARSTORE_HEADER pStoreHdr)
366{
367 if (LogIs2Enabled())
368 {
369 Log2(("EfiVarStore: Variable Store Header:\n"));
370 Log2(("EfiVarStore: GuidVarStore %#.*Rhxs\n", sizeof(pStoreHdr->GuidVarStore), &pStoreHdr->GuidVarStore));
371 Log2(("EfiVarStore: cbVarStore %#RX32\n", RT_LE2H_U32(pStoreHdr->cbVarStore)));
372 Log2(("EfiVarStore: bFmt %#RX8\n", pStoreHdr->bFmt));
373 Log2(("EfiVarStore: bState %#RX8\n", pStoreHdr->bState));
374 }
375}
376
377
378/**
379 * Logs a authenticated variable header.
380 *
381 * @param pVarHdr The authenticated variable header.
382 * @param offVar Offset of the authenticated variable header.
383 */
384static void rtEfiVarStoreAuthVarHdr_Log(PCEFI_AUTH_VAR_HEADER pVarHdr, uint64_t offVar)
385{
386 if (LogIs2Enabled())
387 {
388 Log2(("EfiVarStore: Authenticated Variable Header at offset %#RU64:\n", offVar));
389 Log2(("EfiVarStore: u16StartId %#RX16\n", RT_LE2H_U16(pVarHdr->u16StartId)));
390 Log2(("EfiVarStore: bState %#RX8\n", pVarHdr->bState));
391 Log2(("EfiVarStore: bRsvd %#RX8\n", pVarHdr->bRsvd));
392 Log2(("EfiVarStore: fAttr %#RX32\n", RT_LE2H_U32(pVarHdr->fAttr)));
393 Log2(("EfiVarStore: cMonotonic %#RX64\n", RT_LE2H_U64(pVarHdr->cMonotonic)));
394 Log2(("EfiVarStore: Timestamp.u16Year %#RX16\n", RT_LE2H_U16(pVarHdr->Timestamp.u16Year)));
395 Log2(("EfiVarStore: Timestamp.u8Month %#RX8\n", pVarHdr->Timestamp.u8Month));
396 Log2(("EfiVarStore: Timestamp.u8Day %#RX8\n", pVarHdr->Timestamp.u8Day));
397 Log2(("EfiVarStore: Timestamp.u8Hour %#RX8\n", pVarHdr->Timestamp.u8Hour));
398 Log2(("EfiVarStore: Timestamp.u8Minute %#RX8\n", pVarHdr->Timestamp.u8Minute));
399 Log2(("EfiVarStore: Timestamp.u8Second %#RX8\n", pVarHdr->Timestamp.u8Second));
400 Log2(("EfiVarStore: Timestamp.bPad0 %#RX8\n", pVarHdr->Timestamp.bPad0));
401 Log2(("EfiVarStore: Timestamp.u32Nanosecond %#RX32\n", RT_LE2H_U32(pVarHdr->Timestamp.u32Nanosecond)));
402 Log2(("EfiVarStore: Timestamp.iTimezone %#RI16\n", RT_LE2H_S16(pVarHdr->Timestamp.iTimezone)));
403 Log2(("EfiVarStore: Timestamp.u8Daylight %#RX8\n", pVarHdr->Timestamp.u8Daylight));
404 Log2(("EfiVarStore: Timestamp.bPad1 %#RX8\n", pVarHdr->Timestamp.bPad1));
405 Log2(("EfiVarStore: idPubKey %#RX32\n", RT_LE2H_U32(pVarHdr->idPubKey)));
406 Log2(("EfiVarStore: cbName %#RX32\n", RT_LE2H_U32(pVarHdr->cbName)));
407 Log2(("EfiVarStore: cbData %#RX32\n", RT_LE2H_U32(pVarHdr->cbData)));
408 Log2(("EfiVarStore: GuidVendor %#.*Rhxs\n", sizeof(pVarHdr->GuidVendor), &pVarHdr->GuidVendor));
409 }
410}
411
412#endif /* LOG_ENABLED */
413
414/**
415 * Worker for rtEfiVarStoreFile_QueryInfo() and rtEfiVarStoreDir_QueryInfo().
416 *
417 * @returns IPRT status code.
418 * @param cbObject Size of the object in bytes.
419 * @param fIsDir Flag whether the object is a directory or file.
420 * @param pTime The time to use.
421 * @param pObjInfo The FS object information structure to fill in.
422 * @param enmAddAttr What to fill in.
423 */
424static int rtEfiVarStore_QueryInfo(uint64_t cbObject, bool fIsDir, PCRTTIMESPEC pTime, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
425{
426 pObjInfo->cbObject = cbObject;
427 pObjInfo->cbAllocated = cbObject;
428 pObjInfo->AccessTime = *pTime;
429 pObjInfo->ModificationTime = *pTime;
430 pObjInfo->ChangeTime = *pTime;
431 pObjInfo->BirthTime = *pTime;
432 pObjInfo->Attr.fMode = fIsDir
433 ? RTFS_TYPE_DIRECTORY | RTFS_UNIX_ALL_ACCESS_PERMS
434 : RTFS_TYPE_FILE | RTFS_UNIX_IWOTH | RTFS_UNIX_IROTH
435 | RTFS_UNIX_IWGRP | RTFS_UNIX_IRGRP
436 | RTFS_UNIX_IWUSR | RTFS_UNIX_IRUSR;
437 pObjInfo->Attr.enmAdditional = enmAddAttr;
438
439 switch (enmAddAttr)
440 {
441 case RTFSOBJATTRADD_NOTHING: RT_FALL_THRU();
442 case RTFSOBJATTRADD_UNIX:
443 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
444 pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
445 pObjInfo->Attr.u.Unix.cHardlinks = 1;
446 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
447 pObjInfo->Attr.u.Unix.INodeId = 0;
448 pObjInfo->Attr.u.Unix.fFlags = 0;
449 pObjInfo->Attr.u.Unix.GenerationId = 0;
450 pObjInfo->Attr.u.Unix.Device = 0;
451 break;
452 case RTFSOBJATTRADD_UNIX_OWNER:
453 pObjInfo->Attr.u.UnixOwner.uid = 0;
454 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
455 break;
456 case RTFSOBJATTRADD_UNIX_GROUP:
457 pObjInfo->Attr.u.UnixGroup.gid = 0;
458 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
459 break;
460 case RTFSOBJATTRADD_EASIZE:
461 pObjInfo->Attr.u.EASize.cb = 0;
462 break;
463 default:
464 return VERR_INVALID_PARAMETER;
465 }
466 return VINF_SUCCESS;
467}
468
469
470/**
471 * Tries to find and return the GUID entry for the given UUID.
472 *
473 * @returns Pointer to the GUID entry or NULL if not found.
474 * @param pThis The EFI variable store instance.
475 * @param pUuid The UUID to look for.
476 */
477static PRTEFIGUID rtEfiVarStore_GetGuid(PRTEFIVARSTORE pThis, PCRTUUID pUuid)
478{
479 for (uint32_t i = 0; i < pThis->cGuids; i++)
480 if (!RTUuidCompare(&pThis->paGuids[i].Uuid, pUuid))
481 return &pThis->paGuids[i];
482
483 return NULL;
484}
485
486
487/**
488 * Adds the given UUID to the array of known GUIDs.
489 *
490 * @returns Pointer to the GUID entry or NULL if out of memory.
491 * @param pThis The EFI variable store instance.
492 * @param pUuid The UUID to add.
493 */
494static PRTEFIGUID rtEfiVarStore_AddGuid(PRTEFIVARSTORE pThis, PCRTUUID pUuid)
495{
496 if (pThis->cGuids == pThis->cGuidsMax)
497 {
498 /* Grow the array. */
499 uint32_t cGuidsMaxNew = pThis->cGuidsMax + 10;
500 PRTEFIGUID paGuidsNew = (PRTEFIGUID)RTMemRealloc(pThis->paGuids, cGuidsMaxNew * sizeof(RTEFIGUID));
501 if (!paGuidsNew)
502 return NULL;
503
504 pThis->paGuids = paGuidsNew;
505 pThis->cGuidsMax = cGuidsMaxNew;
506 }
507
508 PRTEFIGUID pGuid = &pThis->paGuids[pThis->cGuids++];
509 pGuid->Uuid = *pUuid;
510 pGuid->paidxVars = NULL;
511 pGuid->cVars = 0;
512 pGuid->cVarsMax = 0;
513 return pGuid;
514}
515
516
517/**
518 * Adds the given variable to the GUID array.
519 *
520 * @returns IPRT status code.
521 * @param pThis The EFI variable store instance.
522 * @param pUuid The UUID of the variable.
523 * @param idVar The variable index into the array.
524 */
525static int rtEfiVarStore_AddVarByGuid(PRTEFIVARSTORE pThis, PCRTUUID pUuid, uint32_t idVar)
526{
527 PRTEFIGUID pGuid = rtEfiVarStore_GetGuid(pThis, pUuid);
528 if (!pGuid)
529 pGuid = rtEfiVarStore_AddGuid(pThis, pUuid);
530
531 if ( pGuid
532 && pGuid->cVars == pGuid->cVarsMax)
533 {
534 /* Grow the array. */
535 uint32_t cVarsMaxNew = pGuid->cVarsMax + 10;
536 uint32_t *paidxVarsNew = (uint32_t *)RTMemRealloc(pGuid->paidxVars, cVarsMaxNew * sizeof(uint32_t));
537 if (!paidxVarsNew)
538 return VERR_NO_MEMORY;
539
540 pGuid->paidxVars = paidxVarsNew;
541 pGuid->cVarsMax = cVarsMaxNew;
542 }
543
544 int rc = VINF_SUCCESS;
545 if (pGuid)
546 pGuid->paidxVars[pGuid->cVars++] = idVar;
547 else
548 rc = VERR_NO_MEMORY;
549
550 return rc;
551}
552
553
554/**
555 * Reads variable data from the given memory area.
556 *
557 * @returns IPRT status code.
558 * @param pThis The EFI variable file instance.
559 * @param pbData Pointer to the start of the data.
560 * @param cbData Size of the variable data in bytes.
561 * @param off Where to start reading relative from the data start offset.
562 * @param pSgBuf Where to store the read data.
563 * @param pcbRead Where to return the number of bytes read, optional.
564 */
565static int rtEfiVarStoreFile_ReadMem(PRTEFIVARFILE pThis, const uint8_t *pbData, size_t cbData,
566 RTFOFF off, PRTSGBUF pSgBuf, size_t *pcbRead)
567{
568 int rc;
569 size_t cbSeg = 0;
570 void * const pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
571 size_t const cbDataLeft = (uint64_t)off < cbData ? cbData - (size_t)off : 0;
572 if (!pcbRead)
573 {
574 if (cbSeg <= cbDataLeft)
575 {
576 memcpy(pvSeg, &pbData[off], cbSeg);
577 pThis->offFile = off + cbSeg;
578 Log6(("rtEfiVarStoreFile_ReadMem: off=%#RX64 cbSeg=%#x -> VINF_SUCCESS\n", off, cbSeg));
579 RTSgBufAdvance(pSgBuf, cbSeg);
580 rc = VINF_SUCCESS;
581 }
582 else
583 {
584 Log6(("rtEfiVarStoreFile_ReadMem: off=%#RX64 cbSeg=%#x -> VERR_EOF (cbDataLeft=%#x)\n", off, cbSeg, cbDataLeft));
585 rc = VERR_EOF;
586 }
587 }
588 else if (cbDataLeft == 0)
589 {
590 Log6(("rtEfiVarStoreFile_ReadMem: off=%#RX64 cbSeg=%#x -> VINF_EOF *pcbRead=0\n", off, cbSeg));
591 *pcbRead = 0;
592 rc = VINF_EOF;
593 }
594 else
595 {
596 size_t const cbThisRead = RT_MAX(cbSeg, cbDataLeft);
597 memcpy(pvSeg, &pbData[off], cbThisRead);
598
599 pThis->offFile = off + cbThisRead;
600 *pcbRead = cbThisRead;
601 RTSgBufAdvance(pSgBuf, cbThisRead);
602
603 /* Return VINF_EOF if beyond end-of-file. */
604 rc = cbThisRead == cbSeg ? VINF_SUCCESS : VINF_EOF;
605 Log6(("rtEfiVarStoreFile_ReadMem: off=%#RX64 cbSeg=%#x -> %Rrc *pcbRead=%#x\n", off, cbSeg, rc, cbThisRead));
606 }
607
608 return rc;
609}
610
611
612/**
613 * Writes variable data from the given memory area.
614 *
615 * @returns IPRT status code.
616 * @param pThis The EFI variable file instance.
617 * @param pbData Pointer to the start of the data.
618 * @param cbData Size of the variable data in bytes.
619 * @param off Where to start writing relative from the data start offset.
620 * @param pSgBuf The data to write.
621 * @param pcbWritten Where to return the number of bytes written, optional.
622 */
623static int rtEfiVarStoreFile_WriteMem(PRTEFIVARFILE pThis, uint8_t *pbData, size_t cbData,
624 RTFOFF off, PRTSGBUF pSgBuf, size_t *pcbWritten)
625{
626 int rc;
627 size_t cbSeg = 0;
628 void const * const pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
629 size_t const cbDataLeft = (uint64_t)off < cbData ? cbData - (size_t)off : 0;
630 if (!pcbWritten)
631 {
632 if (cbSeg <= cbDataLeft)
633 {
634 memcpy(&pbData[off], pvSeg, cbSeg);
635 pThis->offFile = off + cbSeg;
636 RTSgBufAdvance(pSgBuf, cbSeg);
637 Log6(("rtEfiVarStoreFile_WriteMem: off=%#RX64 cbSeg=%#x -> VINF_SUCCESS\n", off, cbSeg));
638 rc = VINF_SUCCESS;
639 }
640 else
641 {
642 Log6(("rtEfiVarStoreFile_WriteMem: off=%#RX64 cbSeg=%#x -> VERR_EOF\n", off, cbSeg));
643 rc = VERR_EOF; /** @todo r=bird: This status seems bogus. Use VERR_FILE_TOO_BIG instead? */
644 }
645 }
646 else if (cbDataLeft == 0)
647 {
648 *pcbWritten = 0;
649 rc = VINF_EOF; /** @todo r=bird: This is weird. Implementing the read EOF protocol for a write... */
650 }
651 else
652 {
653 size_t const cbThisWrite = RT_MAX(cbSeg, cbDataLeft);
654 memcpy(&pbData[off], pvSeg, cbThisWrite);
655
656 pThis->offFile = off + cbThisWrite;
657 *pcbWritten = cbThisWrite;
658 RTSgBufAdvance(pSgBuf, cbThisWrite);
659
660 /* Return VINF_EOF if beyond end-of-file. */
661 /** @todo r=bird: This is weird. Implementing the read EOF protocol for a write... */
662 rc = cbThisWrite == cbSeg ? VINF_SUCCESS : VINF_EOF;
663 Log6(("rtEfiVarStoreFile_WriteMem: off=%#RX64 cbSeg=%#x -> %Rrc *pcbWritten=%#x\n", off, cbSeg, rc, cbThisWrite));
664 }
665 return rc;
666}
667
668
669/**
670 * Reads variable data from the given range.
671 *
672 * @returns IPRT status code.
673 * @param pThis The EFI variable file instance.
674 * @param offData Where the data starts in the backing storage.
675 * @param cbData Size of the variable data in bytes.
676 * @param off Where to start reading relative from the data start offset.
677 * @param pSgBuf Where to store the read data.
678 * @param pcbRead Where to return the number of bytes read, optional.
679 */
680static int rtEfiVarStoreFile_ReadFile(PRTEFIVARFILE pThis, uint64_t offData, size_t cbData,
681 RTFOFF off, PRTSGBUF pSgBuf, size_t *pcbRead)
682{
683 int rc;
684 PRTEFIVARSTORE const pVarStore = pThis->pVarStore;
685 size_t cbSeg = 0;
686 void * const pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
687 size_t const cbDataLeft = (uint64_t)off < cbData ? cbData - (size_t)off : 0;
688 uint64_t const offBacking = offData + off;
689 if (!pcbRead)
690 {
691 if (cbSeg <= cbDataLeft)
692 {
693 rc = RTVfsFileSgRead(pVarStore->hVfsBacking, offBacking, pSgBuf, true /*fBlocking*/, NULL /*pcbRead*/);
694 if (RT_SUCCESS(rc))
695 pThis->offFile = off + cbSeg;
696 Log6(("rtEfiVarStoreFile_ReadFile: off=%#RX64 cbSeg=%#x -> %Rrc\n", off, cbSeg, rc));
697 }
698 else
699 {
700 Log6(("rtEfiVarStoreFile_ReadFile: off=%#RX64 cbSeg=%#x cbDataLeft=%#zx -> VERR_EOF\n", off, cbSeg, cbDataLeft));
701 rc = VERR_EOF;
702 }
703 }
704 else if (cbDataLeft == 0)
705 {
706 Log6(("rtEfiVarStoreFile_ReadFile: off=%#RX64 cbSeg=%#x -> VINF_EOF\n", off, cbSeg));
707 *pcbRead = 0;
708 rc = VINF_EOF;
709 }
710 else
711 {
712 size_t const cbThisRead = RT_MAX(cbSeg, cbDataLeft);
713 rc = RTVfsFileReadAt(pVarStore->hVfsBacking, offBacking, pvSeg, cbThisRead, NULL /*pcbRead*/);
714 if (RT_SUCCESS(rc))
715 {
716 pThis->offFile = off + cbThisRead;
717 *pcbRead = cbThisRead;
718 RTSgBufAdvance(pSgBuf, cbThisRead);
719
720 /* Return VINF_EOF if beyond end-of-file. */
721 rc = cbThisRead == cbSeg ? VINF_SUCCESS : VINF_EOF;
722 }
723 else
724 *pcbRead = 0;
725 Log6(("rtFsEfiVarStore_Read: off=%#RX64 cbSeg=%#x -> %Rrc *pcbRead=%#x\n", off, cbSeg, rc, *pcbRead));
726 }
727 return rc;
728}
729
730
731/**
732 * Ensures that the variable data is available before any modification.
733 *
734 * @returns IPRT status code.
735 * @param pVar The variable instance.
736 */
737static int rtEfiVarStore_VarReadData(PRTEFIVAR pVar)
738{
739 if (RT_LIKELY( !pVar->offVarData
740 || !pVar->cbData))
741 return VINF_SUCCESS;
742
743 Assert(!pVar->pvData);
744 pVar->pvData = RTMemAlloc(pVar->cbData);
745 if (RT_UNLIKELY(!pVar->pvData))
746 return VERR_NO_MEMORY;
747
748 PRTEFIVARSTORE pVarStore = pVar->pVarStore;
749 int rc = RTVfsFileReadAt(pVarStore->hVfsBacking, pVar->offVarData, pVar->pvData, pVar->cbData, NULL);
750 if (RT_SUCCESS(rc))
751 pVar->offVarData = 0; /* Marks the variable data as in memory. */
752 else
753 {
754 RTMemFree(pVar->pvData);
755 pVar->pvData = NULL;
756 }
757
758 return rc;
759}
760
761
762/**
763 * Ensures that the given variable has the given data size.
764 *
765 * @returns IPRT status code.
766 * @retval VERR_DISK_FULL if the new size would exceed the variable storage size.
767 * @param pVar The variable instance.
768 * @param cbData New number of bytes of data for the variable.
769 */
770static int rtEfiVarStore_VarEnsureDataSz(PRTEFIVAR pVar, size_t cbData)
771{
772 PRTEFIVARSTORE pVarStore = pVar->pVarStore;
773
774 if (pVar->cbData == cbData)
775 return VINF_SUCCESS;
776
777 if ((uint32_t)cbData != cbData)
778 return VERR_FILE_TOO_BIG;
779
780 int rc = VINF_SUCCESS;
781 if (cbData < pVar->cbData)
782 {
783 /* Shrink. */
784 void *pvNew = RTMemRealloc(pVar->pvData, cbData);
785 if (pvNew)
786 {
787 pVar->pvData = pvNew;
788 pVarStore->cbVarData -= pVar->cbData - cbData;
789 pVar->cbData = (uint32_t)cbData;
790 }
791 else
792 rc = VERR_NO_MEMORY;
793 }
794 else if (cbData > pVar->cbData)
795 {
796 /* Grow. */
797 if (pVarStore->cbVarStore - pVarStore->cbVarData >= cbData - pVar->cbData)
798 {
799 void *pvNew = RTMemRealloc(pVar->pvData, cbData);
800 if (pvNew)
801 {
802 pVar->pvData = pvNew;
803 pVarStore->cbVarData += cbData - pVar->cbData;
804 pVar->cbData = (uint32_t)cbData;
805 }
806 else
807 rc = VERR_NO_MEMORY;
808 }
809 else
810 rc = VERR_DISK_FULL;
811 }
812
813 return rc;
814}
815
816
817/**
818 * Flush the variable store to the backing storage. This will remove any
819 * deleted variables in the backing storage.
820 *
821 * @returns IPRT status code.
822 * @param pThis The EFI variable store instance.
823 */
824static int rtEfiVarStore_Flush(PRTEFIVARSTORE pThis)
825{
826 int rc = VINF_SUCCESS;
827 uint64_t offCur = pThis->offStoreData;
828
829 for (uint32_t i = 0; i < pThis->cVars && RT_SUCCESS(rc); i++)
830 {
831 PRTUTF16 pwszName = NULL;
832 size_t cwcLen = 0;
833 PRTEFIVAR pVar = &pThis->paVars[i];
834
835 if (!pVar->fDeleted)
836 {
837 rc = RTStrToUtf16Ex(pVar->pszName, RTSTR_MAX, &pwszName, 0, &cwcLen);
838 if (RT_SUCCESS(rc))
839 {
840 cwcLen++; /* Include the terminator. */
841
842 /* Read in the data of the variable if it exists. */
843 rc = rtEfiVarStore_VarReadData(pVar);
844 if (RT_SUCCESS(rc))
845 {
846 /* Write out the variable. */
847 EFI_AUTH_VAR_HEADER VarHdr;
848 size_t cbName = cwcLen * sizeof(RTUTF16);
849
850 VarHdr.u16StartId = RT_H2LE_U16(EFI_AUTH_VAR_HEADER_START);
851 VarHdr.bState = EFI_AUTH_VAR_HEADER_STATE_ADDED;
852 VarHdr.bRsvd = 0;
853 VarHdr.fAttr = RT_H2LE_U32(pVar->fAttr);
854 VarHdr.cMonotonic = RT_H2LE_U64(pVar->cMonotonic);
855 VarHdr.idPubKey = RT_H2LE_U32(pVar->idPubKey);
856 VarHdr.cbName = RT_H2LE_U32((uint32_t)cbName);
857 VarHdr.cbData = RT_H2LE_U32(pVar->cbData);
858 RTEfiGuidFromUuid(&VarHdr.GuidVendor, &pVar->Uuid);
859 memcpy(&VarHdr.Timestamp, &pVar->EfiTimestamp, sizeof(pVar->EfiTimestamp));
860
861 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur, &VarHdr, sizeof(VarHdr), NULL);
862 if (RT_SUCCESS(rc))
863 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur + sizeof(VarHdr), pwszName, cbName, NULL);
864 if (RT_SUCCESS(rc))
865 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur + sizeof(VarHdr) + cbName, pVar->pvData, pVar->cbData, NULL);
866 if (RT_SUCCESS(rc))
867 {
868 offCur += sizeof(VarHdr) + cbName + pVar->cbData;
869 uint64_t offCurAligned = RT_ALIGN_64(offCur, sizeof(uint32_t));
870 if (offCurAligned > offCur)
871 {
872 /* Should be at most 3 bytes to align the next variable to a 32bit boundary. */
873 Assert(offCurAligned - offCur <= 3);
874 uint8_t abFill[3] = { 0xff };
875 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur, &abFill[0], offCurAligned - offCur, NULL);
876 }
877
878 offCur = offCurAligned;
879 }
880 }
881
882 RTUtf16Free(pwszName);
883 }
884 }
885 }
886
887 if (RT_SUCCESS(rc))
888 {
889 /* Fill the remainder with 0xff as it would be the case for a real NAND flash device. */
890 uint8_t abFF[512];
891 memset(&abFF[0], 0xff, sizeof(abFF));
892
893 uint64_t offStart = offCur;
894 uint64_t offEnd = pThis->offStoreData + pThis->cbVarStore;
895 while ( offStart < offEnd
896 && RT_SUCCESS(rc))
897 {
898 size_t cbThisWrite = RT_MIN(sizeof(abFF), offEnd - offStart);
899 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offStart, &abFF[0], cbThisWrite, NULL);
900 offStart += cbThisWrite;
901 }
902 }
903
904 return rc;
905}
906
907
908/**
909 * Tries to find a variable with the given name.
910 *
911 * @returns Pointer to the variable if found or NULL otherwise.
912 * @param pThis The variable store instance.
913 * @param pszName Name of the variable to look for.
914 * @param pidVar Where to store the index of the variable, optional.
915 */
916static PRTEFIVAR rtEfiVarStore_VarGet(PRTEFIVARSTORE pThis, const char *pszName, uint32_t *pidVar)
917{
918 for (uint32_t i = 0; i < pThis->cVars; i++)
919 if ( !pThis->paVars[i].fDeleted
920 && !strcmp(pszName, pThis->paVars[i].pszName))
921 {
922 if (pidVar)
923 *pidVar = i;
924 return &pThis->paVars[i];
925 }
926
927 return NULL;
928}
929
930
931/**
932 * Maybe grows the array of variables to hold more entries.
933 *
934 * @returns IPRT status code.
935 * @param pThis The variable store instance.
936 */
937static int rtEfiVarStore_VarMaybeGrowEntries(PRTEFIVARSTORE pThis)
938{
939 if (pThis->cVars == pThis->cVarsMax)
940 {
941 /* Grow the variable array. */
942 uint32_t cVarsMaxNew = pThis->cVarsMax + 10;
943 PRTEFIVAR paVarsNew = (PRTEFIVAR)RTMemRealloc(pThis->paVars, cVarsMaxNew * sizeof(RTEFIVAR));
944 if (!paVarsNew)
945 return VERR_NO_MEMORY;
946
947 pThis->paVars = paVarsNew;
948 pThis->cVarsMax = cVarsMaxNew;
949 }
950
951 return VINF_SUCCESS;
952}
953
954
955/**
956 * Add a variable with the given name.
957 *
958 * @returns Pointer to the entry or NULL if out of memory.
959 * @param pThis The variable store instance.
960 * @param pszName Name of the variable to add.
961 * @param pUuid The UUID of the variable owner.
962 * @param pidVar Where to store the variable index on success, optional
963 */
964static PRTEFIVAR rtEfiVarStore_VarAdd(PRTEFIVARSTORE pThis, const char *pszName, PCRTUUID pUuid, uint32_t *pidVar)
965{
966 Assert(!rtEfiVarStore_VarGet(pThis, pszName, NULL));
967
968 int rc = rtEfiVarStore_VarMaybeGrowEntries(pThis);
969 if (RT_SUCCESS(rc))
970 {
971 PRTEFIVAR pVar = &pThis->paVars[pThis->cVars];
972 RT_ZERO(*pVar);
973
974 pVar->pszName = RTStrDup(pszName);
975 if (pVar->pszName)
976 {
977 pVar->pVarStore = pThis;
978 pVar->offVarData = 0;
979 pVar->fDeleted = false;
980 pVar->Uuid = *pUuid;
981 RTTimeNow(&pVar->Time);
982
983 rc = rtEfiVarStore_AddVarByGuid(pThis, pUuid, pThis->cVars);
984 AssertRC(rc); /** @todo */
985
986 if (pidVar)
987 *pidVar = pThis->cVars;
988 pThis->cVars++;
989 return pVar;
990 }
991 }
992
993 return NULL;
994}
995
996
997/**
998 * Delete the given variable.
999 *
1000 * @returns IPRT status code.
1001 * @param pThis The variable store instance.
1002 * @param pVar The variable.
1003 */
1004static int rtEfiVarStore_VarDel(PRTEFIVARSTORE pThis, PRTEFIVAR pVar)
1005{
1006 pVar->fDeleted = true;
1007 if (pVar->pvData)
1008 RTMemFree(pVar->pvData);
1009 pVar->pvData = NULL;
1010 pThis->cbVarData -= sizeof(EFI_AUTH_VAR_HEADER) + pVar->cbData;
1011 /** @todo Delete from GUID entry. */
1012 return VINF_SUCCESS;
1013}
1014
1015
1016/**
1017 * Delete the variable with the given index.
1018 *
1019 * @returns IPRT status code.
1020 * @param pThis The variable store instance.
1021 * @param idVar The variable index.
1022 */
1023static int rtEfiVarStore_VarDelById(PRTEFIVARSTORE pThis, uint32_t idVar)
1024{
1025 return rtEfiVarStore_VarDel(pThis, &pThis->paVars[idVar]);
1026}
1027
1028
1029/**
1030 * Delete the variable with the given name.
1031 *
1032 * @returns IPRT status code.
1033 * @param pThis The variable store instance.
1034 * @param pszName Name of the variable to delete.
1035 */
1036static int rtEfiVarStore_VarDelByName(PRTEFIVARSTORE pThis, const char *pszName)
1037{
1038 PRTEFIVAR pVar = rtEfiVarStore_VarGet(pThis, pszName, NULL);
1039 if (pVar)
1040 return rtEfiVarStore_VarDel(pThis, pVar);
1041
1042 return VERR_FILE_NOT_FOUND;
1043}
1044
1045
1046/*
1047 *
1048 * File operations.
1049 * File operations.
1050 * File operations.
1051 *
1052 */
1053
1054/**
1055 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1056 */
1057static DECLCALLBACK(int) rtEfiVarStoreFile_Close(void *pvThis)
1058{
1059 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1060 LogFlow(("rtEfiVarStoreFile_Close(%p/%p)\n", pThis, pThis->pVar));
1061 RT_NOREF(pThis);
1062 return VINF_SUCCESS;
1063}
1064
1065
1066/**
1067 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1068 */
1069static DECLCALLBACK(int) rtEfiVarStoreFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1070{
1071 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1072 uint64_t cbObject = pThis->pEntry->cbObject > 0
1073 ? pThis->pEntry->cbObject
1074 : pThis->pVar->cbData;
1075 return rtEfiVarStore_QueryInfo(cbObject, false /*fIsDir*/, &pThis->pVar->Time, pObjInfo, enmAddAttr);
1076}
1077
1078
1079/**
1080 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
1081 */
1082static DECLCALLBACK(int) rtEfiVarStoreFile_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
1083{
1084 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1085 PRTEFIVAR pVar = pThis->pVar;
1086 AssertReturn(pSgBuf->cSegs == 1, VERR_INTERNAL_ERROR_3);
1087 RT_NOREF(fBlocking);
1088
1089 if (off == -1)
1090 off = pThis->offFile;
1091 else
1092 AssertReturn(off >= 0, VERR_INTERNAL_ERROR_3);
1093
1094 int rc;
1095 if (pThis->pEntry->cbObject)
1096 rc = rtEfiVarStoreFile_ReadMem(pThis, (const uint8_t *)pVar + pThis->pEntry->offObject, pThis->pEntry->cbObject, off,
1097 pSgBuf, pcbRead);
1098 else
1099 {
1100 /* Data section. */
1101 if (!pVar->offVarData)
1102 rc = rtEfiVarStoreFile_ReadMem(pThis, (const uint8_t *)pVar->pvData, pVar->cbData, off, pSgBuf, pcbRead);
1103 else
1104 rc = rtEfiVarStoreFile_ReadFile(pThis, pVar->offVarData, pVar->cbData, off, pSgBuf, pcbRead);
1105 }
1106
1107 return rc;
1108}
1109
1110
1111/**
1112 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
1113 */
1114static DECLCALLBACK(int) rtEfiVarStoreFile_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
1115{
1116 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1117 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1118 PRTEFIVAR pVar = pThis->pVar;
1119 AssertReturn(pSgBuf->cSegs == 1, VERR_INTERNAL_ERROR_3);
1120 RT_NOREF(fBlocking);
1121
1122 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1123 return VERR_WRITE_PROTECT;
1124
1125 if (off == -1)
1126 off = pThis->offFile;
1127 else
1128 AssertReturn(off >= 0, VERR_INTERNAL_ERROR_3);
1129
1130 int rc;
1131 if (pThis->pEntry->cbObject) /* These can't grow. */
1132 rc = rtEfiVarStoreFile_WriteMem(pThis, (uint8_t *)pVar + pThis->pEntry->offObject, pThis->pEntry->cbObject,
1133 off, pSgBuf, pcbWritten);
1134 else
1135 {
1136 /* Writing data section. */
1137 rc = rtEfiVarStore_VarReadData(pVar);
1138 if (RT_SUCCESS(rc))
1139 {
1140 if (off + pSgBuf->paSegs[0].cbSeg > pVar->cbData)
1141 rc = rtEfiVarStore_VarEnsureDataSz(pVar, off + pSgBuf->paSegs[0].cbSeg);
1142 if (RT_SUCCESS(rc))
1143 rc = rtEfiVarStoreFile_WriteMem(pThis, (uint8_t *)pVar->pvData, pVar->cbData, off, pSgBuf, pcbWritten);
1144 }
1145 }
1146
1147 return rc;
1148}
1149
1150
1151/**
1152 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
1153 */
1154static DECLCALLBACK(int) rtEfiVarStoreFile_Flush(void *pvThis)
1155{
1156 RT_NOREF(pvThis);
1157 return VINF_SUCCESS;
1158}
1159
1160
1161/**
1162 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
1163 */
1164static DECLCALLBACK(int) rtEfiVarStoreFile_Tell(void *pvThis, PRTFOFF poffActual)
1165{
1166 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1167 *poffActual = pThis->offFile;
1168 return VINF_SUCCESS;
1169}
1170
1171
1172/**
1173 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
1174 */
1175static DECLCALLBACK(int) rtEfiVarStoreFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
1176{
1177 RT_NOREF(pvThis, fMode, fMask);
1178 return VERR_WRITE_PROTECT;
1179}
1180
1181
1182/**
1183 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
1184 */
1185static DECLCALLBACK(int) rtEfiVarStoreFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1186 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1187{
1188 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1189 return VERR_WRITE_PROTECT;
1190}
1191
1192
1193/**
1194 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
1195 */
1196static DECLCALLBACK(int) rtEfiVarStoreFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
1197{
1198 RT_NOREF(pvThis, uid, gid);
1199 return VERR_WRITE_PROTECT;
1200}
1201
1202
1203/**
1204 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
1205 */
1206static DECLCALLBACK(int) rtEfiVarStoreFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
1207{
1208 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1209 RTFOFF offNew;
1210 switch (uMethod)
1211 {
1212 case RTFILE_SEEK_BEGIN:
1213 offNew = offSeek;
1214 break;
1215 case RTFILE_SEEK_END:
1216 offNew = pThis->pVar->cbData + offSeek;
1217 break;
1218 case RTFILE_SEEK_CURRENT:
1219 offNew = (RTFOFF)pThis->offFile + offSeek;
1220 break;
1221 default:
1222 return VERR_INVALID_PARAMETER;
1223 }
1224 if (offNew >= 0)
1225 {
1226 pThis->offFile = offNew;
1227 *poffActual = offNew;
1228 return VINF_SUCCESS;
1229 }
1230 return VERR_NEGATIVE_SEEK;
1231}
1232
1233
1234/**
1235 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
1236 */
1237static DECLCALLBACK(int) rtEfiVarStoreFile_QuerySize(void *pvThis, uint64_t *pcbFile)
1238{
1239 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1240 if (pThis->pEntry->cbObject)
1241 *pcbFile = pThis->pEntry->cbObject;
1242 else
1243 *pcbFile = (uint64_t)pThis->pVar->cbData;
1244 return VINF_SUCCESS;
1245}
1246
1247
1248/**
1249 * @interface_method_impl{RTVFSFILEOPS,pfnSetSize}
1250 */
1251static DECLCALLBACK(int) rtEfiVarStoreFile_SetSize(void *pvThis, uint64_t cbFile, uint32_t fFlags)
1252{
1253 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1254 PRTEFIVAR pVar = pThis->pVar;
1255 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1256
1257 RT_NOREF(fFlags);
1258
1259 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1260 return VERR_WRITE_PROTECT;
1261
1262 int rc = rtEfiVarStore_VarReadData(pVar);
1263 if (RT_SUCCESS(rc))
1264 rc = rtEfiVarStore_VarEnsureDataSz(pVar, cbFile);
1265
1266 return rc;
1267}
1268
1269
1270/**
1271 * @interface_method_impl{RTVFSFILEOPS,pfnQueryMaxSize}
1272 */
1273static DECLCALLBACK(int) rtEfiVarStoreFile_QueryMaxSize(void *pvThis, uint64_t *pcbMax)
1274{
1275 RT_NOREF(pvThis);
1276 *pcbMax = UINT32_MAX;
1277 return VINF_SUCCESS;
1278}
1279
1280
1281/**
1282 * EFI variable store file operations.
1283 */
1284static const RTVFSFILEOPS g_rtEfiVarStoreFileOps =
1285{
1286 { /* Stream */
1287 { /* Obj */
1288 RTVFSOBJOPS_VERSION,
1289 RTVFSOBJTYPE_FILE,
1290 "EfiVarStore File",
1291 rtEfiVarStoreFile_Close,
1292 rtEfiVarStoreFile_QueryInfo,
1293 NULL,
1294 RTVFSOBJOPS_VERSION
1295 },
1296 RTVFSIOSTREAMOPS_VERSION,
1297 RTVFSIOSTREAMOPS_FEAT_NO_SG,
1298 rtEfiVarStoreFile_Read,
1299 rtEfiVarStoreFile_Write,
1300 rtEfiVarStoreFile_Flush,
1301 NULL /*PollOne*/,
1302 rtEfiVarStoreFile_Tell,
1303 NULL /*pfnSkip*/,
1304 NULL /*pfnZeroFill*/,
1305 RTVFSIOSTREAMOPS_VERSION,
1306 },
1307 RTVFSFILEOPS_VERSION,
1308 0,
1309 { /* ObjSet */
1310 RTVFSOBJSETOPS_VERSION,
1311 RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
1312 rtEfiVarStoreFile_SetMode,
1313 rtEfiVarStoreFile_SetTimes,
1314 rtEfiVarStoreFile_SetOwner,
1315 RTVFSOBJSETOPS_VERSION
1316 },
1317 rtEfiVarStoreFile_Seek,
1318 rtEfiVarStoreFile_QuerySize,
1319 rtEfiVarStoreFile_SetSize,
1320 rtEfiVarStoreFile_QueryMaxSize,
1321 RTVFSFILEOPS_VERSION
1322};
1323
1324
1325/**
1326 * Creates a new VFS file from the given regular file inode.
1327 *
1328 * @returns IPRT status code.
1329 * @param pThis The ext volume instance.
1330 * @param fOpen Open flags passed.
1331 * @param pVar The variable this file accesses.
1332 * @param pEntry File type entry.
1333 * @param phVfsFile Where to store the VFS file handle on success.
1334 * @param pErrInfo Where to record additional error information on error, optional.
1335 */
1336static int rtEfiVarStore_NewFile(PRTEFIVARSTORE pThis, uint64_t fOpen, PRTEFIVAR pVar,
1337 PCRTEFIVARSTOREFILERAWENTRY pEntry, PRTVFSOBJ phVfsObj)
1338{
1339 RTVFSFILE hVfsFile;
1340 PRTEFIVARFILE pNewFile;
1341 int rc = RTVfsNewFile(&g_rtEfiVarStoreFileOps, sizeof(*pNewFile), fOpen, pThis->hVfsSelf, NIL_RTVFSLOCK,
1342 &hVfsFile, (void **)&pNewFile);
1343 if (RT_SUCCESS(rc))
1344 {
1345 pNewFile->pEntry = pEntry;
1346 pNewFile->pVarStore = pThis;
1347 pNewFile->pVar = pVar;
1348 pNewFile->offFile = 0;
1349
1350 *phVfsObj = RTVfsObjFromFile(hVfsFile);
1351 RTVfsFileRelease(hVfsFile);
1352 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
1353 }
1354
1355 return rc;
1356}
1357
1358
1359
1360/*
1361 *
1362 * Directory instance methods
1363 * Directory instance methods
1364 * Directory instance methods
1365 *
1366 */
1367
1368/**
1369 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1370 */
1371static DECLCALLBACK(int) rtEfiVarStoreDir_Close(void *pvThis)
1372{
1373 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1374 LogFlowFunc(("pThis=%p\n", pThis));
1375 pThis->pVarStore = NULL;
1376 return VINF_SUCCESS;
1377}
1378
1379
1380/**
1381 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1382 */
1383static DECLCALLBACK(int) rtEfiVarStoreDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1384{
1385 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1386 LogFlowFunc(("\n"));
1387 return rtEfiVarStore_QueryInfo(1, true /*fIsDir*/, &pThis->Time, pObjInfo, enmAddAttr);
1388}
1389
1390
1391/**
1392 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
1393 */
1394static DECLCALLBACK(int) rtEfiVarStoreDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
1395{
1396 LogFlowFunc(("\n"));
1397 RT_NOREF(pvThis, fMode, fMask);
1398 return VERR_WRITE_PROTECT;
1399}
1400
1401
1402/**
1403 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
1404 */
1405static DECLCALLBACK(int) rtEfiVarStoreDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1406 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1407{
1408 LogFlowFunc(("\n"));
1409 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1410 return VERR_WRITE_PROTECT;
1411}
1412
1413
1414/**
1415 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
1416 */
1417static DECLCALLBACK(int) rtEfiVarStoreDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
1418{
1419 LogFlowFunc(("\n"));
1420 RT_NOREF(pvThis, uid, gid);
1421 return VERR_WRITE_PROTECT;
1422}
1423
1424
1425/**
1426 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
1427 */
1428static DECLCALLBACK(int) rtEfiVarStoreDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen,
1429 uint32_t fFlags, PRTVFSOBJ phVfsObj)
1430{
1431 LogFlowFunc(("pszEntry='%s' fOpen=%#RX64 fFlags=%#x\n", pszEntry, fOpen, fFlags));
1432 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1433 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1434 int rc = VINF_SUCCESS;
1435
1436 /*
1437 * Special cases '.' and '.'
1438 */
1439 if (pszEntry[0] == '.')
1440 {
1441 RTEFIVARSTOREDIRTYPE enmDirTypeNew = RTEFIVARSTOREDIRTYPE_INVALID;
1442 if (pszEntry[1] == '\0')
1443 enmDirTypeNew = pThis->pEntry->enmType;
1444 else if (pszEntry[1] == '.' && pszEntry[2] == '\0')
1445 enmDirTypeNew = pThis->pEntry->enmParentType;
1446
1447 if (enmDirTypeNew != RTEFIVARSTOREDIRTYPE_INVALID)
1448 {
1449 if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
1450 {
1451 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
1452 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE)
1453 rc = rtEfiVarStore_NewDirByType(pVarStore, enmDirTypeNew, NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1454 else
1455 rc = VERR_ACCESS_DENIED;
1456 }
1457 else
1458 rc = VERR_IS_A_DIRECTORY;
1459 return rc;
1460 }
1461 }
1462
1463 /*
1464 * We can create or replace in certain directories.
1465 */
1466 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
1467 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
1468 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
1469 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
1470 { /* likely */ }
1471 else
1472 return VERR_WRITE_PROTECT;
1473
1474 switch (pThis->pEntry->enmType)
1475 {
1476 case RTEFIVARSTOREDIRTYPE_ROOT:
1477 {
1478 if (!strcmp(pszEntry, "by-name"))
1479 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_BY_NAME,
1480 NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1481 else if (!strcmp(pszEntry, "by-uuid"))
1482 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_BY_GUID,
1483 NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1484 else if (!strcmp(pszEntry, "raw"))
1485 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_RAW,
1486 NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1487 else
1488 rc = VERR_FILE_NOT_FOUND;
1489 break;
1490 }
1491 case RTEFIVARSTOREDIRTYPE_GUID: /** @todo This looks through all variables, not only the ones with the GUID. */
1492 case RTEFIVARSTOREDIRTYPE_BY_NAME:
1493 case RTEFIVARSTOREDIRTYPE_RAW:
1494 {
1495 /* Look for the name. */
1496 uint32_t idVar = 0;
1497 PRTEFIVAR pVar = rtEfiVarStore_VarGet(pVarStore, pszEntry, &idVar);
1498 if ( !pVar
1499 && ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
1500 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
1501 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE))
1502 {
1503 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_GUID)
1504 pVar = rtEfiVarStore_VarAdd(pVarStore, pszEntry, &pThis->pGuid->Uuid, &idVar);
1505 else
1506 {
1507 RTUUID UuidNull;
1508 RTUuidClear(&UuidNull);
1509 pVar = rtEfiVarStore_VarAdd(pVarStore, pszEntry, &UuidNull, &idVar);
1510 }
1511
1512 if (!pVar)
1513 {
1514 rc = VERR_NO_MEMORY;
1515 break;
1516 }
1517 }
1518
1519 if (pVar)
1520 {
1521 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW)
1522 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_RAW_ENTRY,
1523 NULL /*pGuid*/, idVar, phVfsObj);
1524 else
1525 return rtEfiVarStore_NewFile(pVarStore, fOpen, pVar,
1526 &g_aRawFiles[RTEFIVARSTORE_FILE_ENTRY_DATA], phVfsObj);
1527 }
1528
1529 rc = VERR_FILE_NOT_FOUND;
1530 break;
1531 }
1532 case RTEFIVARSTOREDIRTYPE_BY_GUID:
1533 {
1534 /* Look for the name. */
1535 for (uint32_t i = 0; i < pVarStore->cGuids; i++)
1536 {
1537 PRTEFIGUID pGuid = &pVarStore->paGuids[i];
1538 char szUuid[RTUUID_STR_LENGTH];
1539 rc = RTUuidToStr(&pGuid->Uuid, szUuid, sizeof(szUuid));
1540 AssertRC(rc);
1541
1542 if (!strcmp(pszEntry, szUuid))
1543 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_GUID,
1544 pGuid, 0 /*idVar*/, phVfsObj);
1545 }
1546
1547 rc = VERR_FILE_NOT_FOUND;
1548 break;
1549 }
1550 case RTEFIVARSTOREDIRTYPE_RAW_ENTRY:
1551 {
1552 /* Look for the name. */
1553 for (uint32_t i = 0; i < RT_ELEMENTS(g_aRawFiles); i++)
1554 if (!strcmp(pszEntry, g_aRawFiles[i].pszName))
1555 return rtEfiVarStore_NewFile(pVarStore, fOpen, &pVarStore->paVars[pThis->idVar],
1556 &g_aRawFiles[i], phVfsObj);
1557
1558 rc = VERR_FILE_NOT_FOUND;
1559 break;
1560 }
1561 case RTEFIVARSTOREDIRTYPE_INVALID:
1562 default:
1563 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
1564 }
1565
1566 LogFlow(("rtEfiVarStoreDir_Open(%s): returns %Rrc\n", pszEntry, rc));
1567 return rc;
1568}
1569
1570
1571/**
1572 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
1573 */
1574static DECLCALLBACK(int) rtEfiVarStoreDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
1575{
1576 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1577 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1578 LogFlowFunc(("\n"));
1579
1580 RT_NOREF(fMode, phVfsDir);
1581
1582 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1583 return VERR_WRITE_PROTECT;
1584
1585 /* We support creating directories only for GUIDs and RAW variable entries. */
1586 int rc = VINF_SUCCESS;
1587 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_BY_GUID)
1588 {
1589 RTUUID Uuid;
1590 rc = RTUuidFromStr(&Uuid, pszSubDir);
1591 if (RT_FAILURE(rc))
1592 return VERR_NOT_SUPPORTED;
1593
1594 PRTEFIGUID pGuid = rtEfiVarStore_GetGuid(pVarStore, &Uuid);
1595 if (pGuid)
1596 return VERR_ALREADY_EXISTS;
1597
1598 pGuid = rtEfiVarStore_AddGuid(pVarStore, &Uuid);
1599 if (!pGuid)
1600 return VERR_NO_MEMORY;
1601 }
1602 else if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW)
1603 {
1604 PRTEFIVAR pVar = rtEfiVarStore_VarGet(pVarStore, pszSubDir, NULL /*pidVar*/);
1605 if (!pVar)
1606 {
1607 if (sizeof(EFI_AUTH_VAR_HEADER) < pVarStore->cbVarStore - pVarStore->cbVarData)
1608 {
1609 uint32_t idVar = 0;
1610 RTUUID UuidNull;
1611 RTUuidClear(&UuidNull);
1612
1613 pVar = rtEfiVarStore_VarAdd(pVarStore, pszSubDir, &UuidNull, &idVar);
1614 if (pVar)
1615 pVarStore->cbVarData += sizeof(EFI_AUTH_VAR_HEADER);
1616 else
1617 rc = VERR_NO_MEMORY;
1618 }
1619 else
1620 rc = VERR_DISK_FULL;
1621 }
1622 else
1623 rc = VERR_ALREADY_EXISTS;
1624 }
1625 else
1626 rc = VERR_NOT_SUPPORTED;
1627
1628 return rc;
1629}
1630
1631
1632/**
1633 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
1634 */
1635static DECLCALLBACK(int) rtEfiVarStoreDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
1636{
1637 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
1638 LogFlowFunc(("\n"));
1639 return VERR_NOT_SUPPORTED;
1640}
1641
1642
1643/**
1644 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
1645 */
1646static DECLCALLBACK(int) rtEfiVarStoreDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
1647 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
1648{
1649 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
1650 LogFlowFunc(("\n"));
1651 return VERR_WRITE_PROTECT;
1652}
1653
1654
1655/**
1656 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
1657 */
1658static DECLCALLBACK(int) rtEfiVarStoreDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
1659{
1660 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1661 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1662 LogFlowFunc(("\n"));
1663
1664 RT_NOREF(fType);
1665
1666 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1667 return VERR_WRITE_PROTECT;
1668
1669 if ( pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW
1670 || pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_BY_NAME
1671 || pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_GUID)
1672 return rtEfiVarStore_VarDelByName(pVarStore, pszEntry);
1673 else if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_BY_GUID)
1674 {
1675 /* Look for the name. */
1676 for (uint32_t i = 0; i < pVarStore->cGuids; i++)
1677 {
1678 PRTEFIGUID pGuid = &pVarStore->paGuids[i];
1679 char szUuid[RTUUID_STR_LENGTH];
1680 int rc = RTUuidToStr(&pGuid->Uuid, szUuid, sizeof(szUuid));
1681 AssertRC(rc); RT_NOREF(rc);
1682
1683 if (!strcmp(pszEntry, szUuid))
1684 {
1685 for (uint32_t iVar = 0; iVar < pGuid->cVars; iVar++)
1686 rtEfiVarStore_VarDelById(pVarStore, pGuid->paidxVars[iVar]);
1687
1688 if (pGuid->paidxVars)
1689 RTMemFree(pGuid->paidxVars);
1690 pGuid->paidxVars = NULL;
1691 pGuid->cVars = 0;
1692 pGuid->cVarsMax = 0;
1693 RTUuidClear(&pGuid->Uuid);
1694 return VINF_SUCCESS;
1695 }
1696 }
1697
1698 return VERR_FILE_NOT_FOUND;
1699 }
1700
1701 return VERR_NOT_SUPPORTED;
1702}
1703
1704
1705/**
1706 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
1707 */
1708static DECLCALLBACK(int) rtEfiVarStoreDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
1709{
1710 RT_NOREF(pvThis, pszEntry, fType, pszNewName);
1711 LogFlowFunc(("\n"));
1712 return VERR_WRITE_PROTECT;
1713}
1714
1715
1716/**
1717 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
1718 */
1719static DECLCALLBACK(int) rtEfiVarStoreDir_RewindDir(void *pvThis)
1720{
1721 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1722 LogFlowFunc(("\n"));
1723
1724 pThis->idxNext = 0;
1725 return VINF_SUCCESS;
1726}
1727
1728
1729/**
1730 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
1731 */
1732static DECLCALLBACK(int) rtEfiVarStoreDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
1733 RTFSOBJATTRADD enmAddAttr)
1734{
1735 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1736 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1737 LogFlowFunc(("\n"));
1738
1739 if (pThis->fNoMoreFiles)
1740 return VERR_NO_MORE_FILES;
1741
1742 int rc = VINF_SUCCESS;
1743 char aszUuid[RTUUID_STR_LENGTH];
1744 const char *pszName = NULL;
1745 size_t cbName = 0;
1746 uint64_t cbObject = 0;
1747 bool fIsDir = false;
1748 bool fNoMoreFiles = false;
1749 RTTIMESPEC Time;
1750 PCRTTIMESPEC pTimeSpec = &Time;
1751 RTTimeNow(&Time);
1752
1753 switch (pThis->pEntry->enmType)
1754 {
1755 case RTEFIVARSTOREDIRTYPE_ROOT:
1756 {
1757 if (pThis->idxNext == 0)
1758 {
1759 pszName = "by-name";
1760 cbName = sizeof("by-name");
1761 cbObject = 1;
1762 fIsDir = true;
1763 }
1764 else if (pThis->idxNext == 1)
1765 {
1766 pszName = "by-uuid";
1767 cbName = sizeof("by-uuid");
1768 cbObject = 1;
1769 fIsDir = true;
1770 }
1771 else if (pThis->idxNext == 2)
1772 {
1773 pszName = "raw";
1774 cbName = sizeof("raw");
1775 cbObject = 1;
1776 fIsDir = true;
1777 fNoMoreFiles = true;
1778 }
1779 break;
1780 }
1781 case RTEFIVARSTOREDIRTYPE_BY_NAME:
1782 case RTEFIVARSTOREDIRTYPE_RAW:
1783 {
1784 PRTEFIVAR pVar = &pVarStore->paVars[pThis->idxNext];
1785 if (pThis->idxNext + 1 == pVarStore->cVars)
1786 fNoMoreFiles = true;
1787 pszName = pVar->pszName;
1788 cbName = strlen(pszName) + 1;
1789 cbObject = pVar->cbData;
1790 pTimeSpec = &pVar->Time;
1791 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW)
1792 fIsDir = true;
1793 break;
1794 }
1795 case RTEFIVARSTOREDIRTYPE_BY_GUID:
1796 {
1797 PRTEFIGUID pGuid = &pVarStore->paGuids[pThis->idxNext];
1798 if (pThis->idxNext + 1 == pVarStore->cGuids)
1799 fNoMoreFiles = true;
1800 pszName = &aszUuid[0];
1801 cbName = sizeof(aszUuid);
1802 cbObject = 1;
1803 rc = RTUuidToStr(&pGuid->Uuid, &aszUuid[0], cbName);
1804 AssertRC(rc);
1805 break;
1806 }
1807 case RTEFIVARSTOREDIRTYPE_GUID:
1808 {
1809 PRTEFIGUID pGuid = pThis->pGuid;
1810 uint32_t idVar = pGuid->paidxVars[pThis->idxNext];
1811 PRTEFIVAR pVar = &pVarStore->paVars[idVar];
1812 if (pThis->idxNext + 1 == pGuid->cVars)
1813 fNoMoreFiles = true;
1814 pszName = pVar->pszName;
1815 cbName = strlen(pszName) + 1;
1816 cbObject = pVar->cbData;
1817 pTimeSpec = &pVar->Time;
1818 break;
1819 }
1820 case RTEFIVARSTOREDIRTYPE_RAW_ENTRY:
1821 {
1822 PCRTEFIVARSTOREFILERAWENTRY pEntry = &g_aRawFiles[pThis->idxNext];
1823 PRTEFIVAR pVar = &pVarStore->paVars[pThis->idVar];
1824
1825 if (pThis->idxNext + 1 == RT_ELEMENTS(g_aRawFiles))
1826 fNoMoreFiles = true;
1827 pszName = pEntry->pszName;
1828 cbName = strlen(pszName) + 1;
1829 cbObject = pEntry->cbObject;
1830 if (!cbObject)
1831 cbObject = pVar->cbData;
1832 pTimeSpec = &pVar->Time;
1833 break;
1834 }
1835 case RTEFIVARSTOREDIRTYPE_INVALID:
1836 default:
1837 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
1838 }
1839
1840 if (cbName <= 255)
1841 {
1842 size_t const cbDirEntry = *pcbDirEntry;
1843
1844 *pcbDirEntry = RT_UOFFSETOF_DYN(RTDIRENTRYEX, szName[cbName + 2]);
1845 if (*pcbDirEntry <= cbDirEntry)
1846 {
1847 memcpy(&pDirEntry->szName[0], pszName, cbName);
1848 pDirEntry->szName[cbName] = '\0';
1849 pDirEntry->cbName = (uint16_t)cbName;
1850 rc = rtEfiVarStore_QueryInfo(cbObject, fIsDir, pTimeSpec, &pDirEntry->Info, enmAddAttr);
1851 if (RT_SUCCESS(rc))
1852 {
1853 pThis->fNoMoreFiles = fNoMoreFiles;
1854 pThis->idxNext++;
1855 return VINF_SUCCESS;
1856 }
1857 }
1858 else
1859 rc = VERR_BUFFER_OVERFLOW;
1860 }
1861 else
1862 rc = VERR_FILENAME_TOO_LONG;
1863 return rc;
1864}
1865
1866
1867/**
1868 * EFI variable store directory operations.
1869 */
1870static const RTVFSDIROPS g_rtEfiVarStoreDirOps =
1871{
1872 { /* Obj */
1873 RTVFSOBJOPS_VERSION,
1874 RTVFSOBJTYPE_DIR,
1875 "EfiVarStore Dir",
1876 rtEfiVarStoreDir_Close,
1877 rtEfiVarStoreDir_QueryInfo,
1878 NULL,
1879 RTVFSOBJOPS_VERSION
1880 },
1881 RTVFSDIROPS_VERSION,
1882 0,
1883 { /* ObjSet */
1884 RTVFSOBJSETOPS_VERSION,
1885 RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj),
1886 rtEfiVarStoreDir_SetMode,
1887 rtEfiVarStoreDir_SetTimes,
1888 rtEfiVarStoreDir_SetOwner,
1889 RTVFSOBJSETOPS_VERSION
1890 },
1891 rtEfiVarStoreDir_Open,
1892 NULL /* pfnFollowAbsoluteSymlink */,
1893 NULL /* pfnOpenFile */,
1894 NULL /* pfnOpenDir */,
1895 rtEfiVarStoreDir_CreateDir,
1896 rtEfiVarStoreDir_OpenSymlink,
1897 rtEfiVarStoreDir_CreateSymlink,
1898 NULL /* pfnQueryEntryInfo */,
1899 rtEfiVarStoreDir_UnlinkEntry,
1900 rtEfiVarStoreDir_RenameEntry,
1901 rtEfiVarStoreDir_RewindDir,
1902 rtEfiVarStoreDir_ReadDir,
1903 RTVFSDIROPS_VERSION,
1904};
1905
1906
1907static int rtEfiVarStore_NewDirByType(PRTEFIVARSTORE pThis, RTEFIVARSTOREDIRTYPE enmDirType,
1908 PRTEFIGUID pGuid, uint32_t idVar, PRTVFSOBJ phVfsObj)
1909{
1910 RTVFSDIR hVfsDir;
1911 PRTEFIVARSTOREDIR pDir;
1912 int rc = RTVfsNewDir(&g_rtEfiVarStoreDirOps, sizeof(*pDir), 0 /*fFlags*/, pThis->hVfsSelf, NIL_RTVFSLOCK,
1913 &hVfsDir, (void **)&pDir);
1914 if (RT_SUCCESS(rc))
1915 {
1916 PCRTEFIVARSTOREDIRENTRY pEntry = NULL;
1917
1918 for (uint32_t i = 0; i < RT_ELEMENTS(g_aDirs); i++)
1919 if (g_aDirs[i].enmType == enmDirType)
1920 {
1921 pEntry = &g_aDirs[i];
1922 break;
1923 }
1924
1925 AssertPtr(pEntry);
1926 pDir->idxNext = 0;
1927 pDir->pEntry = pEntry;
1928 pDir->pVarStore = pThis;
1929 pDir->pGuid = pGuid;
1930 pDir->idVar = idVar;
1931 RTTimeNow(&pDir->Time);
1932
1933 *phVfsObj = RTVfsObjFromDir(hVfsDir);
1934 RTVfsDirRelease(hVfsDir);
1935 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
1936 }
1937
1938 return rc;
1939}
1940
1941
1942/*
1943 *
1944 * Volume level code.
1945 * Volume level code.
1946 * Volume level code.
1947 *
1948 */
1949
1950/**
1951 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
1952 */
1953static DECLCALLBACK(int) rtEfiVarStore_Close(void *pvThis)
1954{
1955 PRTEFIVARSTORE pThis = (PRTEFIVARSTORE)pvThis;
1956
1957 /* Write the variable store if in read/write mode. */
1958 if (!(pThis->fMntFlags & RTVFSMNT_F_READ_ONLY))
1959 {
1960 int rc = rtEfiVarStore_Flush(pThis);
1961 if (RT_FAILURE(rc))
1962 return rc;
1963 }
1964
1965 /*
1966 * Backing file and handles.
1967 */
1968 RTVfsFileRelease(pThis->hVfsBacking);
1969 pThis->hVfsBacking = NIL_RTVFSFILE;
1970 pThis->hVfsSelf = NIL_RTVFS;
1971 if (pThis->paVars)
1972 {
1973 for (uint32_t i = 0; i < pThis->cVars; i++)
1974 {
1975 RTStrFree(pThis->paVars[i].pszName);
1976 if (pThis->paVars[i].pvData)
1977 RTMemFree(pThis->paVars[i].pvData);
1978 }
1979
1980 RTMemFree(pThis->paVars);
1981 pThis->paVars = NULL;
1982 pThis->cVars = 0;
1983 pThis->cVarsMax = 0;
1984 }
1985
1986 if (pThis->paGuids)
1987 {
1988 for (uint32_t i = 0; i < pThis->cGuids; i++)
1989 {
1990 PRTEFIGUID pGuid = &pThis->paGuids[i];
1991
1992 if (pGuid->paidxVars)
1993 {
1994 RTMemFree(pGuid->paidxVars);
1995 pGuid->paidxVars = NULL;
1996 }
1997 }
1998
1999 RTMemFree(pThis->paGuids);
2000 pThis->paGuids = NULL;
2001 }
2002
2003 return VINF_SUCCESS;
2004}
2005
2006
2007/**
2008 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
2009 */
2010static DECLCALLBACK(int) rtEfiVarStore_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2011{
2012 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
2013 return VERR_WRONG_TYPE;
2014}
2015
2016
2017/**
2018 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnOpenRoot}
2019 */
2020static DECLCALLBACK(int) rtEfiVarStore_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
2021{
2022 PRTEFIVARSTORE pThis = (PRTEFIVARSTORE)pvThis;
2023 RTVFSOBJ hVfsObj;
2024 int rc = rtEfiVarStore_NewDirByType(pThis, RTEFIVARSTOREDIRTYPE_ROOT,
2025 NULL /*pGuid*/, 0 /*idVar*/, &hVfsObj);
2026 if (RT_SUCCESS(rc))
2027 {
2028 *phVfsDir = RTVfsObjToDir(hVfsObj);
2029 RTVfsObjRelease(hVfsObj);
2030 }
2031
2032 LogFlowFunc(("returns %Rrc\n", rc));
2033 return rc;
2034}
2035
2036
2037DECL_HIDDEN_CONST(const RTVFSOPS) g_rtEfiVarStoreOps =
2038{
2039 /* .Obj = */
2040 {
2041 /* .uVersion = */ RTVFSOBJOPS_VERSION,
2042 /* .enmType = */ RTVFSOBJTYPE_VFS,
2043 /* .pszName = */ "EfiVarStore",
2044 /* .pfnClose = */ rtEfiVarStore_Close,
2045 /* .pfnQueryInfo = */ rtEfiVarStore_QueryInfo,
2046 /* .pfnQueryInfoEx = */ NULL,
2047 /* .uEndMarker = */ RTVFSOBJOPS_VERSION
2048 },
2049 /* .uVersion = */ RTVFSOPS_VERSION,
2050 /* .fFeatures = */ 0,
2051 /* .pfnOpenRoot = */ rtEfiVarStore_OpenRoot,
2052 /* .pfnQueryRangeState = */ NULL,
2053 /* .uEndMarker = */ RTVFSOPS_VERSION
2054};
2055
2056
2057/**
2058 * Validates the given firmware header.
2059 *
2060 * @returns true if the given header is considered valid, flse otherwise.
2061 * @param pThis The EFI variable store instance.
2062 * @param pFvHdr The firmware volume header to validate.
2063 * @param poffData The offset into the backing where the data area begins.
2064 * @param pErrInfo Where to return additional error info.
2065 */
2066static int rtEfiVarStoreFvHdr_Validate(PRTEFIVARSTORE pThis, PCEFI_FIRMWARE_VOLUME_HEADER pFvHdr, uint64_t *poffData,
2067 PRTERRINFO pErrInfo)
2068{
2069#ifdef LOG_ENABLED
2070 rtEfiVarStoreFvHdr_Log(pFvHdr);
2071#endif
2072
2073 EFI_GUID GuidNvData = EFI_VARSTORE_FILESYSTEM_GUID;
2074 if (memcmp(&pFvHdr->GuidFilesystem, &GuidNvData, sizeof(GuidNvData)))
2075 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Filesystem GUID doesn't indicate a variable store");
2076 if (RT_LE2H_U64(pFvHdr->cbFv) > pThis->cbBacking)
2077 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Firmware volume length exceeds size of backing storage (truncated file?)");
2078 /* Signature was already verfied by caller. */
2079 /** @todo Check attributes. */
2080 if (pFvHdr->bRsvd != 0)
2081 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Reserved field of header is not 0");
2082 if (pFvHdr->bRevision != EFI_FIRMWARE_VOLUME_HEADER_REVISION)
2083 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Unexpected revision of the firmware volume header");
2084 if (RT_LE2H_U16(pFvHdr->offExtHdr) != 0)
2085 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Firmware volume header contains unsupported extended headers");
2086
2087 /* Start calculating the checksum of the main header. */
2088 uint16_t u16Chksum = 0;
2089 const uint16_t *pu16 = (const uint16_t *)pFvHdr;
2090 while (pu16 < (const uint16_t *)pFvHdr + (sizeof(*pFvHdr) / sizeof(uint16_t)))
2091 u16Chksum += RT_LE2H_U16(*pu16++);
2092
2093 /* Read in the block map and verify it as well. */
2094 uint64_t cbFvVol = 0;
2095 uint64_t cbFvHdr = sizeof(*pFvHdr);
2096 uint64_t offBlockMap = sizeof(*pFvHdr);
2097 for (;;)
2098 {
2099 EFI_FW_BLOCK_MAP BlockMap;
2100 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offBlockMap, &BlockMap, sizeof(BlockMap), NULL);
2101 if (RT_FAILURE(rc))
2102 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Reading block map entry from %#RX64 failed", offBlockMap);
2103
2104 cbFvHdr += sizeof(BlockMap);
2105 offBlockMap += sizeof(BlockMap);
2106
2107 /* A zero entry denotes the end. */
2108 if ( !RT_LE2H_U32(BlockMap.cBlocks)
2109 && !RT_LE2H_U32(BlockMap.cbBlock))
2110 break;
2111
2112 cbFvVol += RT_LE2H_U32(BlockMap.cBlocks) * RT_LE2H_U32(BlockMap.cbBlock);
2113
2114 pu16 = (const uint16_t *)&BlockMap;
2115 while (pu16 < (const uint16_t *)&BlockMap + (sizeof(BlockMap) / sizeof(uint16_t)))
2116 u16Chksum += RT_LE2H_U16(*pu16++);
2117 }
2118
2119 *poffData = offBlockMap;
2120
2121 if (u16Chksum)
2122 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Firmware volume header has incorrect checksum");
2123 if (RT_LE2H_U16(pFvHdr->cbFvHdr) != cbFvHdr)
2124 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Unexpected firmware volume header size");
2125
2126 return VINF_SUCCESS;
2127}
2128
2129
2130/**
2131 * Validates the given variable store header.
2132 *
2133 * @returns true if the given header is considered valid, false otherwise.
2134 * @param pThis The EFI variable store instance.
2135 * @param pHdr The variable store header to validate.
2136 * @param pfAuth Where to store whether the variable store uses authenticated variables or not.
2137 * @param pErrInfo Where to return additional error info.
2138 */
2139static int rtEfiVarStoreHdr_Validate(PRTEFIVARSTORE pThis, PCEFI_VARSTORE_HEADER pHdr, bool *pfAuth, PRTERRINFO pErrInfo)
2140{
2141#ifdef LOG_ENABLED
2142 rtEfiVarStoreHdr_Log(pHdr);
2143#endif
2144
2145 EFI_GUID GuidVarStoreAuth = EFI_VARSTORE_HEADER_GUID_AUTHENTICATED_VARIABLE;
2146 EFI_GUID GuidVarStore = EFI_VARSTORE_HEADER_GUID_VARIABLE;
2147 if (!memcmp(&pHdr->GuidVarStore, &GuidVarStoreAuth, sizeof(GuidVarStoreAuth)))
2148 *pfAuth = true;
2149 else if (!memcmp(&pHdr->GuidVarStore, &GuidVarStore, sizeof(GuidVarStore)))
2150 *pfAuth = false;
2151 else
2152 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
2153 "Variable store GUID doesn't indicate a variable store (%RTuuid)", pHdr->GuidVarStore);
2154 if (RT_LE2H_U32(pHdr->cbVarStore) >= pThis->cbBacking)
2155 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
2156 "Variable store length exceeds size of backing storage (truncated file?): %#RX32, max %#RX64",
2157 RT_LE2H_U32(pHdr->cbVarStore), pThis->cbBacking);
2158 if (pHdr->bFmt != EFI_VARSTORE_HEADER_FMT_FORMATTED)
2159 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable store is not formatted (%#x)", pHdr->bFmt);
2160 if (pHdr->bState != EFI_VARSTORE_HEADER_STATE_HEALTHY)
2161 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable store is not healthy (%#x)", pHdr->bState);
2162
2163 return VINF_SUCCESS;
2164}
2165
2166
2167/**
2168 * Validates the given authenticate variable header.
2169 *
2170 * @returns true if the given header is considered valid, false otherwise.
2171 * @param pThis The EFI variable store instance.
2172 * @param pVarHdr The variable header to validate.
2173 * @param offVar Offset of the authenticated variable header.
2174 * @param pErrInfo Where to return additional error info.
2175 */
2176static int rtEfiVarStoreAuthVar_Validate(PRTEFIVARSTORE pThis, PCEFI_AUTH_VAR_HEADER pVarHdr, uint64_t offVar, PRTERRINFO pErrInfo)
2177{
2178#ifdef LOG_ENABLED
2179 rtEfiVarStoreAuthVarHdr_Log(pVarHdr, offVar);
2180#endif
2181
2182 uint32_t cbName = RT_LE2H_U32(pVarHdr->cbName);
2183 uint32_t cbData = RT_LE2H_U32(pVarHdr->cbData);
2184 uint64_t cbVarMax = pThis->cbBacking - offVar - sizeof(*pVarHdr);
2185 if ( cbVarMax <= cbName
2186 || cbVarMax - cbName <= cbData)
2187 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable exceeds remaining space in store (cbName=%u cbData=%u cbVarMax=%llu)",
2188 cbName, cbData, cbVarMax);
2189
2190 return VINF_SUCCESS;
2191}
2192
2193
2194/**
2195 * Loads the authenticated variable at the given offset.
2196 *
2197 * @returns IPRT status code.
2198 * @retval VERR_EOF if the end of the store was reached.
2199 * @param pThis The EFI variable store instance.
2200 * @param offVar Offset of the variable to load.
2201 * @param poffVarEnd Where to store the offset pointing to the end of the variable.
2202 * @param fIgnoreDelVars Flag whether to ignore deleted variables.
2203 * @param pErrInfo Where to return additional error info.
2204 */
2205static int rtEfiVarStoreLoadAuthVar(PRTEFIVARSTORE pThis, uint64_t offVar, uint64_t *poffVarEnd,
2206 bool fIgnoreDelVars, PRTERRINFO pErrInfo)
2207{
2208 EFI_AUTH_VAR_HEADER VarHdr;
2209 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offVar, &VarHdr, sizeof(VarHdr), NULL);
2210 if (RT_FAILURE(rc))
2211 return rc;
2212
2213 rc = rtEfiVarStoreAuthVar_Validate(pThis, &VarHdr, offVar, pErrInfo);
2214 if (RT_FAILURE(rc))
2215 return rc;
2216
2217 if (poffVarEnd)
2218 *poffVarEnd = offVar + sizeof(VarHdr) + RT_LE2H_U32(VarHdr.cbData) + RT_LE2H_U32(VarHdr.cbName);
2219
2220 /* Only add complete variables or deleted variables when requested. */
2221 if ( ( fIgnoreDelVars
2222 && VarHdr.bState != EFI_AUTH_VAR_HEADER_STATE_ADDED)
2223 || VarHdr.bState == EFI_AUTH_VAR_HEADER_STATE_HDR_VALID_ONLY)
2224 return VINF_SUCCESS;
2225
2226 pThis->cbVarData += sizeof(VarHdr) + RT_LE2H_U32(VarHdr.cbData) + RT_LE2H_U32(VarHdr.cbName);
2227
2228 RTUTF16 awchName[128]; RT_ZERO(awchName);
2229 if (RT_LE2H_U32(VarHdr.cbName) > sizeof(awchName) - sizeof(RTUTF16))
2230 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable name is too long (%llu vs. %llu)\n",
2231 RT_LE2H_U32(VarHdr.cbName), sizeof(awchName));
2232
2233 rc = RTVfsFileReadAt(pThis->hVfsBacking, offVar + sizeof(VarHdr), &awchName[0], RT_LE2H_U32(VarHdr.cbName), NULL);
2234 if (RT_FAILURE(rc))
2235 return rc;
2236
2237 Log2(("Variable name '%ls'\n", &awchName[0]));
2238 rc = rtEfiVarStore_VarMaybeGrowEntries(pThis);
2239 if (RT_FAILURE(rc))
2240 return rc;
2241
2242 PRTEFIVAR pVar = &pThis->paVars[pThis->cVars++];
2243 pVar->pVarStore = pThis;
2244 if (RT_LE2H_U32(VarHdr.cbData))
2245 pVar->offVarData = offVar + sizeof(VarHdr) + RT_LE2H_U32(VarHdr.cbName);
2246 else
2247 pVar->offVarData = 0;
2248 pVar->fAttr = RT_LE2H_U32(VarHdr.fAttr);
2249 pVar->cMonotonic = RT_LE2H_U64(VarHdr.cMonotonic);
2250 pVar->idPubKey = RT_LE2H_U32(VarHdr.idPubKey);
2251 pVar->cbData = RT_LE2H_U32(VarHdr.cbData);
2252 pVar->pvData = NULL;
2253 pVar->fDeleted = false;
2254 memcpy(&pVar->EfiTimestamp, &VarHdr.Timestamp, sizeof(VarHdr.Timestamp));
2255
2256 if (VarHdr.Timestamp.u8Month)
2257 RTEfiTimeToTimeSpec(&pVar->Time, &VarHdr.Timestamp);
2258 else
2259 RTTimeNow(&pVar->Time);
2260
2261 RTEfiGuidToUuid(&pVar->Uuid, &VarHdr.GuidVendor);
2262
2263 rc = RTUtf16ToUtf8(&awchName[0], &pVar->pszName);
2264 if (RT_FAILURE(rc))
2265 pThis->cVars--;
2266
2267 rc = rtEfiVarStore_AddVarByGuid(pThis, &pVar->Uuid, pThis->cVars - 1);
2268
2269 return rc;
2270}
2271
2272
2273/**
2274 * Looks for the next variable starting at the given offset.
2275 *
2276 * @returns IPRT status code.
2277 * @retval VERR_EOF if the end of the store was reached.
2278 * @param pThis The EFI variable store instance.
2279 * @param offStart Where in the image to start looking.
2280 * @param poffVar Where to store the start of the next variable if found.
2281 */
2282static int rtEfiVarStoreFindVar(PRTEFIVARSTORE pThis, uint64_t offStart, uint64_t *poffVar)
2283{
2284 /* Try to find the ID indicating a variable start by loading data in chunks. */
2285 uint64_t offEnd = pThis->offStoreData + pThis->cbVarStore;
2286 while (offStart < offEnd)
2287 {
2288 uint16_t au16Tmp[_1K / sizeof(uint16_t)];
2289 size_t cbThisRead = RT_MIN(sizeof(au16Tmp), offEnd - offStart);
2290 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offStart, &au16Tmp[0], sizeof(au16Tmp), NULL);
2291 if (RT_FAILURE(rc))
2292 return rc;
2293
2294 for (uint32_t i = 0; i < RT_ELEMENTS(au16Tmp); i++)
2295 if (RT_LE2H_U16(au16Tmp[i]) == EFI_AUTH_VAR_HEADER_START)
2296 {
2297 *poffVar = offStart + i * sizeof(uint16_t);
2298 return VINF_SUCCESS;
2299 }
2300
2301 offStart += cbThisRead;
2302 }
2303
2304 return VERR_EOF;
2305}
2306
2307
2308/**
2309 * Loads and parses the superblock of the filesystem.
2310 *
2311 * @returns IPRT status code.
2312 * @param pThis The EFI variable store instance.
2313 * @param pErrInfo Where to return additional error info.
2314 */
2315static int rtEfiVarStoreLoad(PRTEFIVARSTORE pThis, PRTERRINFO pErrInfo)
2316{
2317 EFI_FIRMWARE_VOLUME_HEADER FvHdr;
2318 int rc = RTVfsFileReadAt(pThis->hVfsBacking, 0, &FvHdr, sizeof(FvHdr), NULL);
2319 if (RT_FAILURE(rc))
2320 return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading firmware volume header");
2321
2322 /* Validate the signature. */
2323 if (RT_LE2H_U32(FvHdr.u32Signature) != EFI_FIRMWARE_VOLUME_HEADER_SIGNATURE)
2324 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, "Not a EFI variable store - Signature mismatch: %RX32", RT_LE2H_U16(FvHdr.u32Signature));
2325
2326 uint64_t offData = 0;
2327 rc = rtEfiVarStoreFvHdr_Validate(pThis, &FvHdr, &offData, pErrInfo);
2328 if (RT_FAILURE(rc))
2329 return rc;
2330
2331 EFI_VARSTORE_HEADER StoreHdr;
2332 rc = RTVfsFileReadAt(pThis->hVfsBacking, offData, &StoreHdr, sizeof(StoreHdr), NULL);
2333 if (RT_FAILURE(rc))
2334 return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading variable store header");
2335
2336 rc = rtEfiVarStoreHdr_Validate(pThis, &StoreHdr, &pThis->fAuth, pErrInfo);
2337 if (RT_FAILURE(rc))
2338 return rc;
2339
2340 pThis->offStoreData = offData + sizeof(StoreHdr);
2341 pThis->cbVarStore = RT_LE2H_U32(StoreHdr.cbVarStore) - sizeof(StoreHdr);
2342
2343 /* Go over variables and set up the pointers. */
2344 offData = pThis->offStoreData;
2345 for (;;)
2346 {
2347 uint64_t offVar = 0;
2348
2349 rc = rtEfiVarStoreFindVar(pThis, offData, &offVar);
2350 if (RT_FAILURE(rc))
2351 break;
2352
2353 rc = rtEfiVarStoreLoadAuthVar(pThis, offVar, &offData, true /* fIgnoreDelVars*/, pErrInfo);
2354 if (RT_FAILURE(rc))
2355 break;
2356
2357 /* Align to 16bit boundary. */
2358 offData = RT_ALIGN_64(offData, 2);
2359 }
2360
2361 if (rc == VERR_EOF) /* Reached end of variable store. */
2362 rc = VINF_SUCCESS;
2363
2364 return rc;
2365}
2366
2367
2368/**
2369 * Fills the given range with 0xff to match what a real NAND flash device would return for
2370 * unwritten storage.
2371 *
2372 * @returns IPRT status code.
2373 * @param hVfsFile The VFS file handle to write to.
2374 * @param offStart The start offset to fill.
2375 * @param offEnd Offset to fill up to (exclusive).
2376 */
2377static int rtEfiVarStoreFillWithFF(RTVFSFILE hVfsFile, uint64_t offStart, uint64_t offEnd)
2378{
2379 int rc = VINF_SUCCESS;
2380 uint8_t abFF[512];
2381 memset(&abFF[0], 0xff, sizeof(abFF));
2382
2383 while ( offStart < offEnd
2384 && RT_SUCCESS(rc))
2385 {
2386 size_t cbThisWrite = RT_MIN(sizeof(abFF), offEnd - offStart);
2387 rc = RTVfsFileWriteAt(hVfsFile, offStart, &abFF[0], cbThisWrite, NULL);
2388 offStart += cbThisWrite;
2389 }
2390
2391 return rc;
2392}
2393
2394
2395RTDECL(int) RTEfiVarStoreOpenAsVfs(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fVarStoreFlags, PRTVFS phVfs, PRTERRINFO pErrInfo)
2396{
2397 AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
2398 AssertReturn(!(fMntFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
2399 AssertReturn(!fVarStoreFlags, VERR_INVALID_FLAGS);
2400
2401 uint32_t cRefs = RTVfsFileRetain(hVfsFileIn);
2402 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
2403
2404 /*
2405 * Create a VFS instance and initialize the data so rtFsExtVol_Close works.
2406 */
2407 RTVFS hVfs;
2408 PRTEFIVARSTORE pThis;
2409 int rc = RTVfsNew(&g_rtEfiVarStoreOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis);
2410 if (RT_SUCCESS(rc))
2411 {
2412 pThis->hVfsBacking = hVfsFileIn;
2413 pThis->hVfsSelf = hVfs;
2414 pThis->fMntFlags = fMntFlags;
2415 pThis->fVarStoreFlags = fVarStoreFlags;
2416
2417 rc = RTVfsFileQuerySize(pThis->hVfsBacking, &pThis->cbBacking);
2418 if (RT_SUCCESS(rc))
2419 {
2420 rc = rtEfiVarStoreLoad(pThis, pErrInfo);
2421 if (RT_SUCCESS(rc))
2422 {
2423 *phVfs = hVfs;
2424 return VINF_SUCCESS;
2425 }
2426 }
2427
2428 RTVfsRelease(hVfs);
2429 *phVfs = NIL_RTVFS;
2430 }
2431 else
2432 RTVfsFileRelease(hVfsFileIn);
2433
2434 return rc;
2435}
2436
2437
2438RTDECL(int) RTEfiVarStoreCreate(RTVFSFILE hVfsFile, uint64_t offStore, uint64_t cbStore, uint32_t fFlags, uint32_t cbBlock,
2439 PRTERRINFO pErrInfo)
2440{
2441 RT_NOREF(pErrInfo);
2442
2443 /*
2444 * Validate input.
2445 */
2446 if (!cbBlock)
2447 cbBlock = 4096;
2448 else
2449 AssertMsgReturn(cbBlock <= 8192 && RT_IS_POWER_OF_TWO(cbBlock),
2450 ("cbBlock=%#x\n", cbBlock), VERR_INVALID_PARAMETER);
2451 AssertReturn(!(fFlags & ~RTEFIVARSTORE_CREATE_F_VALID_MASK), VERR_INVALID_FLAGS);
2452
2453 if (!cbStore)
2454 {
2455 uint64_t cbFile;
2456 int rc = RTVfsFileQuerySize(hVfsFile, &cbFile);
2457 AssertRCReturn(rc, rc);
2458 AssertMsgReturn(cbFile > offStore, ("cbFile=%#RX64 offStore=%#RX64\n", cbFile, offStore), VERR_INVALID_PARAMETER);
2459 cbStore = cbFile - offStore;
2460 }
2461
2462 uint32_t cbFtw = 0;
2463 uint32_t offFtw = 0;
2464 uint32_t cbVarStore = cbStore;
2465 uint32_t cbNvEventLog = 0;
2466 uint32_t offNvEventLog = 0;
2467 if (!(fFlags & RTEFIVARSTORE_CREATE_F_NO_FTW_WORKING_SPACE))
2468 {
2469 /* Split the available space in half for the fault tolerant working area. */
2470 /** @todo Don't fully understand how these values come together right now but
2471 * we want to create NVRAM files matching the default OVMF_VARS.fd for now, see
2472 * https://github.com/tianocore/edk2/commit/b24fca05751f8222acf264853709012e0ab7bf49
2473 * for the layout.
2474 * Probably have toadd more arguments to control the different parameters.
2475 */
2476 cbNvEventLog = _4K;
2477 cbVarStore = cbStore / 2 - cbNvEventLog - _4K;
2478 cbFtw = cbVarStore + _4K;
2479 offNvEventLog = cbVarStore;
2480 offFtw = offNvEventLog + cbNvEventLog;
2481 }
2482
2483 uint32_t const cBlocks = (uint32_t)(cbStore / cbBlock);
2484
2485 EFI_GUID GuidVarStore = EFI_VARSTORE_FILESYSTEM_GUID;
2486 EFI_GUID GuidVarAuth = EFI_VARSTORE_HEADER_GUID_AUTHENTICATED_VARIABLE;
2487 EFI_FIRMWARE_VOLUME_HEADER FvHdr; RT_ZERO(FvHdr);
2488 EFI_FW_BLOCK_MAP aBlockMap[2]; RT_ZERO(aBlockMap);
2489 EFI_VARSTORE_HEADER VarStoreHdr; RT_ZERO(VarStoreHdr);
2490
2491 /* Firmware volume header. */
2492 memcpy(&FvHdr.GuidFilesystem, &GuidVarStore, sizeof(GuidVarStore));
2493 FvHdr.cbFv = RT_H2LE_U64(cbStore);
2494 FvHdr.u32Signature = RT_H2LE_U32(EFI_FIRMWARE_VOLUME_HEADER_SIGNATURE);
2495 FvHdr.fAttr = RT_H2LE_U32(0x4feff); /** @todo */
2496 FvHdr.cbFvHdr = RT_H2LE_U16(sizeof(FvHdr) + sizeof(aBlockMap));
2497 FvHdr.bRevision = EFI_FIRMWARE_VOLUME_HEADER_REVISION;
2498
2499 /* Start calculating the checksum of the main header. */
2500 uint16_t u16Chksum = 0;
2501 const uint16_t *pu16 = (const uint16_t *)&FvHdr;
2502 while (pu16 < (const uint16_t *)&FvHdr + (sizeof(FvHdr) / sizeof(uint16_t)))
2503 u16Chksum += RT_LE2H_U16(*pu16++);
2504
2505 /* Block map, the second entry remains 0 as it serves the delimiter. */
2506 aBlockMap[0].cbBlock = RT_H2LE_U32(cbBlock);
2507 aBlockMap[0].cBlocks = RT_H2LE_U32(cBlocks);
2508
2509 pu16 = (const uint16_t *)&aBlockMap[0];
2510 while (pu16 < (const uint16_t *)&aBlockMap[0] + (sizeof(aBlockMap) / (sizeof(uint16_t))))
2511 u16Chksum += RT_LE2H_U16(*pu16++);
2512
2513 FvHdr.u16Chksum = RT_H2LE_U16(UINT16_MAX - u16Chksum + 1);
2514
2515 /* Variable store header. */
2516 memcpy(&VarStoreHdr.GuidVarStore, &GuidVarAuth, sizeof(GuidVarAuth));
2517 VarStoreHdr.cbVarStore = RT_H2LE_U32(cbVarStore - sizeof(FvHdr) - sizeof(aBlockMap));
2518 VarStoreHdr.bFmt = EFI_VARSTORE_HEADER_FMT_FORMATTED;
2519 VarStoreHdr.bState = EFI_VARSTORE_HEADER_STATE_HEALTHY;
2520
2521 /* Write everything. */
2522 int rc = RTVfsFileWriteAt(hVfsFile, offStore, &FvHdr, sizeof(FvHdr), NULL);
2523 if (RT_SUCCESS(rc))
2524 rc = RTVfsFileWriteAt(hVfsFile, offStore + sizeof(FvHdr), &aBlockMap[0], sizeof(aBlockMap), NULL);
2525 if (RT_SUCCESS(rc))
2526 rc = RTVfsFileWriteAt(hVfsFile, offStore + sizeof(FvHdr) + sizeof(aBlockMap), &VarStoreHdr, sizeof(VarStoreHdr), NULL);
2527 if (RT_SUCCESS(rc))
2528 {
2529 /* Fill the remainder with 0xff as it would be the case for a real NAND flash device. */
2530 uint64_t offStart = offStore + sizeof(FvHdr) + sizeof(aBlockMap) + sizeof(VarStoreHdr);
2531 uint64_t offEnd = offStore + cbVarStore;
2532
2533 rc = rtEfiVarStoreFillWithFF(hVfsFile, offStart, offEnd);
2534 }
2535
2536 if ( RT_SUCCESS(rc)
2537 && !(fFlags & RTEFIVARSTORE_CREATE_F_NO_FTW_WORKING_SPACE))
2538 {
2539 EFI_GUID GuidFtwArea = EFI_WORKING_BLOCK_SIGNATURE_GUID;
2540 EFI_FTW_BLOCK_HEADER FtwHdr; RT_ZERO(FtwHdr);
2541
2542 memcpy(&FtwHdr.GuidSignature, &GuidFtwArea, sizeof(GuidFtwArea));
2543 FtwHdr.fWorkingBlockValid = RT_H2LE_U32(0xfffffffe); /** @todo */
2544 FtwHdr.cbWriteQueue = RT_H2LE_U64(0xfe0ULL); /* This comes from the default OVMF variable volume. */
2545 FtwHdr.u32Chksum = RTCrc32(&FtwHdr, sizeof(FtwHdr));
2546
2547 /* The area starts with the event log which defaults to 0xff. */
2548 rc = rtEfiVarStoreFillWithFF(hVfsFile, offNvEventLog, offNvEventLog + cbNvEventLog);
2549 if (RT_SUCCESS(rc))
2550 {
2551 /* Write the FTW header. */
2552 rc = RTVfsFileWriteAt(hVfsFile, offFtw, &FtwHdr, sizeof(FtwHdr), NULL);
2553 if (RT_SUCCESS(rc))
2554 rc = rtEfiVarStoreFillWithFF(hVfsFile, offFtw + sizeof(FtwHdr), offFtw + cbFtw);
2555 }
2556 }
2557
2558 return rc;
2559}
2560
2561
2562/**
2563 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
2564 */
2565static DECLCALLBACK(int) rtVfsChainEfiVarStore_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
2566 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
2567{
2568 RT_NOREF(pProviderReg);
2569
2570 /*
2571 * Basic checks.
2572 */
2573 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
2574 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
2575 if ( pElement->enmType != RTVFSOBJTYPE_VFS
2576 && pElement->enmType != RTVFSOBJTYPE_DIR)
2577 return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
2578 if (pElement->cArgs > 1)
2579 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
2580
2581 /*
2582 * Parse the flag if present, save in pElement->uProvider.
2583 */
2584 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
2585 if (pElement->cArgs > 0)
2586 {
2587 const char *psz = pElement->paArgs[0].psz;
2588 if (*psz)
2589 {
2590 if (!strcmp(psz, "ro"))
2591 fReadOnly = true;
2592 else if (!strcmp(psz, "rw"))
2593 fReadOnly = false;
2594 else
2595 {
2596 *poffError = pElement->paArgs[0].offSpec;
2597 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
2598 }
2599 }
2600 }
2601
2602 pElement->uProvider = fReadOnly ? RTVFSMNT_F_READ_ONLY : 0;
2603 return VINF_SUCCESS;
2604}
2605
2606
2607/**
2608 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
2609 */
2610static DECLCALLBACK(int) rtVfsChainEfiVarStore_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
2611 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
2612 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
2613{
2614 RT_NOREF(pProviderReg, pSpec, poffError);
2615
2616 int rc;
2617 RTVFSFILE hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
2618 if (hVfsFileIn != NIL_RTVFSFILE)
2619 {
2620 RTVFS hVfs;
2621 rc = RTEfiVarStoreOpenAsVfs(hVfsFileIn, (uint32_t)pElement->uProvider, (uint32_t)(pElement->uProvider >> 32), &hVfs, pErrInfo);
2622 RTVfsFileRelease(hVfsFileIn);
2623 if (RT_SUCCESS(rc))
2624 {
2625 *phVfsObj = RTVfsObjFromVfs(hVfs);
2626 RTVfsRelease(hVfs);
2627 if (*phVfsObj != NIL_RTVFSOBJ)
2628 return VINF_SUCCESS;
2629 rc = VERR_VFS_CHAIN_CAST_FAILED;
2630 }
2631 }
2632 else
2633 rc = VERR_VFS_CHAIN_CAST_FAILED;
2634 return rc;
2635}
2636
2637
2638/**
2639 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
2640 */
2641static DECLCALLBACK(bool) rtVfsChainEfiVarStore_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
2642 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
2643 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
2644{
2645 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
2646 if ( pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
2647 || !pReuseElement->paArgs[0].uProvider)
2648 return true;
2649 return false;
2650}
2651
2652
2653/** VFS chain element 'efivarstore'. */
2654static RTVFSCHAINELEMENTREG g_rtVfsChainEfiVarStoreReg =
2655{
2656 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
2657 /* fReserved = */ 0,
2658 /* pszName = */ "efivarstore",
2659 /* ListEntry = */ { NULL, NULL },
2660 /* pszHelp = */ "Open a EFI variable store, requires a file object on the left side.\n"
2661 "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
2662 /* pfnValidate = */ rtVfsChainEfiVarStore_Validate,
2663 /* pfnInstantiate = */ rtVfsChainEfiVarStore_Instantiate,
2664 /* pfnCanReuseElement = */ rtVfsChainEfiVarStore_CanReuseElement,
2665 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
2666};
2667
2668RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainEfiVarStoreReg, rtVfsChainEfiVarStoreReg);
2669
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use