File: super.c

package info (click to toggle)
refit 0.12-2
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 2,280 kB
  • ctags: 2,663
  • sloc: ansic: 13,451; sh: 1,418; python: 631; objc: 319; makefile: 83; perl: 45
file content (162 lines) | stat: -rw-r--r-- 5,151 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * fs_ext2/super.c
 * Per-volume functions, including SimpleFileSystem interface
 *
 * Copyright (c) 2006 Christoph Pfisterer
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * See LICENSE.txt for details about the copyright status of
 * the ext2 file system driver.
 */

#include "fs_ext2.h"

#define DEBUG_LEVEL 0


// functions

EFI_STATUS EFIAPI Ext2OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
                                 OUT EFI_FILE **Root);

//
// read the superblock and setup the Simple File System interface
//

EFI_STATUS Ext2ReadSuper(IN EXT2_VOLUME_DATA *Volume)
{
    EFI_STATUS          Status;
    
    // NOTE: in the error case, the caller frees SuperBlock and BlockBuffer
    
    // read the superblock from disk
    Volume->SuperBlock = AllocatePool(sizeof(struct ext2_super_block));
    Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
                                      BLOCK_SIZE,
                                      sizeof(struct ext2_super_block),
                                      Volume->SuperBlock);
    if (EFI_ERROR(Status))
        return Status;
    
    // check the superblock
    if (Volume->SuperBlock->s_magic != EXT2_SUPER_MAGIC)
        return EFI_UNSUPPORTED;
    if (Volume->SuperBlock->s_rev_level != EXT2_GOOD_OLD_REV &&
        Volume->SuperBlock->s_rev_level != EXT2_DYNAMIC_REV)
        return EFI_UNSUPPORTED;
    if (Volume->SuperBlock->s_rev_level == EXT2_DYNAMIC_REV &&
        (Volume->SuperBlock->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
        return EFI_UNSUPPORTED;
    
    if (Volume->SuperBlock->s_rev_level == EXT2_DYNAMIC_REV &&
        (Volume->SuperBlock->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER))
        Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n");
    
    Volume->BlockSize = 1024 << Volume->SuperBlock->s_log_block_size;
    Volume->IndBlockCount = Volume->BlockSize / sizeof(__u32);
    Volume->DIndBlockCount = Volume->IndBlockCount * Volume->IndBlockCount;
    if (Volume->SuperBlock->s_rev_level == EXT2_GOOD_OLD_REV) {
        Volume->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
#if DEBUG_LEVEL
        Print(L"Ext2ReadSuper: EXT2_GOOD_OLD_REV, %d byte inodes\n", Volume->InodeSize);
#endif
    } else {
        Volume->InodeSize = Volume->SuperBlock->s_inode_size;
#if DEBUG_LEVEL
        Print(L"Ext2ReadSuper: EXT2_DYNAMIC_REV, %d byte inodes\n", Volume->InodeSize);
#endif
    }
    Volume->RootInode = NULL;
    Volume->DirInodeList = NULL;
    
    Volume->BlockBuffer = AllocatePool(Volume->BlockSize);
    Volume->BlockInBuffer = INVALID_BLOCK_NO;
    
#if DEBUG_LEVEL
    Print(L"Ext2ReadSuper: successful, BlockSize %d\n", Volume->BlockSize);
#endif
    
    // setup the SimpleFileSystem protocol
    Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION;
    Volume->FileSystem.OpenVolume = Ext2OpenVolume;
    
    return EFI_SUCCESS;
}

//
// Ext2OpenVolume
//

EFI_STATUS EFIAPI Ext2OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
                                 OUT EFI_FILE **Root)
{
    EFI_STATUS          Status;
    EXT2_VOLUME_DATA    *Volume;
    EXT2_INODE_HANDLE   InodeHandle;
    
#if DEBUG_LEVEL
    Print(L"Ext2OpenVolume\n");
#endif
    
    Volume = EXT2_VOLUME_FROM_FILE_SYSTEM(This);
    
    // open the root inode, keep it around until the FS is unmounted
    if (Volume->RootInode == NULL) {
        Status = Ext2InodeOpen(Volume, EXT2_ROOT_INO, NULL, NULL, &Volume->RootInode);
        if (EFI_ERROR(Status))
            return Status;
    }
    
    // create a new inode handle
    Status = Ext2InodeHandleReopen(Volume->RootInode, &InodeHandle);
    if (EFI_ERROR(Status))
        return Status;
    
    // wrap it in a file structure
    Status = Ext2FileFromInodeHandle(&InodeHandle, Root);
    // NOTE: file handle takes ownership of inode handle
    
    return Status;
}

//
// read given block into the volume's block buffer
//

EFI_STATUS Ext2ReadBlock(IN EXT2_VOLUME_DATA *Volume, IN UINT32 BlockNo)
{
    EFI_STATUS          Status;
    
    // check buffer
    if (BlockNo == Volume->BlockInBuffer)
        return EFI_SUCCESS;
    
#if DEBUG_LEVEL == 2
    Print(L"Ext2ReadBlock: %d\n", BlockNo);
#endif
    
    // remember buffer state
    Volume->BlockInBuffer = BlockNo;
    
    // special treatment for "holes" a.k.a. sparse files
    if (BlockNo == 0) {
        ZeroMem(Volume->BlockBuffer, Volume->BlockSize);
        return EFI_SUCCESS;
    }
    
    // read from disk
    Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
                                      (UINT64)BlockNo * Volume->BlockSize,
                                      Volume->BlockSize,
                                      Volume->BlockBuffer);
    if (EFI_ERROR(Status)) {
        Volume->BlockInBuffer = INVALID_BLOCK_NO;
        return Status;
    }
    
    return EFI_SUCCESS;
}