~ubuntu-branches/ubuntu/vivid/parted/vivid

« back to all changes in this revision

Viewing changes to libparted/fs/ext2/ext2.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-07-21 10:23:16 UTC
  • mfrom: (7.2.32 sid)
  • Revision ID: package-import@ubuntu.com-20140721102316-jsyv3yzmbo8vlde5
Tags: 3.1-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    ext2.c -- generic ext2 stuff
3
 
    Copyright (C) 1998-2001, 2007, 2009-2010 Free Software Foundation,
4
 
    Inc.
5
 
 
6
 
    This program is free software; you can redistribute it and/or modify
7
 
    it under the terms of the GNU General Public License as published by
8
 
    the Free Software Foundation; either version 3 of the License, or
9
 
    (at your option) any later version.
10
 
 
11
 
    This program is distributed in the hope that it will be useful,
12
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
    GNU General Public License for more details.
15
 
 
16
 
    You should have received a copy of the GNU General Public License
17
 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
*/
19
 
 
20
 
#include <config.h>
21
 
 
22
 
#ifndef DISCOVER_ONLY
23
 
 
24
 
#include <stdio.h>
25
 
#include <stdlib.h>
26
 
#include <string.h>
27
 
#include <time.h>
28
 
#include <uuid/uuid.h>
29
 
#include "ext2.h"
30
 
 
31
 
/* ext2 stuff ****************************************************************/
32
 
 
33
 
unsigned char _bitmap[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
34
 
 
35
 
int ext2_copy_block(struct ext2_fs *fs, blk_t from, blk_t to)
36
 
{
37
 
        unsigned char* buf = ped_malloc (fs->blocksize);
38
 
 
39
 
        if (!ext2_bcache_flush(fs, from)) return 0;
40
 
        if (!ext2_bcache_flush(fs, to)) return 0;
41
 
 
42
 
        if (!ext2_read_blocks(fs, buf, from, 1)) return 0;
43
 
        if (!ext2_write_blocks(fs, buf, to, 1)) return 0;
44
 
 
45
 
        return 1;
46
 
}
47
 
 
48
 
int ext2_get_block_state(struct ext2_fs *fs, blk_t block)
49
 
{
50
 
        struct ext2_buffer_head *bh;
51
 
        int group;
52
 
        int offset;
53
 
        int state;
54
 
 
55
 
        block -= EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
56
 
        group = block / EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
57
 
        offset = block % EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
58
 
 
59
 
        bh = ext2_bread(fs, EXT2_GROUP_BLOCK_BITMAP(fs->gd[group]));
60
 
        state = bh->data[offset>>3] & _bitmap[offset&7];
61
 
        ext2_brelse(bh, 0);
62
 
 
63
 
        return state;
64
 
}
65
 
 
66
 
blk_t ext2_find_free_block(struct ext2_fs *fs)
67
 
{
68
 
        int i;
69
 
 
70
 
        for (i=0;i<fs->numgroups;i++)
71
 
                if (EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[i]))
72
 
                {
73
 
                        blk_t j;
74
 
                        blk_t offset;
75
 
 
76
 
                        offset = i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb)
77
 
                                 + EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
78
 
                        for (j=fs->adminblocks;
79
 
                             j<EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
80
 
                             j++)
81
 
                                if (ext2_is_data_block(fs, offset + j) &&
82
 
                                    !ext2_get_block_state(fs, offset + j))
83
 
                                        return offset + j;
84
 
 
85
 
                        ped_exception_throw (PED_EXCEPTION_ERROR,
86
 
                                PED_EXCEPTION_CANCEL,
87
 
                                _("Inconsistent group descriptors!"));
88
 
                }
89
 
 
90
 
        ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
91
 
                             _("File system full!"));
92
 
        return 0;
93
 
}
94
 
 
95
 
ino_t ext2_find_free_inode(struct ext2_fs *fs)
96
 
{
97
 
        int i;
98
 
 
99
 
        for (i=0;i<fs->numgroups;i++)
100
 
                if (EXT2_GROUP_FREE_INODES_COUNT(fs->gd[i]))
101
 
                {
102
 
                        ino_t j;
103
 
                        ino_t offset;
104
 
 
105
 
                        offset = i * EXT2_SUPER_INODES_PER_GROUP(fs->sb) + 1;
106
 
                        for (j=0;j<EXT2_SUPER_INODES_PER_GROUP(fs->sb);j++)
107
 
                                if (!ext2_get_inode_state(fs, offset + j))
108
 
                                        return offset + j;
109
 
 
110
 
                        ped_exception_throw (PED_EXCEPTION_ERROR,
111
 
                                PED_EXCEPTION_CANCEL,
112
 
                                _("Inconsistent group descriptors!"));
113
 
                }
114
 
 
115
 
        ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
116
 
                             _("File system full!"));
