VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fs/ext2vfs.cpp@ 73502

Last change on this file since 73502 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/* $Id: ext2vfs.cpp 73097 2018-07-12 21:06:33Z vboxsync $ */
2/** @file
3 * IPRT - Ext2/3/4 Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2012-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_FS
32#include <iprt/fsvfs.h>
33
34#include <iprt/assert.h>
35#include <iprt/log.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38#include <iprt/vfs.h>
39#include <iprt/vfslowlevel.h>
40#include <iprt/formats/ext2.h>
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46/**
47 * Cached block group descriptor data.
48 */
49typedef struct RTFILESYSTEMEXTBLKGRP
50{
51 /** Start offset (in bytes and from the start of the disk). */
52 uint64_t offStart;
53 /** Last offset in the block group (inclusive). */
54 uint64_t offLast;
55 /** Block bitmap - variable in size (depends on the block size
56 * and number of blocks per group). */
57 uint8_t abBlockBitmap[1];
58} RTFILESYSTEMEXTBLKGRP;
59/** Pointer to block group descriptor data. */
60typedef RTFILESYSTEMEXTBLKGRP *PRTFILESYSTEMEXTBLKGRP;
61
62/**
63 * Ext2/3 filesystem data.
64 */
65typedef struct RTFILESYSTEMEXT
66{
67 /** VFS file handle. */
68 RTVFSFILE hVfsFile;
69 /** Block number of the superblock. */
70 uint32_t iSbBlock;
71 /** Size of one block. */
72 size_t cbBlock;
73 /** Number of blocks in one group. */
74 unsigned cBlocksPerGroup;
75 /** Number of blocks groups in the volume. */
76 unsigned cBlockGroups;
77 /** Cached block group descriptor data. */
78 PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc;
79} RTFILESYSTEMEXT;
80/** Pointer to the ext filesystem data. */
81typedef RTFILESYSTEMEXT *PRTFILESYSTEMEXT;
82
83
84
85/**
86 * Loads the block descriptor of the given block group from the medium.
87 *
88 * @returns IPRT status code.
89 * @param pThis EXT filesystem instance data.
90 * @param iBlkGrp Block group number to load.
91 */
92static int rtFsExtLoadBlkGrpDesc(PRTFILESYSTEMEXT pThis, uint32_t iBlkGrp)
93{
94 size_t cbBlockBitmap = pThis->cBlocksPerGroup / 8;
95 if (pThis->cBlocksPerGroup % 8)
96 cbBlockBitmap++;
97
98 PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc = pThis->pBlkGrpDesc;
99 if (!pBlkGrpDesc)
100 {
101 size_t cbBlkDesc = RT_UOFFSETOF_DYN(RTFILESYSTEMEXTBLKGRP, abBlockBitmap[cbBlockBitmap]);
102 pBlkGrpDesc = (PRTFILESYSTEMEXTBLKGRP)RTMemAllocZ(cbBlkDesc);
103 if (!pBlkGrpDesc)
104 return VERR_NO_MEMORY;
105 }
106
107 uint64_t offRead = (pThis->iSbBlock + 1) * pThis->cbBlock;
108 EXT2BLOCKGROUPDESC BlkDesc;
109 int rc = RTVfsFileReadAt(pThis->hVfsFile, offRead, &BlkDesc, sizeof(BlkDesc), NULL);
110 if (RT_SUCCESS(rc))
111 {
112 pBlkGrpDesc->offStart = pThis->iSbBlock + (uint64_t)iBlkGrp * pThis->cBlocksPerGroup * pThis->cbBlock;
113 pBlkGrpDesc->offLast = pBlkGrpDesc->offStart + pThis->cBlocksPerGroup * pThis->cbBlock;
114 rc = RTVfsFileReadAt(pThis->hVfsFile, BlkDesc.offBlockBitmap * pThis->cbBlock,
115 &pBlkGrpDesc->abBlockBitmap[0], cbBlockBitmap, NULL);
116 }
117
118 pThis->pBlkGrpDesc = pBlkGrpDesc;
119 return rc;
120}
121
122
123static bool rtFsExtIsBlockRangeInUse(PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc, uint32_t offBlockStart, size_t cBlocks)
124{
125 while (cBlocks)
126 {
127 uint32_t idxByte = offBlockStart / 8;
128 uint32_t iBit = offBlockStart % 8;
129
130 if (pBlkGrpDesc->abBlockBitmap[idxByte] & RT_BIT(iBit))
131 return true;
132
133 cBlocks--;
134 offBlockStart++;
135 }
136
137 return false;
138}
139
140
141/**
142 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
143 */
144static DECLCALLBACK(int) rtFsExt2Vol_Close(void *pvThis)
145{
146 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
147
148 if (pThis->pBlkGrpDesc)
149 RTMemFree(pThis->pBlkGrpDesc);
150
151 return VINF_SUCCESS;
152}
153
154
155/**
156 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
157 */
158static DECLCALLBACK(int) rtFsExt2Vol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
159{
160 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
161 return VERR_WRONG_TYPE;
162}
163
164
165/**
166 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnOpenRoot}
167 */
168static DECLCALLBACK(int) rtFsExt2_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
169{
170 NOREF(pvThis);
171 NOREF(phVfsDir);
172 return VERR_NOT_IMPLEMENTED;
173}
174
175
176/**
177 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryRangeState}
178 */
179static DECLCALLBACK(int) rtFsExt2_QueryRangeState(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)
180{
181 int rc = VINF_SUCCESS;
182 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
183
184 *pfUsed = false;
185
186 while (cb > 0)
187 {
188 uint32_t const offBlockStart = (uint32_t)(off / pThis->cbBlock);
189 uint32_t const iBlockGroup = (offBlockStart - pThis->iSbBlock) / pThis->cBlocksPerGroup;
190 uint32_t const offBlockRelStart = offBlockStart - iBlockGroup * pThis->cBlocksPerGroup;
191
192 if ( off < pThis->pBlkGrpDesc->offStart
193 || off > pThis->pBlkGrpDesc->offLast)
194 {
195 /* Load new block descriptor. */
196 rc = rtFsExtLoadBlkGrpDesc(pThis, iBlockGroup);
197 if (RT_FAILURE(rc))
198 break;
199 }
200
201 size_t cbThis = RT_MIN(cb, pThis->pBlkGrpDesc->offLast - off + 1);
202 if (rtFsExtIsBlockRangeInUse(pThis->pBlkGrpDesc,
203 offBlockRelStart,
204 cbThis / pThis->cbBlock + (cbThis % pThis->cbBlock ? 1 : 0)) )
205 {
206 *pfUsed = true;
207 break;
208 }
209
210 cb -= cbThis;
211 off += cbThis;
212 }
213
214 return rc;
215}
216
217
218DECL_HIDDEN_CONST(const RTVFSOPS) g_rtFsExt2VolOps =
219{
220 /* .Obj = */
221 {
222 /* .uVersion = */ RTVFSOBJOPS_VERSION,
223 /* .enmType = */ RTVFSOBJTYPE_VFS,
224 /* .pszName = */ "Ext2Vol",
225 /* .pfnClose = */ rtFsExt2Vol_Close,
226 /* .pfnQueryInfo = */ rtFsExt2Vol_QueryInfo,
227 /* .uEndMarker = */ RTVFSOBJOPS_VERSION
228 },
229 /* .uVersion = */ RTVFSOPS_VERSION,
230 /* .fFeatures = */ 0,
231 /* .pfnOpenRoot = */ rtFsExt2_OpenRoot,
232 /* .pfnQueryRangeState = */ rtFsExt2_QueryRangeState,
233 /* .uEndMarker = */ RTVFSOPS_VERSION
234};
235
236
237RTDECL(int) RTFsExt2VolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fExtFlags, PRTVFS phVfs, PRTERRINFO pErrInfo)
238{
239 AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
240 AssertReturn(!(fMntFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
241 AssertReturn(!fExtFlags, VERR_INVALID_FLAGS);
242
243 uint32_t cRefs = RTVfsFileRetain(hVfsFileIn);
244 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
245
246 PRTFILESYSTEMEXT pThis;
247 int rc = RTVfsNew(&g_rtFsExt2VolOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, phVfs, (void **)&pThis);
248 if (RT_SUCCESS(rc))
249 {
250 pThis->hVfsFile = hVfsFileIn;
251 pThis->pBlkGrpDesc = NULL;
252
253 EXT2SUPERBLOCK SuperBlock;
254 rc = RTVfsFileReadAt(hVfsFileIn, 1024, &SuperBlock, sizeof(EXT2SUPERBLOCK), NULL);
255 if (RT_SUCCESS(rc))
256 {
257#if defined(RT_BIGENDIAN)
258 /** @todo Convert to host endianess. */
259#endif
260 if (SuperBlock.u16FilesystemState == EXT2_STATE_ERRORS)
261 rc = RTERRINFO_LOG_SET(pErrInfo, VERR_FILESYSTEM_CORRUPT, "EXT2_STATE_ERRORS");
262 else
263 {
264 pThis->iSbBlock = SuperBlock.iBlockOfSuperblock;
265 pThis->cbBlock = 1024 << SuperBlock.cBitsShiftLeftBlockSize;
266 pThis->cBlocksPerGroup = SuperBlock.cBlocksPerGroup;
267 pThis->cBlockGroups = SuperBlock.cBlocksTotal / pThis->cBlocksPerGroup;
268
269 /* Load first block group descriptor. */
270 rc = rtFsExtLoadBlkGrpDesc(pThis, 0);
271 }
272 if (RT_SUCCESS(rc))
273 {
274 return VINF_SUCCESS;
275 }
276 }
277 else
278 rc = RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading super block");
279
280 RTVfsRelease(*phVfs);
281 *phVfs = NIL_RTVFS;
282 }
283 else
284 RTVfsFileRelease(hVfsFileIn);
285
286 return rc;
287}
288
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette