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