117
 
        return 0;
118
 
}
119
 
 
120
 
int ext2_move_blocks(struct ext2_fs *fs, blk_t src, blk_t num, blk_t dest)
121
 
{
122
 
        unsigned char *buf;
123
 
        blk_t i;
124
 
 
125
 
        ped_exception_fetch_all();
126
 
        if ((buf = ped_malloc(num << fs->logsize)) != NULL)
127
 
        {
128
 
                ped_exception_leave_all();
129
 
 
130
 
                if (!ext2_bcache_flush_range(fs, src, num)) return 0;
131
 
                if (!ext2_bcache_flush_range(fs, dest, num)) return 0;
132
 
 
133
 
                if (!ext2_read_blocks(fs, buf, src, num)) return 0;
134
 
                if (!ext2_write_blocks(fs, buf, dest, num)) return 0;
135
 
 
136
 
                free(buf);
137
 
                return 1;
138
 
        }
139
 
        ped_exception_catch();
140
 
        ped_exception_leave_all();
141
 
 
142
 
        if (src > dest)
143
 
        {
144
 
                for (i=0;i<num;i++)
145
 
                        if (!ext2_copy_block(fs, src+i, dest+i))
146
 
                                return 0;
147
 
        }
148
 
        else
149
 
        {
150
 
                for (i=num;i>0;i--)
151
 
                        if (!ext2_copy_block(fs, src+i, dest+i))
152
 
                                return 0;
153
 
        }
154
 
        return 1;
155
 
}
156
 
 
157
 
int ext2_read_blocks(struct ext2_fs *fs, void *ptr, blk_t block, blk_t num)
158
 
{
159
 
        return fs->devhandle->ops->read(fs->devhandle->cookie, ptr, block, num);
160
 
}
161
 
 
162
 
int ext2_set_block_state(struct ext2_fs *fs, blk_t block, int state, int updatemetadata)
163
 
{
164
 
        struct ext2_buffer_head *bh;
165
 
        int                      group;
166
 
        int                      offset;
167
 
 
168
 
        block -= EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
169
 
        group = block / EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
170
 
        offset = block % EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
171
 
 
172
 
        bh = ext2_bread(fs, EXT2_GROUP_BLOCK_BITMAP(fs->gd[group]));
173
 
        bh->dirty = 1;
174
 
        if (state)
175
 
                bh->data[offset>>3] |= _bitmap[offset&7];
176
 
        else
177
 
                bh->data[offset>>3] &= ~_bitmap[offset&7];
178
 
        ext2_brelse(bh, 0);
179
 
 
180
 
        if (updatemetadata)
181
 
        {
182
 
                int diff;
183
 
 
184
 
                diff = state ? -1 : 1;
185
 
 
186
 
                fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16
187
 
                        (EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group]) + diff);
188
 
                ext2_super_free_blocks_count_set(&fs->sb,
189
 
                        EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) + diff);
190
 
                fs->metadirty |= EXT2_META_SB | EXT2_META_GD;
191
 
        }
192
 
        return 1;
193
 
}
194
 
 
195
 
int ext2_write_blocks(struct ext2_fs *fs, void *ptr, blk_t block, blk_t num)
196
 
{
197
 
        return fs->devhandle->ops->write(fs->devhandle->cookie, ptr, block, num);
198
 
}
199
 
 
200
 
int ext2_zero_blocks(struct ext2_fs *fs, blk_t block, blk_t num)
201
 
