VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp@ 66574

Last change on this file since 66574 was 66574, checked in by vboxsync, 8 years ago

fatvfs.cpp: Updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
Line 
1/* $Id: fatvfs.cpp 66574 2017-04-14 13:41:11Z vboxsync $ */
2/** @file
3 * IPRT - FAT Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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#include "internal/iprt.h"
32//#include <iprt/???.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/file.h>
38#include <iprt/err.h>
39#include <iprt/poll.h>
40#include <iprt/string.h>
41#include <iprt/thread.h>
42#include <iprt/vfs.h>
43#include <iprt/vfslowlevel.h>
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * A part of the cluster chain covering up to 252 clusters.
56 */
57typedef struct RTFSFATCHAINPART
58{
59 /** List entry. */
60 RTLISTNODE ListEntry;
61 /** Chain entries. */
62 uint32_t aEntries[256 - 4];
63} RTFSFATCHAINPART;
64AssertCompile(sizeof(RTFSFATCHAINPART) <= _1K);
65typedef RTFSFATCHAINPART *PRTFSFATCHAINPART;
66typedef RTFSFATCHAINPART const *PCRTFSFATCHAINPART;
67
68/**
69 * A FAT cluster chain.
70 */
71typedef struct RTFSFATCHAIN
72{
73 /** The chain size in bytes. */
74 uint32_t cbChain;
75 /** The chain size in entries. */
76 uint32_t cClusters;
77 /** List of chain parts (RTFSFATCHAINPART). */
78 RTLISTANCHOR ListParts;
79} RTFSFATCHAIN;
80typedef RTFSFATCHAIN *PRTFSFATCHAIN;
81
82/**
83 * FAT file system object (common part to files and dirs).
84 */
85typedef struct RTFSFATOBJ
86{
87 /** The byte offset of the directory entry.
88 * This is set to UINT64_MAX if special FAT12/16 root directory. */
89 uint64_t offDirEntry;
90 /** Attributes. */
91 RTFMODE fAttrib;
92 /** The object size. */
93 uint32_t cbObject;
94 /** The access time. */
95 RTTIMESPEC AccessTime;
96 /** The modificaton time. */
97 RTTIMESPEC ModificationTime;
98 /** The birth time. */
99 RTTIMESPEC BirthTime;
100 /** Cluster chain. */
101 RTFSFATCHAIN Clusters;
102 /** Pointer to the volume. */
103 struct RTFSFATVOL *pVol;
104} RTFSFATOBJ;
105
106typedef struct RTFSFATFILE
107{
108 /** Core FAT object info. */
109 RTFSFATOBJ Core;
110 /** The current file offset. */
111 uint32_t offFile;
112} RTFSFATFILE;
113typedef RTFSFATFILE *PRTFSFATFILE;
114
115/**
116 * FAT directory.
117 */
118typedef struct RTFSFATDIR
119{
120 /** Core FAT object info. */
121 RTFSFATOBJ Core;
122} RTFSFATDIR;
123typedef RTFSFATDIR *PRTFSFATDIR;
124
125
126/**
127 * FAT type (format).
128 */
129typedef enum RTFSFATTYPE
130{
131 RTFSFATTYPE_INVALID = 0,
132 RTFSFATTYPE_FAT12,
133 RTFSFATTYPE_FAT16,
134 RTFSFATTYPE_FAT32,
135 RTFSFATTYPE_END
136} RTFSFATTYPE;
137
138/**
139 * A FAT volume.
140 */
141typedef struct RTFSFATVOL
142{
143 /** Set if read-only mode. */
144 bool fReadOnly;
145
146 /** The cluster size in bytes. */
147 uint32_t cbCluster;
148 /** The number of data clusters. */
149 uint32_t cClusters;
150 /** The offset of the first cluster. */
151 uint64_t offFirstCluster;
152
153 /** The FAT type. */
154 RTFSFATTYPE enmFatType;
155 /** Number of FAT entries (clusters). */
156 uint32_t cFatEntries;
157 /** Number of FATs. */
158 uint32_t cFats;
159 /** FAT byte offsets. */
160 uint64_t aoffFats[8];
161
162 /** The root directory byte offset. */
163 uint64_t offRootDir;
164
165} RTFSFATVOL;
166
167
168/**
169 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
170 */
171static DECLCALLBACK(int) rtFsFatFile_Close(void *pvThis)
172{
173 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
174 RT_NOREF(pThis);
175 return VERR_NOT_IMPLEMENTED;
176}
177
178
179/**
180 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
181 */
182static DECLCALLBACK(int) rtFsFatObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
183{
184 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
185
186 pObjInfo->cbObject = pThis->Core.cbObject;
187 pObjInfo->cbAllocated = pThis->Core.Clusters.cClusters * pThis->Core.pVol->cbCluster;
188 pObjInfo->AccessTime = pThis->Core.AccessTime;
189 pObjInfo->ModificationTime = pThis->Core.ModificationTime;
190 pObjInfo->ChangeTime = pThis->Core.ModificationTime;
191 pObjInfo->BirthTime = pThis->Core.BirthTime;
192 pObjInfo->Attr.fMode = pThis->Core.fAttrib;
193 pObjInfo->Attr.enmAdditional = enmAddAttr;
194
195 switch (enmAddAttr)
196 {
197 case RTFSOBJATTRADD_NOTHING: /* fall thru */
198 case RTFSOBJATTRADD_UNIX:
199 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
200 pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
201 pObjInfo->Attr.u.Unix.cHardlinks = 1;
202 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
203 pObjInfo->Attr.u.Unix.INodeId = 0; /* Could probably use the directory entry offset. */
204 pObjInfo->Attr.u.Unix.fFlags = 0;
205 pObjInfo->Attr.u.Unix.GenerationId = 0;
206 pObjInfo->Attr.u.Unix.Device = 0;
207 break;
208 case RTFSOBJATTRADD_UNIX_OWNER:
209 pObjInfo->Attr.u.UnixOwner.uid = 0;
210 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
211 break;
212 case RTFSOBJATTRADD_UNIX_GROUP:
213 pObjInfo->Attr.u.UnixGroup.gid = 0;
214 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
215 break;
216 case RTFSOBJATTRADD_EASIZE:
217 pObjInfo->Attr.u.EASize.cb = 0;
218 break;
219 default:
220 return VERR_INVALID_PARAMETER;
221 }
222 return VINF_SUCCESS;
223}
224
225
226/**
227 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
228 */
229static DECLCALLBACK(int) rtFsFatFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
230{
231 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
232 RT_NOREF(pThis, off, pSgBuf, fBlocking, pcbRead);
233 return VERR_NOT_IMPLEMENTED;
234}
235
236
237/**
238 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
239 */
240static DECLCALLBACK(int) rtFsFatFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
241{
242 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
243 RT_NOREF(pThis, off, pSgBuf, fBlocking, pcbWritten);
244 return VERR_NOT_IMPLEMENTED;
245}
246
247
248/**
249 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
250 */
251static DECLCALLBACK(int) rtFsFatFile_Flush(void *pvThis)
252{
253 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
254 RT_NOREF(pThis);
255 return VERR_NOT_IMPLEMENTED;
256}
257
258
259/**
260 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
261 */
262static DECLCALLBACK(int) rtFsFatFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
263 uint32_t *pfRetEvents)
264{
265 NOREF(pvThis);
266 int rc;
267 if (fEvents != RTPOLL_EVT_ERROR)
268 {
269 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
270 rc = VINF_SUCCESS;
271 }
272 else if (fIntr)
273 rc = RTThreadSleep(cMillies);
274 else
275 {
276 uint64_t uMsStart = RTTimeMilliTS();
277 do
278 rc = RTThreadSleep(cMillies);
279 while ( rc == VERR_INTERRUPTED
280 && !fIntr
281 && RTTimeMilliTS() - uMsStart < cMillies);
282 if (rc == VERR_INTERRUPTED)
283 rc = VERR_TIMEOUT;
284 }
285 return rc;
286}
287
288
289/**
290 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
291 */
292static DECLCALLBACK(int) rtFsFatFile_Tell(void *pvThis, PRTFOFF poffActual)
293{
294 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
295 *poffActual = pThis->offFile;
296 return VINF_SUCCESS;
297}
298
299
300/**
301 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
302 */
303static DECLCALLBACK(int) rtFsFatObj_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
304{
305#if 0
306 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
307 if (fMask != ~RTFS_TYPE_MASK)
308 {
309 fMode |= ~fMask & ObjInfo.Attr.fMode;
310 }
311#else
312 RT_NOREF(pvThis, fMode, fMask);
313 return VERR_NOT_IMPLEMENTED;
314#endif
315}
316
317
318/**
319 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
320 */
321static DECLCALLBACK(int) rtFsFatObj_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
322 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
323{
324#if 0
325 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
326#else
327 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
328 return VERR_NOT_IMPLEMENTED;
329#endif
330}
331
332
333/**
334 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
335 */
336static DECLCALLBACK(int) rtFsFatObj_SetOwner(void *pvThis, RTUID uid, RTGID gid)
337{
338 RT_NOREF(pvThis, uid, gid);
339 return VERR_NOT_SUPPORTED;
340}
341
342
343/**
344 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
345 */
346static DECLCALLBACK(int) rtFsFatFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
347{
348 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
349 RTFOFF offNew;
350 switch (uMethod)
351 {
352 case RTFILE_SEEK_BEGIN:
353 offNew = offSeek;
354 break;
355 case RTFILE_SEEK_END:
356 offNew = (RTFOFF)pThis->Core.cbObject + offSeek;
357 break;
358 case RTFILE_SEEK_CURRENT:
359 offNew = (RTFOFF)pThis->offFile + offSeek;
360 break;
361 default:
362 return VERR_INVALID_PARAMETER;
363 }
364 if (offNew >= 0)
365 {
366 if (offNew <= _4G)
367 {
368 pThis->offFile = offNew;
369 *poffActual = offNew;
370 return VINF_SUCCESS;
371 }
372 return VERR_OUT_OF_RANGE;
373 }
374 return VERR_NEGATIVE_SEEK;
375}
376
377
378/**
379 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
380 */
381static DECLCALLBACK(int) rtFsFatFile_QuerySize(void *pvThis, uint64_t *pcbFile)
382{
383 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
384 *pcbFile = pThis->Core.cbObject;
385 return VINF_SUCCESS;
386}
387
388
389/**
390 * FAT file operations.
391 */
392DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtFsFatFileOps =
393{
394 { /* Stream */
395 { /* Obj */
396 RTVFSOBJOPS_VERSION,
397 RTVFSOBJTYPE_FILE,
398 "FatFile",
399 rtFsFatFile_Close,
400 rtFsFatObj_QueryInfo,
401 RTVFSOBJOPS_VERSION
402 },
403 RTVFSIOSTREAMOPS_VERSION,
404 0,
405 rtFsFatFile_Read,
406 rtFsFatFile_Write,
407 rtFsFatFile_Flush,
408 rtFsFatFile_PollOne,
409 rtFsFatFile_Tell,
410 NULL /*pfnSkip*/,
411 NULL /*pfnZeroFill*/,
412 RTVFSIOSTREAMOPS_VERSION,
413 },
414 RTVFSFILEOPS_VERSION,
415 0,
416 { /* ObjSet */
417 RTVFSOBJSETOPS_VERSION,
418 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
419 rtFsFatObj_SetMode,
420 rtFsFatObj_SetTimes,
421 rtFsFatObj_SetOwner,
422 RTVFSOBJSETOPS_VERSION
423 },
424 rtFsFatFile_Seek,
425 rtFsFatFile_QuerySize,
426 RTVFSFILEOPS_VERSION
427};
428
429
430/**
431 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
432 */
433static DECLCALLBACK(int) rtFsFatDir_Close(void *pvThis)
434{
435 PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis;
436 RT_NOREF(pThis);
437 return VERR_NOT_IMPLEMENTED;
438}
439
440
441/**
442 * @interface_method_impl{RTVFSOBJOPS,pfnTraversalOpen}
443 */
444static DECLCALLBACK(int) rtFsFatDir_TraversalOpen(void *pvThis, const char *pszEntry, PRTVFSDIR phVfsDir,
445 PRTVFSSYMLINK phVfsSymlink, PRTVFS phVfsMounted)
446{
447 RT_NOREF(pvThis, pszEntry, phVfsDir, phVfsSymlink, phVfsMounted);
448 return VERR_NOT_IMPLEMENTED;
449}
450
451
452/**
453 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
454 */
455static DECLCALLBACK(int) rtFsFatDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
456{
457 RT_NOREF(pvThis, pszFilename, fOpen, phVfsFile);
458 return VERR_NOT_IMPLEMENTED;
459}
460
461
462/**
463 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
464 */
465static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, PRTVFSDIR phVfsDir)
466{
467 RT_NOREF(pvThis, pszSubDir, phVfsDir);
468 return VERR_NOT_IMPLEMENTED;
469}
470
471
472/**
473 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
474 */
475static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
476{
477 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
478 return VERR_NOT_IMPLEMENTED;
479}
480
481
482/**
483 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
484 */
485static DECLCALLBACK(int) rtFsFatDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
486{
487 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
488 return VERR_NOT_SUPPORTED;
489}
490
491
492/**
493 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
494 */
495static DECLCALLBACK(int) rtFsFatDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
496 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
497{
498 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
499 return VERR_NOT_SUPPORTED;
500}
501
502
503/**
504 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
505 */
506static DECLCALLBACK(int) rtFsFatDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
507{
508 RT_NOREF(pvThis, pszEntry, fType);
509 return VERR_NOT_IMPLEMENTED;
510}
511
512
513/**
514 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
515 */
516static DECLCALLBACK(int) rtFsFatDir_RewindDir(void *pvThis)
517{
518 return VERR_NOT_IMPLEMENTED;
519}
520
521
522/**
523 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
524 */
525static DECLCALLBACK(int) rtFsFatDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
526 RTFSOBJATTRADD enmAddAttr)
527{
528 return VERR_NOT_IMPLEMENTED;
529}
530
531
532/**
533 * FAT file operations.
534 */
535static const RTVFSDIROPS g_rtFsFatDirOps =
536{
537 { /* Obj */
538 RTVFSOBJOPS_VERSION,
539 RTVFSOBJTYPE_FILE,
540 "FatDir",
541 rtFsFatDir_Close,
542 rtFsFatObj_QueryInfo,
543 RTVFSOBJOPS_VERSION
544 },
545 RTVFSDIROPS_VERSION,
546 0,
547 { /* ObjSet */
548 RTVFSOBJSETOPS_VERSION,
549 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
550 rtFsFatObj_SetMode,
551 rtFsFatObj_SetTimes,
552 rtFsFatObj_SetOwner,
553 RTVFSOBJSETOPS_VERSION
554 },
555 rtFsFatDir_TraversalOpen,
556 rtFsFatDir_OpenFile,
557 rtFsFatDir_OpenDir,
558 rtFsFatDir_CreateDir,
559 rtFsFatDir_OpenSymlink,
560 rtFsFatDir_CreateSymlink,
561 rtFsFatDir_UnlinkEntry,
562 rtFsFatDir_RewindDir,
563 rtFsFatDir_ReadDir,
564 RTVFSDIROPS_VERSION,
565};
566
567
568/**
569 * @interface_method_impl{RTVFSOPS,pfnDestroy}
570 */
571static DECLCALLBACK(void) rtFsFatVol_Destroy(void *pvThis)
572{
573}
574
575
576/**
577 * @interface_method_impl{RTVFSOPS,pfnOpenRoo}
578 */
579static DECLCALLBACK(int) rtFsFatVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
580{
581 return VERR_NOT_IMPLEMENTED;
582}
583
584
585/**
586 * @interface_method_impl{RTVFSOPS,pfnIsRangeInUse}
587 */
588static DECLCALLBACK(int) rtFsFatVol_IsRangeInUse(void *pvThis, RTFOFF off, size_t cb, bool *pfUsed)
589{
590 RT_NOREF(pvThis, off, cb, pfUsed);
591 return VERR_NOT_IMPLEMENTED;
592}
593
594
595DECL_HIDDEN_CONST(const RTVFSOPS) g_rtFsFatVolOps =
596{
597 RTVFSOPS_VERSION,
598 0 /* fFeatures */,
599 "FatVol",
600 rtFsFatVol_Destroy,
601 rtFsFatVol_OpenRoot,
602 rtFsFatVol_IsRangeInUse,
603 RTVFSOPS_VERSION
604};
605
Note: See TracBrowser for help on using the repository browser.

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