VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/filesystem/filesystemext.cpp@ 58591

Last change on this file since 58591 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1/* $Id: filesystemext.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT Filesystem API (FileSys) - ext2/3 format.
4 */
5
6/*
7 * Copyright (C) 2012-2015 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 LOG_GROUP_DEFAULT
32#include <iprt/types.h>
33#include <iprt/assert.h>
34#include <iprt/mem.h>
35#include <iprt/filesystem.h>
36#include <iprt/string.h>
37#include <iprt/vfs.h>
38#include "internal/filesystem.h"
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44
45/*
46 * The filesystem structures are from http://wiki.osdev.org/Ext2 and
47 * http://www.nongnu.org/ext2-doc/ext2.html
48 */
49
50/**
51 * Ext superblock.
52 *
53 * Everything is stored little endian on the disk.
54 */
55#pragma pack(1)
56typedef struct ExtSuperBlock
57{
58 /** Total number of inodes in the filesystem. */
59 uint32_t cInodesTotal;
60 /** Total number of blocks in the filesystem. */
61 uint32_t cBlocksTotal;
62 /** Number of blocks reserved for the super user. */
63 uint32_t cBlocksRsvdForSuperUser;
64 /** Total number of unallocated blocks. */
65 uint32_t cBlocksUnallocated;
66 /** Total number of unallocated inodes. */
67 uint32_t cInodesUnallocated;
68 /** Block number of block containing the superblock. */
69 uint32_t iBlockOfSuperblock;
70 /** Number of bits to shift 1024 to the left to get the block size */
71 uint32_t cBitsShiftLeftBlockSize;
72 /** Number of bits to shift 1024 to the left to get the fragment size */
73 uint32_t cBitsShiftLeftFragmentSize;
74 /** Number of blocks in each block group. */
75 uint32_t cBlocksPerGroup;
76 /** Number of fragments in each block group. */
77 uint32_t cFragmentsPerBlockGroup;
78 /** Number of inodes in each block group. */
79 uint32_t cInodesPerBlockGroup;
80 /** Last mount time. */
81 uint32_t u32LastMountTime;
82 /** Last written time. */
83 uint32_t u32LastWrittenTime;
84 /** Number of times the volume was mounted since the last check. */
85 uint16_t cMountsSinceLastCheck;
86 /** Number of mounts allowed before a consistency check. */
87 uint16_t cMaxMountsUntilCheck;
88 /** Signature to identify a ext2 volume. */
89 uint16_t u16Signature;
90 /** State of the filesystem (clean/errors) */
91 uint16_t u16FilesystemState;
92 /** What to do on an error. */
93 uint16_t u16ActionOnError;
94 /** Minor version field. */
95 uint16_t u16VersionMinor;
96 /** Time of last check. */
97 uint32_t u32LastCheckTime;
98 /** Interval between consistency checks. */
99 uint32_t u32CheckInterval;
100 /** Operating system ID of the filesystem creator. */
101 uint32_t u32OsIdCreator;
102 /** Major version field. */
103 uint32_t u32VersionMajor;
104 /** User ID that is allowed to use reserved blocks. */
105 uint16_t u16UidReservedBlocks;
106 /** Group ID that is allowed to use reserved blocks. */
107 uint16_t u16GidReservedBlocks;
108 /** Reserved fields. */
109 uint8_t abReserved[940];
110} ExtSuperBlock;
111#pragma pack()
112AssertCompileSize(ExtSuperBlock, 1024);
113/** Pointer to an ext super block. */
114typedef ExtSuperBlock *PExtSuperBlock;
115
116/** Ext2 signature. */
117#define RTFILESYSTEM_EXT2_SIGNATURE (0xef53)
118/** Clean filesystem state. */
119#define RTFILESYSTEM_EXT2_STATE_CLEAN (0x0001)
120/** Error filesystem state. */
121#define RTFILESYSTEM_EXT2_STATE_ERRORS (0x0002)
122
123/**
124 * Block group descriptor.
125 */
126#pragma pack(1)
127typedef struct BlockGroupDesc
128{
129 /** Block address of the block bitmap. */
130 uint32_t offBlockBitmap;
131 /** Block address of the inode bitmap. */
132 uint32_t offInodeBitmap;
133 /** Start block address of the inode table. */
134 uint32_t offInodeTable;
135 /** Number of unallocated blocks in group. */
136 uint16_t cBlocksUnallocated;
137 /** Number of unallocated inodes in group. */
138 uint16_t cInodesUnallocated;
139 /** Number of directories in the group. */
140 uint16_t cDirectories;
141 /** Padding. */
142 uint16_t u16Padding;
143 /** Reserved. */
144 uint8_t abReserved[12];
145} BlockGroupDesc;
146#pragma pack()
147AssertCompileSize(BlockGroupDesc, 32);
148/** Pointer to an ext block group descriptor. */
149typedef BlockGroupDesc *PBlockGroupDesc;
150
151/**
152 * Cached block group descriptor data.
153 */
154typedef struct RTFILESYSTEMEXTBLKGRP
155{
156 /** Start offset (in bytes and from the start of the disk). */
157 uint64_t offStart;
158 /** Last offset in the block group (inclusive). */
159 uint64_t offLast;
160 /** Block bitmap - variable in size (depends on the block size
161 * and number of blocks per group). */
162 uint8_t abBlockBitmap[1];
163} RTFILESYSTEMEXTBLKGRP;
164/** Pointer to block group descriptor data. */
165typedef RTFILESYSTEMEXTBLKGRP *PRTFILESYSTEMEXTBLKGRP;
166
167/**
168 * Ext2/3 filesystem data.
169 */
170typedef struct RTFILESYSTEMEXT
171{
172 /** VFS file handle. */
173 RTVFSFILE hVfsFile;
174 /** Block number of the superblock. */
175 uint32_t iSbBlock;
176 /** Size of one block. */
177 size_t cbBlock;
178 /** Number of blocks in one group. */
179 unsigned cBlocksPerGroup;
180 /** Number of blocks groups in the volume. */
181 unsigned cBlockGroups;
182 /** Cached block group descriptor data. */
183 PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc;
184} RTFILESYSTEMEXT;
185/** Pointer to the ext filesystem data. */
186typedef RTFILESYSTEMEXT *PRTFILESYSTEMEXT;
187
188
189/*********************************************************************************************************************************
190* Methods *
191*********************************************************************************************************************************/
192
193/**
194 * Loads the block descriptor of the given block group from the medium.
195 *
196 * @returns IPRT status code.
197 * @param pThis EXT filesystem instance data.
198 * @param iBlkGrp Block group number to load.
199 */
200static int rtFsExtLoadBlkGrpDesc(PRTFILESYSTEMEXT pThis, uint32_t iBlkGrp)
201{
202 int rc = VINF_SUCCESS;
203 PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc = pThis->pBlkGrpDesc;
204 uint64_t offRead = (pThis->iSbBlock + 1) * pThis->cbBlock;
205 BlockGroupDesc BlkDesc;
206 size_t cbBlockBitmap;
207
208 cbBlockBitmap = pThis->cBlocksPerGroup / 8;
209 if (pThis->cBlocksPerGroup % 8)
210 cbBlockBitmap++;
211
212 if (!pBlkGrpDesc)
213 {
214 size_t cbBlkDesc = RT_OFFSETOF(RTFILESYSTEMEXTBLKGRP, abBlockBitmap[cbBlockBitmap]);
215 pBlkGrpDesc = (PRTFILESYSTEMEXTBLKGRP)RTMemAllocZ(cbBlkDesc);
216 if (!pBlkGrpDesc)
217 return VERR_NO_MEMORY;
218 }
219
220 rc = RTVfsFileReadAt(pThis->hVfsFile, offRead, &BlkDesc, sizeof(BlkDesc), NULL);
221 if (RT_SUCCESS(rc))
222 {
223 pBlkGrpDesc->offStart = pThis->iSbBlock + (uint64_t)iBlkGrp * pThis->cBlocksPerGroup * pThis->cbBlock;
224 pBlkGrpDesc->offLast = pBlkGrpDesc->offStart + pThis->cBlocksPerGroup * pThis->cbBlock;
225 rc = RTVfsFileReadAt(pThis->hVfsFile, BlkDesc.offBlockBitmap * pThis->cbBlock,
226 &pBlkGrpDesc->abBlockBitmap[0], cbBlockBitmap, NULL);
227 }
228
229 pThis->pBlkGrpDesc = pBlkGrpDesc;
230
231 return rc;
232}
233
234static bool rtFsExtIsBlockRangeInUse(PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc,
235 uint32_t offBlockStart, size_t cBlocks)
236{
237 bool fUsed = false;
238
239 while (cBlocks)
240 {
241 uint32_t idxByte = offBlockStart / 8;
242 uint32_t iBit = offBlockStart % 8;
243
244 if (pBlkGrpDesc->abBlockBitmap[idxByte] & RT_BIT(iBit))
245 {
246 fUsed = true;
247 break;
248 }
249
250 cBlocks--;
251 offBlockStart++;
252 }
253
254 return fUsed;
255}
256
257
258static DECLCALLBACK(int) rtFsExtProbe(RTVFSFILE hVfsFile, uint32_t *puScore)
259{
260 int rc = VINF_SUCCESS;
261 uint64_t cbMedium = 0;
262
263 *puScore = RTFILESYSTEM_MATCH_SCORE_UNSUPPORTED;
264
265 rc = RTVfsFileGetSize(hVfsFile, &cbMedium);
266 if (RT_SUCCESS(rc))
267 {
268 if (cbMedium >= 2*sizeof(ExtSuperBlock))
269 {
270 ExtSuperBlock SuperBlock;
271
272 rc = RTVfsFileReadAt(hVfsFile, 1024, &SuperBlock, sizeof(ExtSuperBlock), NULL);
273 if (RT_SUCCESS(rc))
274 {
275#if defined(RT_BIGENDIAN)
276 /** @todo: Convert to host endianess. */
277#endif
278 if (SuperBlock.u16Signature == RTFILESYSTEM_EXT2_SIGNATURE)
279 *puScore = RTFILESYSTEM_MATCH_SCORE_SUPPORTED;
280 }
281 }
282 }
283
284 return rc;
285}
286
287static DECLCALLBACK(int) rtFsExtInit(void *pvThis, RTVFSFILE hVfsFile)
288{
289 int rc = VINF_SUCCESS;
290 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
291 ExtSuperBlock SuperBlock;
292
293 pThis->hVfsFile = hVfsFile;
294 pThis->pBlkGrpDesc = NULL;
295
296 rc = RTVfsFileReadAt(hVfsFile, 1024, &SuperBlock, sizeof(ExtSuperBlock), NULL);
297 if (RT_SUCCESS(rc))
298 {
299#if defined(RT_BIGENDIAN)
300 /** @todo: Convert to host endianess. */
301#endif
302 if (SuperBlock.u16FilesystemState == RTFILESYSTEM_EXT2_STATE_ERRORS)
303 rc = VERR_FILESYSTEM_CORRUPT;
304 else
305 {
306 pThis->iSbBlock = SuperBlock.iBlockOfSuperblock;
307 pThis->cbBlock = 1024 << SuperBlock.cBitsShiftLeftBlockSize;
308 pThis->cBlocksPerGroup = SuperBlock.cBlocksPerGroup;
309 pThis->cBlockGroups = SuperBlock.cBlocksTotal / pThis->cBlocksPerGroup;
310
311 /* Load first block group descriptor. */
312 rc = rtFsExtLoadBlkGrpDesc(pThis, 0);
313 }
314 }
315
316 return rc;
317}
318
319static DECLCALLBACK(void) rtFsExtDestroy(void *pvThis)
320{
321 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
322
323 if (pThis->pBlkGrpDesc)
324 RTMemFree(pThis->pBlkGrpDesc);
325}
326
327static DECLCALLBACK(int) rtFsExtOpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
328{
329 NOREF(pvThis);
330 NOREF(phVfsDir);
331 return VERR_NOT_IMPLEMENTED;
332}
333
334static DECLCALLBACK(int) rtFsExtIsRangeInUse(void *pvThis, RTFOFF off, size_t cb,
335 bool *pfUsed)
336{
337 int rc = VINF_SUCCESS;
338 uint64_t offStart = (uint64_t)off;
339 PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
340
341 *pfUsed = false;
342
343 while (cb > 0)
344 {
345 bool fUsed;
346 uint32_t offBlockStart = (uint32_t)(offStart / pThis->cbBlock);
347 uint32_t iBlockGroup = (offBlockStart - pThis->iSbBlock) / pThis->cBlocksPerGroup;
348 uint32_t offBlockRelStart = offBlockStart - iBlockGroup * pThis->cBlocksPerGroup;
349 size_t cbThis = 0;
350
351 if ( offStart < pThis->pBlkGrpDesc->offStart
352 || offStart > pThis->pBlkGrpDesc->offLast)
353 {
354 /* Load new block descriptor. */
355 rc = rtFsExtLoadBlkGrpDesc(pThis, iBlockGroup);
356 if (RT_FAILURE(rc))
357 break;
358 }
359
360 cbThis = RT_MIN(cb, pThis->pBlkGrpDesc->offLast - offStart + 1);
361 fUsed = rtFsExtIsBlockRangeInUse(pThis->pBlkGrpDesc, offBlockRelStart,
362 cbThis / pThis->cbBlock +
363 (cbThis % pThis->cbBlock ? 1 : 0));
364
365 if (fUsed)
366 {
367 *pfUsed = true;
368 break;
369 }
370
371 cb -= cbThis;
372 offStart += cbThis;
373 }
374
375 return rc;
376}
377
378DECL_HIDDEN_CONST(RTFILESYSTEMDESC) const g_rtFsExt =
379{
380 /** cbFs */
381 sizeof(RTFILESYSTEMEXT),
382 /** VfsOps */
383 {
384 /** uVersion. */
385 RTVFSOPS_VERSION,
386 /** fFeatures */
387 0,
388 /** pszName */
389 "ExtVfsOps",
390 /** pfnDestroy */
391 rtFsExtDestroy,
392 /** pfnOpenRoot */
393 rtFsExtOpenRoot,
394 /** pfnIsRangeInUse */
395 rtFsExtIsRangeInUse,
396 /** uEndMarker */
397 RTVFSOPS_VERSION
398 },
399 /** pfnProbe */
400 rtFsExtProbe,
401 /** pfnInit */
402 rtFsExtInit
403};
404
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