{
202
 
        unsigned char *buf;
203
 
        blk_t i;
204
 
 
205
 
        ped_exception_fetch_all();
206
 
        buf = ped_malloc (num << fs->logsize);
207
 
        if (buf)
208
 
        {
209
 
                ped_exception_leave_all();
210
 
 
211
 
                memset(buf, 0, num << fs->logsize);
212
 
                if (!ext2_bcache_flush_range(fs, block, num))
213
 
                        goto error_free_buf;
214
 
                if (!ext2_write_blocks(fs, buf, block, num))
215
 
                        goto error_free_buf;
216
 
                free(buf);
217
 
                return 1;
218
 
        }
219
 
        ped_exception_catch();
220
 
 
221
 
        buf = ped_malloc (fs->blocksize);
222
 
        if (buf)
223
 
        {
224
 
                ped_exception_leave_all();
225
 
 
226
 
                memset(buf, 0, fs->blocksize);
227
 
 
228
 
                for (i=0;i<num;i++)
229
 
                {
230
 
                        if (!ext2_bcache_flush(fs, block+i))
231
 
                                goto error_free_buf;
232
 
                        if (!ext2_write_blocks(fs, buf, block+i, 1))
233
 
                                goto error_free_buf;
234
 
                }
235
 
 
236
 
                free(buf);
237
 
                return 1;
238
 
        }
239
 
        ped_exception_catch();
240
 
        ped_exception_leave_all();
241
 
 
242
 
        for (i=0;i<num;i++)
243
 
        {
244
 
                struct ext2_buffer_head *bh;
245
 
 
246
 
                bh = ext2_bcreate(fs, block+i);
247
 
                if (!bh)
248
 
                        goto error;
249
 
                bh->dirty = 1;
250
 
                if (!ext2_brelse(bh, 1))
251
 
                        goto error;
252
 
        }
253
 
        return 1;
254
 
 
255
 
error_free_buf:
256
 
        free(buf);
257
 
error:
258
 
        return 0;
259
 
}
260
 
 
261
 
off_t ext2_get_inode_offset(struct ext2_fs *fs, ino_t inode, blk_t *block)
262
 
{
263
 
        int group;
264
 
        int offset;
265
 
 
266
 
        inode--;
267
 
 
268
 
        group = inode / EXT2_SUPER_INODES_PER_GROUP(fs->sb);
269
 
        offset = (inode % EXT2_SUPER_INODES_PER_GROUP(fs->sb))
270
 
                 * sizeof(struct ext2_inode);
271
 
 
272
 
        *block = EXT2_GROUP_INODE_TABLE(fs->gd[group])
273
 
                 + (offset >> fs->logsize);
274
 
 
275
 
        return offset & (fs->blocksize - 1);
276
 
}
277
 
 
278
 
int ext2_get_inode_state(struct ext2_fs *fs, ino_t inode)
279
 
{
280
 
        struct ext2_buffer_head *bh;
281
 
        int                      group;
282
 
        int                      offset;
283
 
        int                      ret;
284
 
 
285
 
        inode--;
286
 
        group = inode / EXT2_SUPER_INODES_PER_GROUP(fs->sb);
287
 
        offset = inode % EXT2_SUPER_INODES_PER_GROUP(fs->sb);
288
 
 
289
 
        bh = ext2_bread(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[group]));
290
 
        ret = bh->data[offset>>3] & _bitmap[offset&7];
291
 
        ext2_brelse(bh, 0);
292
 
 
293
 
        return ret;
294
 
}
295
 
 
296
 
int ext2_read_inode(struct ext2_fs *fs, ino_t inode, struct ext2_inode *data)
297
 
{
298
 
        struct ext2_buffer_head *bh;
299
 
        blk_t                    blk;
300
 
        off_t                    off;
301
 
 
302
 
        off = ext2_get_inode_offset(fs, inode, &blk);
303
 
 
304
 
        bh = ext2_bread(fs, blk);
305
 
        if (!bh)
306
 
                return 0;
307
 
 
308
 
        memcpy(data, bh->data + off, sizeof(struct ext2_inode));
309
 
        ext2_brelse(bh, 0);
310
 
        return 1;
311
 
}
312
 
 
313
 
int ext2_set_inode_state(struct ext2_fs *fs, ino_t inode, int state, int updatemetadata)
314
 
{
315
 
        struct ext2_buffer_head *bh;
316
 
        int                      group;
317
 
        int                      offset;
318
 
 
319
 
        inode--;
320
 
        group = inode / EXT2_SUPER_INODES_PER_GROUP(fs->sb);
321
 
        offset = inode % EXT2_SUPER_INODES_PER_GROUP(fs->sb);
322
 
 
323
 
        bh = ext2_bread(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[group]));
324
 
        if (!bh)
325
 
                return 0;
326
 
        bh->dirty = 1;
327
 
        if (state)
328
 
                bh->data[offset>>3] |= _bitmap[offset&7];
329
 
        else
330
 
                bh->data[offset>>3] &= ~_bitmap[offset&7];
331
 
        ext2_brelse(bh, 0);
