VirtualBox

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

Last change on this file since 69844 was 69844, checked in by vboxsync, 7 years ago

IPRT: VFS IsRangeInUse cleanup.

  • Renamed to RTVfsQueryRangeState / pfnQueryRangeState because it isn't a predicate returning a bool, but an IPRT status.
  • Changed the pfnIsRangeInUse offset parameter to uint64_t from RTFOFF since we don't want to deal with negative offset and the RTVfsIsRangeInUse API takes an unsigned value.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1/* $Id: ext2vfs.cpp 69844 2017-11-27 15:44:03Z vboxsync $ */
2/** @file
3 * IPRT Filesystem API (FileSys) - ext2/3 format.
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 int rc = VINF_SUCCESS;
95 PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc = pThis->pBlkGrpDesc;
96 uint64_t offRead = (pThis->iSbBlock + 1) * pThis->cbBlock;
97 EXT2BLOCKGROUPDESC BlkDesc;
98 size_t cbBlockBitmap;
99
100 cbBlockBitmap = pThis->cBlocksPerGroup / 8;
101 if (pThis->cBlocksPerGroup % 8)
102 cbBlockBitmap++;
103
104 if (!pBlkGrpDesc)
105 {
106 size_t cbBlkDesc = RT_OFFSETOF(RTFILESYSTEMEXTBLKGRP, abBlockBitmap[cbBlockBitmap]);
107 pBlkGrpDesc = (PRTFILESYSTEMEXTBLKGRP)RTMemAllocZ(cbBlkDesc);
108 if (!pBlkGrpDesc)
109 return VERR_NO_MEMORY;
110 }
111
112 rc = RTVfsFileReadAt(pThis->hVfsFile, offRead, &BlkDesc, sizeof(BlkDesc), NULL);
113 if (RT_SUCCESS(rc))
114 {
115 pBlkGrpDesc->offStart = pThis->iSbBlock + (uint64_t)iBlkGrp * pThis->cBlocksPerGroup * pThis->cbBlock;
116 pBlkGrpDesc->offLast = pBlkGrpDesc->offStart + pThis->cBlocksPerGroup * pThis->cbBlock;
117 rc = RTVfsFileReadAt(pThis->hVfsFile, BlkDesc.offBlockBitmap * pThis->cbBlock,
118 &pBlkGrpDesc->abBlockBitmap[0], cbBlockBitmap, NULL);
119 }
120
121 pThis->pBlkGrpDesc = pBlkGrpDesc;
122
123 return rc;
124}
125
126static bool rtFsExtIsBlockRangeInUse(PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc, uint32_t offBlockStart, size_t cBlocks)
127{
128 bool fUsed = false;
129
130 while (cBlocks)
131 {
132 uint32_t idxByte = offBlockStart / 8;
133 uint32_t iBit = offBlockStart % 8;
134
135 if (pBlkGrpDesc->abBlockBitmap[idxByte] & RT_BIT(iBit))
136 {
137 fUsed = true;
138 break;
139 }
140
141 cBlocks--;
142 offBlockStart++;
143 }
144
145 return fUsed;
146}
147
148
149/**
150 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
151 */
152static DECLCALLBACK(int) rtFsExt2Vol_Close(void *pvThis)
153{
154 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
155
156 if (pThis->pBlkGrpDesc)
157 RTMemFree(pThis->pBlkGrpDesc);
158
159 return VINF_SUCCESS;
160}
161
162
163/**
164 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
165 */
166static DECLCALLBACK(int) rtFsExt2Vol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
167{
168 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
169 return VERR_WRONG_TYPE;
170}
171
172
173/**
174 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnOpenRoot}
175 */
176static DECLCALLBACK(int) rtFsExt2_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
177{
178 NOREF(pvThis);
179 NOREF(phVfsDir);
180 return VERR_NOT_IMPLEMENTED;
181}
182
183
184/**
185 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryRangeState}
186 */
187static DECLCALLBACK(int) rtFsExt2_QueryRangeState(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)
188{
189 int rc = VINF_SUCCESS;
190 uint64_t offStart = (uint64_t)off;
191 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
192
193 *pfUsed = false;
194
195 while (cb > 0)
196 {
197 bool fUsed;
198 uint32_t offBlockStart = (uint32_t)(offStart / pThis->cbBlock);
199 uint32_t iBlockGroup = (offBlockStart - pThis->iSbBlock) / pThis->cBlocksPerGroup;
200 uint32_t offBlockRelStart = offBlockStart - iBlockGroup * pThis->cBlocksPerGroup;
201 size_t cbThis = 0;
202
203 if ( offStart < pThis->pBlkGrpDesc->offStart
204 || offStart > pThis->pBlkGrpDesc->offLast)
205 {
206 /* Load new block descriptor. */
207 rc = rtFsExtLoadBlkGrpDesc(pThis, iBlockGroup);
208 if (RT_FAILURE(rc))
209 break;
210 }
211
212 cbThis = RT_MIN(cb, pThis->pBlkGrpDesc->offLast - offStart + 1);
213 fUsed = rtFsExtIsBlockRangeInUse(pThis->pBlkGrpDesc, offBlockRelStart,
214 cbThis / pThis->cbBlock +
215 (cbThis % pThis->cbBlock ? 1 : 0));
216
217 if (fUsed)
218 {
219 *pfUsed = true;
220 break;
221 }
222
223 cb -= cbThis;
224 offStart += cbThis;
225 }
226
227 return rc;
228}
229
230
231DECL_HIDDEN_CONST(const RTVFSOPS) g_rtFsExt2VolOps =
232{
233 /* .Obj = */
234 {
235 /* .uVersion = */ RTVFSOBJOPS_VERSION,
236 /* .enmType = */ RTVFSOBJTYPE_VFS,
237 /* .pszName = */ "Ext2Vol",
238 /* .pfnClose = */ rtFsExt2Vol_Close,
239 /* .pfnQueryInfo = */ rtFsExt2Vol_QueryInfo,
240 /* .uEndMarker = */ RTVFSOBJOPS_VERSION
241 },
242 /* .uVersion = */ RTVFSOPS_VERSION,
243 /* .fFeatures = */ 0,
244 /* .pfnOpenRoot = */ rtFsExt2_OpenRoot,
245 /* .pfnQueryRangeState = */ rtFsExt2_QueryRangeState,
246 /* .uEndMarker = */ RTVFSOPS_VERSION
247};
248
249
250RTDECL(int) RTFsExt2VolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fExtFlags, PRTVFS phVfs, PRTERRINFO pErrInfo)
251{
252 AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
253 AssertReturn(!(fMntFlags & RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
254 AssertReturn(!fExtFlags, VERR_INVALID_FLAGS);
255
256 uint32_t cRefs = RTVfsFileRetain(hVfsFileIn);
257 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
258
259 PRTFILESYSTEMEXT pThis;
260 int rc = RTVfsNew(&g_rtFsExt2VolOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, phVfs, (void **)&pThis);
261 if (RT_SUCCESS(rc))
262 {
263 pThis->hVfsFile = hVfsFileIn;
264 pThis->pBlkGrpDesc = NULL;
265
266 EXT2SUPERBLOCK SuperBlock;
267 rc = RTVfsFileReadAt(hVfsFileIn, 1024, &SuperBlock, sizeof(EXT2SUPERBLOCK), NULL);
268 if (RT_SUCCESS(rc))
269 {
270#if defined(RT_BIGENDIAN)
271 /** @todo Convert to host endianess. */
272#endif
273 if (SuperBlock.u16FilesystemState == EXT2_STATE_ERRORS)
274 rc = RTERRINFO_LOG_SET(pErrInfo, VERR_FILESYSTEM_CORRUPT, "EXT2_STATE_ERRORS");
275 else
276 {
277 pThis->iSbBlock = SuperBlock.iBlockOfSuperblock;
278 pThis->cbBlock = 1024 << SuperBlock.cBitsShiftLeftBlockSize;
279 pThis->cBlocksPerGroup = SuperBlock.cBlocksPerGroup;
280 pThis->cBlockGroups = SuperBlock.cBlocksTotal / pThis->cBlocksPerGroup;
281
282 /* Load first block group descriptor. */
283 rc = rtFsExtLoadBlkGrpDesc(pThis, 0);
284 }
285 if (RT_SUCCESS(rc))
286 {
287 return VINF_SUCCESS;
288 }
289 }
290 else
291 rc = RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading super block");
292
293 RTVfsRelease(*phVfs);
294 *phVfs = NIL_RTVFS;
295 }
296 else
297 RTVfsFileRelease(hVfsFileIn);
298
299 return rc;
300}
301
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