332
 
 
333
 
        if (updatemetadata)
334
 
        {
335
 
                int diff;
336
 
 
337
 
                diff = state ? -1 : 1;
338
 
 
339
 
                fs->gd[group].bg_free_inodes_count = PED_CPU_TO_LE16
340
 
                        (EXT2_GROUP_FREE_INODES_COUNT(fs->gd[group]) + diff);
341
 
                fs->sb.s_free_inodes_count = PED_CPU_TO_LE32
342
 
                        (EXT2_SUPER_FREE_INODES_COUNT(fs->sb) + diff);
343
 
                fs->metadirty = EXT2_META_SB | EXT2_META_GD;
344
 
        }
345
 
        return 1;
346
 
}
347
 
 
348
 
static void
349
 
_inode_update_size(struct ext2_fs *fs, struct ext2_inode *inode, int delta)
350
 
{
351
 
        int             i512perblock = 1 << (fs->logsize - 9);
352
 
        uint64_t        size;
353
 
 
354
 
        /* i_blocks is in 512 byte blocks */
355
 
        inode->i_blocks = PED_CPU_TO_LE32(EXT2_INODE_BLOCKS(*inode)
356
 
                                          + delta * i512perblock);
357
 
        size = EXT2_INODE_SIZE(*inode) + delta * fs->blocksize;
358
 
        inode->i_size = PED_CPU_TO_LE32(size % (1LL << 32));
359
 
        inode->i_size_high = PED_CPU_TO_LE32(size / (1LL << 32));
360
 
        inode->i_mtime = PED_CPU_TO_LE32(time(NULL));
361
 
}
362
 
 
363
 
int ext2_do_inode(struct ext2_fs *fs, struct ext2_inode *inode, blk_t block,
364
 
                   int action)
365
 
{
366
 
        struct ext2_buffer_head *bh;
367
 
        uint32_t                *udata;
368
 
        blk_t                    count = 0;
369
 
        int                      i;
370
 
        int                      u32perblock = fs->blocksize >> 2;
371
 
        int                      i512perblock = 1 << (fs->logsize - 9);
372
 
 
373
 
        if (block == 0 || EXT2_INODE_MODE(*inode) == 0)
374
 
                return -1;
375
 
 
376
 
        if (fs->opt_debug)
377
 
                switch (action)
378
 
                {
379
 
                        case EXT2_ACTION_ADD:
380
 
                                fprintf(stderr,"adding 0x%04x to inode\n",
381
 
                                        block);
382
 
                                break;
383
 
                        case EXT2_ACTION_DELETE:
384
 
                                fprintf(stderr,"deleting 0x%04x from inode\n",
385
 
                                        block);
386
 
                                break;
387
 
                        case EXT2_ACTION_FIND:
388
 
                                fprintf(stderr,"finding 0x%04x in inode\n",
389
 
                                        block);
390
 
                                break;
391
 
                }
392
 
 
393
 
        /* Direct blocks for first 12 blocks */
394
 
        for (i = 0; i < EXT2_NDIR_BLOCKS; i++)
395
 
        {
396
 
                if (action == EXT2_ACTION_ADD && !EXT2_INODE_BLOCK(*inode, i))
397
 
                {
398
 
                        inode->i_block[i] = PED_CPU_TO_LE32(block);
399
 
                        _inode_update_size (fs, inode, 1);
400
 
                        ext2_set_block_state(fs, block, 1, 1);
401
 
                        return i;
402
 
                }
403
 
                if (EXT2_INODE_BLOCK(*inode, i) == block)
404
 
                {
405
 
                        if (action == EXT2_ACTION_DELETE)
406
 
                        {
407
 
                                inode->i_block[i] = 0;
408
 
                                _inode_update_size (fs, inode, -1);
409
 
                                ext2_set_block_state(fs, block, 0, 1);
410
 
                        }
411
 
                        return i;
412
 
                }
413
 
                if (EXT2_INODE_BLOCK(*inode, i))
414
 
                        count += i512perblock;
415
 
        }
416
 
 
417
 
        count += EXT2_INODE_BLOCK(*inode, EXT2_IND_BLOCK) ? i512perblock : 0;
418
 
        count += EXT2_INODE_BLOCK(*inode, EXT2_DIND_BLOCK) ? i512perblock : 0;
419
 
        count += EXT2_INODE_BLOCK(*inode, EXT2_TIND_BLOCK) ? i512perblock : 0;
420
 
 
421
 
        if (!EXT2_INODE_BLOCK(*inode, EXT2_IND_BLOCK) ||
422
 
            (count >= EXT2_INODE_BLOCKS(*inode) && action != EXT2_ACTION_ADD))
423
 
                return -1;
424
 
 
425
 
        bh = ext2_bread(fs, EXT2_INODE_BLOCK(*inode, EXT2_IND_BLOCK));
426
 
        udata = (uint32_t *)bh->data;
427
 
 
428
 
        /* Indirect blocks for next 256/512/1024 blocks (for 1k/2k/4k blocks) */
429
 
        for (i = 0; i < u32perblock; i++) {
430
 
                if (action == EXT2_ACTION_ADD && !udata[i]) {
431
 
                        bh->dirty = 1;
432
 
                        udata[i] = PED_CPU_TO_LE32(block);
433
 
                        _inode_update_size (fs, inode, 1);
434
 
                        ext2_set_block_state(fs, block, 1, 1);
435
 
                        ext2_brelse(bh, 0);
436
 
                        return EXT2_NDIR_BLOCKS + i;
437
 
                }
438
 
                if (PED_LE32_TO_CPU(udata[i]) == block) {
439
 
                        if (action == EXT2_ACTION_DELETE) {
440
 
                                bh->dirty = 1;
441
 
                                udata[i] = 0;
442
 
                                _inode_update_size (fs, inode, -1);
443
 
                                ext2_set_block_state(fs, block, 0, 1);
444
 
                        }
445
 
                        ext2_brelse(bh, 0);
446
 
                        return EXT2_NDIR_BLOCKS + i;
447
 
                }
448
 
                if (udata[i])
449
 
                {
450
 
                        count += i512perblock;
451
 
                        if (count >= EXT2_INODE_BLOCKS(*inode) &&
452
 
                            action != EXT2_ACTION_ADD)
453
 
                                return -1;
454
 
                }
455
 
        }
456
 
 
457
 
        ext2_brelse(bh, 0);
458
 
 
459
 
        if (!EXT2_INODE_BLOCK(*inode, EXT2_DIND_BLOCK) ||
460
 
            (count >= EXT2_INODE_BLOCKS(*inode) && action != EXT2_ACTION_ADD))
461
 
                return -1;
462
 
        bh = ext2_bread(fs, EXT2_INODE_BLOCK(*inode, EXT2_DIND_BLOCK));
463
 
        udata = (uint32_t *)bh->data;
464
 
 
465
 
        /* Double indirect blocks for next 2^16/2^18/2^20 1k/2k/4k blocks */
466
 
        for (i = 0; i < u32perblock; i++) {
467
 
                struct ext2_buffer_head *bh2;
468
 
                uint32_t                        *udata2;
469
 
                int                      j;
470
 
 
471
 
                if (!udata[i]) {
472
 
                        ext2_brelse(bh, 0);
473
 
                        return -1;
474
 
                }
475
 
                bh2 = ext2_bread(fs, PED_LE32_TO_CPU(udata[i]));
476
 
                udata2 = (uint32_t *)bh2->data;
477
 
                count += i512perblock;
478
 
 
479
 
                for (j = 0; j < u32perblock; j++) {
480
 
                        if (action == EXT2_ACTION_ADD && !udata2[j]) {
481
 
                                bh2->dirty = 1;
482
 
                                udata2[j] = PED_CPU_TO_LE32(block);
483
 
                                _inode_update_size (fs, inode, 1);
484
 
                                ext2_set_block_state(fs, block, 1, 1);
485
 
                                ext2_brelse(bh, 0);
486
 
                                ext2_brelse(bh2, 0);
487
 
                                return EXT2_NDIR_BLOCKS + i * u32perblock + j;
488
 
                        }
489
 
                        if (PED_LE32_TO_CPU(udata2[j]) == block) {
490
 
                                if (action == EXT2_ACTION_DELETE) {
491
 
                                        bh2->dirty = 1;
492
 
                                        udata2[j] = 0;
493
 
                                        _inode_update_size (fs, inode, -1);
494
 
                                        ext2_set_block_state(fs, block, 0, 1);
495
 
                                }
496
 
                                ext2_brelse(bh, 0);
497
 
                                ext2_brelse(bh2, 0);
498
 
                                return EXT2_NDIR_BLOCKS + i * u32perblock + j;
499
 
                        }
500
 
                        if (udata2[j])
501
 
                        {
502
 
                                count += i512perblock;
503
 
                                if (count >= EXT2_INODE_BLOCKS(*inode) &&
504
 
                                    action != EXT2_ACTION_ADD)
505
 
                                        return -1;
506
 
                        }
507
 
                }
508
 
                ext2_brelse(bh2, 0);
509
 
        }
510
 
        ext2_brelse(bh, 0);
511
 
 
512
 
        /* FIXME: we should check for triple-indirect blocks here, but it
513
 
         * would be nice to have a better routine to traverse blocks, and
514
 
         * file systems that need triple-indirect blocks for the resize
515
 
         * inode are too big to worry about yet.
516
 
         */
517
 
 
518
 
        return -1;
519
 
}
520
 
 
521
 
int ext2_write_inode(struct ext2_fs *fs, ino_t inode, const struct ext2_inode *data)
522
 
{
523
 
        struct ext2_buffer_head *bh;
524
 
        blk_t                    blk;
525
 
        off_t                    off;
526
 
 
527
 
        off = ext2_get_inode_offset(fs, inode, &blk);
528
 
 
529
 
        bh = ext2_bread(fs, blk);
530
 
        if (!bh)
531
 
                return 0;
532
 
        bh->dirty = 1;
533
 
        memcpy(bh->data + off, data, sizeof(struct ext2_inode));
534
 
        ext2_brelse(bh, 0);
535
 
 
536
 
        return 1;
537
 
}
538
 
 
539
 
int ext2_zero_inode(struct ext2_fs *fs, ino_t inode)
540
 
{
541
 
        struct ext2_inode buf;
542
 
 
543
 
        memset(&buf, 0, sizeof(struct ext2_inode));
544
 
        return ext2_write_inode(fs, inode, &buf);
545
 
}
546
 
 
547
 
 
548
 
 
549
 
 
550
 
 
551
 
/* check whether y is root of x
552
 
 * (formula grabbed from linux ext2 kernel source) */
553
 
static int is_root(int x, int y)
554
 
{
555
 
        if (!x)
556
 
                return 1;
557
 
 
558
 
        while (1)
559
 
        {
560
 
                if (x == 1)
561
 
                        return 1;
562
 
 
563
 
                if (x % y)
564
 
                        return 0;
565
 
 
566
 
                x /= y;
567
 
        }
568
 
}
569
 
 
570
 
/* check whether group contains a superblock copy on file systems
571
 
 * where not all groups have one (sparse superblock feature) */
572
 
int ext2_is_group_sparse(struct ext2_fs *fs, int group)
573
 
{
574
 
        if (!fs->sparse)
575
 
                return 1;
576
 
 
577
 
        if (is_root(group, 3) || is_root(group, 5) || is_root(group, 7))
578
 
                return 1;
579
 
 
580
 
        return 0;
581
 
}
582
 
 
583
 
void ext2_close(struct ext2_fs *fs)
584
 
{
585
 
        ext2_commit_metadata(fs, EXT2_META_PRIMARY | EXT2_META_BACKUP);
586
 
        ext2_sync(fs);
587
 
 
588
 
        ext2_bcache_deinit(fs);
589
 
 
590
 
        fs->devhandle->ops->close(fs->devhandle->cookie);
591
 
 
592
 
        free(fs->gd);
593
 
        free(fs);
594
 
}
595
 
 
596
 
int ext2_commit_metadata(struct ext2_fs *fs, int copies)
597
 
{
598
 
        int             i;
599
 
        int             num;
600
 
        int             wmeta = fs->metadirty & copies;
601
 
        unsigned char*  sb = ped_malloc(fs->blocksize);
602
 
        struct ext2_super_block *sb_for_io;
603
 
        int             sb_block;
604
 
 
605
 
        /* See if there is even anything to write... */
606
 
        if (wmeta == EXT2_META_CLEAN)
607
 
                return 1;
608
 
 
609
 
        ext2_super_r_blocks_count_set(&fs->sb,
610
 
                fs->r_frac * (loff_t)EXT2_SUPER_BLOCKS_COUNT(fs->sb)
611
 
                                  / 100);
612
 
 
613
 
        if (!ext2_read_blocks (fs, sb, 0, 1))
614
 
                return 0;
615
 
 
616
 
        if (EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)) {
617
 
                memcpy(sb, &fs->sb, 1024);
618
 
                sb_for_io = (struct ext2_super_block *) sb;
619
 
        } else {
620
 
                memcpy(sb+1024, &fs->sb, 1024);
621
 
                sb_for_io = (struct ext2_super_block *) (sb + 1024);
622
 
        }
623
 
 
624
 
        num = copies & EXT2_META_BACKUP ? fs->numgroups : 1;
625
 
 
626
 
        for (i = 0, sb_block = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb); i < num;
627
 
             i++, sb_block += EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
628
 
        {
629
 
 
630
 
                if (!ext2_is_group_sparse(fs, i))
631
 
                        continue;
632
 
 
633
 
                if (fs->dynamic_version)
634
 
                        sb_for_io->s_block_group_nr = PED_CPU_TO_LE16 (i);
635
 
 
636
 
                if ((i == 0 && wmeta & EXT2_META_PRIMARY_SB) ||
637
 
                    (i != 0 && wmeta & EXT2_META_SB))
638
 
                {
639
 
                        if (!ext2_bcache_flush_range(fs, sb_block, 1))
640
 
                                return 0;
641
 
                        if (!ext2_write_blocks(fs, sb, sb_block, 1))
642
 
                                return 0;
643
 
                }
644
 
                if ((i == 0 && wmeta & EXT2_META_PRIMARY_GD) ||
645
 
                    (i != 0 && wmeta & EXT2_META_GD))
646
 
                {
647
 
                        if (!ext2_bcache_flush_range(fs, sb_block + 1,
648
 
                                                     fs->gdblocks))
649
 
                                return 0;
650
 
                        if (!ext2_write_blocks(fs, fs->gd, sb_block + 1,
651
 
                                               fs->gdblocks))
652
 
                                return 0;
653
 
                }
654
 
        }
655
 
 
656
 
        sb_for_io->s_block_group_nr = 0;
657
 
 
658
 
        /* Clear the flags of the components we just finished writing. */
659
 
        fs->metadirty &= ~copies;
660
 
 
661
 
        return 1;
662
 
}
663
 
 
664
 
int ext2_sync(struct ext2_fs *fs)
665
 
{
666
 
        if (!ext2_commit_metadata(fs, EXT2_META_PRIMARY)) return 0;
667
 
        if (!ext2_bcache_sync(fs)) return 0;
668
 
        if (!fs->devhandle->ops->sync(fs->devhandle->cookie)) return 0;
669
 
        return 1;
670
 
}
671
 
 
672
 
struct ext2_fs *ext2_open(struct ext2_dev_handle *handle, int state)
673
 
{
674
 
        struct ext2_fs *fs;
675
 
 
676
 
        if ((fs = (struct ext2_fs *) ped_malloc(sizeof(struct ext2_fs)))
677
 
                == NULL)
678
 
                goto error;
679
 
 
680
 
        handle->ops->set_blocksize(handle->cookie, 10);
681
 
 
682
 
        if (!handle->ops->read(handle->cookie, &fs->sb, 1, 1)
683
 
            || EXT2_SUPER_MAGIC(fs->sb) != EXT2_SUPER_MAGIC_CONST)
684
 
        {
685
 
                ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
686
 
                        _("Invalid superblock.  Are you sure this is an ext2 "
687
 
                          "file system?"));
688
 
                goto error_free_fs;
689
 
        }
690
 
 
691
 
 
692
 
        fs->opt_debug = 1;
693
 
        fs->opt_safe = 1;
694
 
        fs->opt_verbose = 0;
695
 
 
696
 
        if (EXT2_SUPER_STATE(fs->sb) & EXT2_ERROR_FS & ~(state & EXT2_ERROR_FS))
697
 
        {
698
 
                if (ped_exception_throw (
699
 
                        PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL,
700
 
                        _("File system has errors!  You should run e2fsck."))
701
 
                                == PED_EXCEPTION_CANCEL)
702
 
                        goto error_free_fs;
703
 
        }
704
 
 
705
 
        if (!((EXT2_SUPER_STATE(fs->sb) | state) & EXT2_VALID_FS)
706
 
            || (EXT2_SUPER_FEATURE_INCOMPAT(fs->sb)
707
 
                & EXT3_FEATURE_INCOMPAT_RECOVER))
708
 
        {
709
 
                if (ped_exception_throw (
710
 
                        PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
711
 
                        _("File system was not cleanly unmounted!  "
712
 
                          "You should run e2fsck.  Modifying an unclean "
713
 
                          "file system could cause severe corruption."))
714
 
                                != PED_EXCEPTION_IGNORE)
715
 
                        goto error_free_fs;
716
 
        }
717
 
 
718
 
        fs->dynamic_version = EXT2_SUPER_REV_LEVEL (fs->sb) > 0;
719
 
 
720
 
        if ((EXT2_SUPER_FEATURE_COMPAT(fs->sb)
721
 
                        & ~(EXT3_FEATURE_COMPAT_HAS_JOURNAL |
722
 
                            EXT2_FEATURE_COMPAT_HAS_DIR_INDEX)) ||
723
 
            (EXT2_SUPER_FEATURE_INCOMPAT(fs->sb)
724
 
                        & ~(EXT2_FEATURE_INCOMPAT_FILETYPE |
725
 
                            EXT3_FEATURE_INCOMPAT_RECOVER |
726
 
                            EXT4_FEATURE_INCOMPAT_64BIT)) ||
727
 
            (EXT2_SUPER_FEATURE_RO_COMPAT(fs->sb)
728
 
                        & ~(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
729
 
                            EXT2_FEATURE_RO_COMPAT_LARGE_FILE)))
730
 
        {
731
 
                ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
732
 
                     _("File system has an incompatible feature enabled.  "
733
 
                       "Compatible features are has_journal, dir_index, "
734
 
                       "filetype, sparse_super and large_file.  "
735
 
                       "Use tune2fs or debugfs to remove features."));
736
 
                goto error_free_fs;
737
 
        }
738
 
 
739
 
        fs->devhandle = handle;
740
 
        fs->logsize = EXT2_SUPER_LOG_BLOCK_SIZE(fs->sb) + 10;
741
 
        handle->ops->set_blocksize(handle->cookie, fs->logsize);
742
 
 
743
 
        if (!ext2_bcache_init(fs))
744
 
        {
745
 
                ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
746
 
                                     _("Error allocating buffer cache."));
747
 
                goto error_free_fs;
748
 
        }
749
 
 
750
 
        fs->blocksize = 1 << fs->logsize;
751
 
 
752
 
        fs->numgroups = ped_div_round_up (EXT2_SUPER_BLOCKS_COUNT(fs->sb)
753
 
                                - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb),
754
 
                                EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
755
 
        fs->gdblocks = ped_div_round_up (fs->numgroups
756
 
                        * sizeof(struct ext2_group_desc),
757
 
                               fs->blocksize);
758
 
        fs->inodeblocks = ped_div_round_up (EXT2_SUPER_INODES_PER_GROUP(fs->sb)
759
 
                                  * sizeof(struct ext2_inode),
760
 
                                  fs->blocksize);
761
 
        fs->r_frac = ped_div_round_up (100 * (loff_t)EXT2_SUPER_R_BLOCKS_COUNT(fs->sb),
762
 
                             EXT2_SUPER_BLOCKS_COUNT(fs->sb));
763
 
        fs->adminblocks = 3 + fs->gdblocks + fs->inodeblocks;
764
 
 
765
 
        fs->sparse = 0;
766
 
        if (EXT2_SUPER_FEATURE_RO_COMPAT(fs->sb)
767
 
                        & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
768
 
                fs->sparse = 1;
769
 
 
770
 
        fs->has_journal = 0 < (EXT2_SUPER_FEATURE_COMPAT(fs->sb)
771
 
                               & EXT3_FEATURE_COMPAT_HAS_JOURNAL);
772
 
        fs->has_internal_journal
773
 
                = fs->has_journal
774
 
                        && uuid_is_null(EXT2_SUPER_JOURNAL_UUID(fs->sb))
775
 
                        && EXT2_SUPER_JOURNAL_INUM(fs->sb);
776
 
 
777
 
        fs->gd = ped_malloc (fs->numgroups * sizeof (struct ext2_group_desc)
778
 
                                + fs->blocksize);
779
 
        if (!fs->gd)
780
 
                goto error_deinit_bcache;
781
 
 
782
 
        ext2_read_blocks(fs, fs->gd, EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) + 1,
783
 
                         fs->gdblocks);
784
 
 
785
 
        fs->metadirty = 0;
786
 
        return fs;
787
 
 
788
 
        free(fs->gd);
789
 
error_deinit_bcache:
790
 
        ext2_bcache_deinit(fs);
791
 
error_free_fs:
792
 
        free(fs);
793
 
error:
794
 
        return NULL;
795
 
}
796
 
 
797
 
#endif /* !DISCOVER_ONLY */