busybox/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * mkjournal.c --- make a journal for a filesystem
   4 *
   5 * Copyright (C) 2000 Theodore Ts'o.
   6 *
   7 * %Begin-Header%
   8 * This file may be redistributed under the terms of the GNU Public
   9 * License.
  10 * %End-Header%
  11 */
  12
  13#include <stdio.h>
  14#include <string.h>
  15#if HAVE_UNISTD_H
  16#include <unistd.h>
  17#endif
  18#if HAVE_ERRNO_H
  19#include <errno.h>
  20#endif
  21#include <fcntl.h>
  22#include <time.h>
  23#if HAVE_SYS_STAT_H
  24#include <sys/stat.h>
  25#endif
  26#if HAVE_SYS_TYPES_H
  27#include <sys/types.h>
  28#endif
  29#if HAVE_SYS_IOCTL_H
  30#include <sys/ioctl.h>
  31#endif
  32#if HAVE_NETINET_IN_H
  33#include <netinet/in.h>
  34#endif
  35
  36#include "ext2_fs.h"
  37#include "../e2p/e2p.h"
  38#include "../e2fsck.h"
  39#include "ext2fs.h"
  40#include "kernel-jbd.h"
  41
  42/*
  43 * This function automatically sets up the journal superblock and
  44 * returns it as an allocated block.
  45 */
  46errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
  47                                           __u32 size, int flags,
  48                                           char  **ret_jsb)
  49{
  50        errcode_t               retval;
  51        journal_superblock_t    *jsb;
  52
  53        if (size < 1024)
  54                return EXT2_ET_JOURNAL_TOO_SMALL;
  55
  56        if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
  57                return retval;
  58
  59        memset (jsb, 0, fs->blocksize);
  60
  61        jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
  62        if (flags & EXT2_MKJOURNAL_V1_SUPER)
  63                jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
  64        else
  65                jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
  66        jsb->s_blocksize = htonl(fs->blocksize);
  67        jsb->s_maxlen = htonl(size);
  68        jsb->s_nr_users = htonl(1);
  69        jsb->s_first = htonl(1);
  70        jsb->s_sequence = htonl(1);
  71        memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
  72        /*
  73         * If we're creating an external journal device, we need to
  74         * adjust these fields.
  75         */
  76        if (fs->super->s_feature_incompat &
  77            EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
  78                jsb->s_nr_users = 0;
  79                if (fs->blocksize == 1024)
  80                        jsb->s_first = htonl(3);
  81                else
  82                        jsb->s_first = htonl(2);
  83        }
  84
  85        *ret_jsb = (char *) jsb;
  86        return 0;
  87}
  88
  89/*
  90 * This function writes a journal using POSIX routines.  It is used
  91 * for creating external journals and creating journals on live
  92 * filesystems.
  93 */
  94static errcode_t write_journal_file(ext2_filsys fs, char *filename,
  95                                    blk_t size, int flags)
  96{
  97        errcode_t       retval;
  98        char            *buf = NULL;
  99        int             fd, ret_size;
 100        blk_t           i;
 101
 102        if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
 103                return retval;
 104
 105        /* Open the device or journal file */
 106        if ((fd = open(filename, O_WRONLY)) < 0) {
 107                retval = errno;
 108                goto errout;
 109        }
 110
 111        /* Write the superblock out */
 112        retval = EXT2_ET_SHORT_WRITE;
 113        ret_size = write(fd, buf, fs->blocksize);
 114        if (ret_size < 0) {
 115                retval = errno;
 116                goto errout;
 117        }
 118        if (ret_size != (int) fs->blocksize)
 119                goto errout;
 120        memset(buf, 0, fs->blocksize);
 121
 122        for (i = 1; i < size; i++) {
 123                ret_size = write(fd, buf, fs->blocksize);
 124                if (ret_size < 0) {
 125                        retval = errno;
 126                        goto errout;
 127                }
 128                if (ret_size != (int) fs->blocksize)
 129                        goto errout;
 130        }
 131        close(fd);
 132
 133        retval = 0;
 134errout:
 135        ext2fs_free_mem(&buf);
 136        return retval;
 137}
 138
 139/*
 140 * Helper function for creating the journal using direct I/O routines
 141 */
 142struct mkjournal_struct {
 143        int             num_blocks;
 144        int             newblocks;
 145        char            *buf;
 146        errcode_t       err;
 147};
 148
 149static int mkjournal_proc(ext2_filsys   fs,
 150                           blk_t        *blocknr,
 151                           e2_blkcnt_t  blockcnt,
 152                           blk_t        ref_block EXT2FS_ATTR((unused)),
 153                           int          ref_offset EXT2FS_ATTR((unused)),
 154                           void         *priv_data)
 155{
 156        struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
 157        blk_t   new_blk;
 158        static blk_t    last_blk = 0;
 159        errcode_t       retval;
 160
 161        if (*blocknr) {
 162                last_blk = *blocknr;
 163                return 0;
 164        }
 165        retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
 166        if (retval) {
 167                es->err = retval;
 168                return BLOCK_ABORT;
 169        }
 170        if (blockcnt > 0)
 171                es->num_blocks--;
 172
 173        es->newblocks++;
 174        retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
 175
 176        if (blockcnt == 0)
 177                memset(es->buf, 0, fs->blocksize);
 178
 179        if (retval) {
 180                es->err = retval;
 181                return BLOCK_ABORT;
 182        }
 183        *blocknr = new_blk;
 184        last_blk = new_blk;
 185        ext2fs_block_alloc_stats(fs, new_blk, +1);
 186
 187        if (es->num_blocks == 0)
 188                return (BLOCK_CHANGED | BLOCK_ABORT);
 189        else
 190                return BLOCK_CHANGED;
 191
 192}
 193
 194/*
 195 * This function creates a journal using direct I/O routines.
 196 */
 197static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
 198                                     blk_t size, int flags)
 199{
 200        char                    *buf;
 201        errcode_t               retval;
 202        struct ext2_inode       inode;
 203        struct mkjournal_struct es;
 204
 205        if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
 206                return retval;
 207
 208        if ((retval = ext2fs_read_bitmaps(fs)))
 209                return retval;
 210
 211        if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
 212                return retval;
 213
 214        if (inode.i_blocks > 0)
 215                return EEXIST;
 216
 217        es.num_blocks = size;
 218        es.newblocks = 0;
 219        es.buf = buf;
 220        es.err = 0;
 221
 222        retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
 223                                       0, mkjournal_proc, &es);
 224        if (es.err) {
 225                retval = es.err;
 226                goto errout;
 227        }
 228
 229        if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
 230                goto errout;
 231
 232        inode.i_size += fs->blocksize * size;
 233        inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
 234        inode.i_mtime = inode.i_ctime = time(NULL);
 235        inode.i_links_count = 1;
 236        inode.i_mode = LINUX_S_IFREG | 0600;
 237
 238        if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
 239                goto errout;
 240        retval = 0;
 241
 242        memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
 243        fs->super->s_jnl_blocks[16] = inode.i_size;
 244        fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
 245        ext2fs_mark_super_dirty(fs);
 246
 247errout:
 248        ext2fs_free_mem(&buf);
 249        return retval;
 250}
 251
 252/*
 253 * This function adds a journal device to a filesystem
 254 */
 255errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
 256{
 257        struct stat     st;
 258        errcode_t       retval;
 259        char            buf[1024];
 260        journal_superblock_t    *jsb;
 261        int             start;
 262        __u32           i, nr_users;
 263
 264        /* Make sure the device exists and is a block device */
 265        if (stat(journal_dev->device_name, &st) < 0)
 266                return errno;
 267
 268        if (!S_ISBLK(st.st_mode))
 269                return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
 270
 271        /* Get the journal superblock */
 272        start = 1;
 273        if (journal_dev->blocksize == 1024)
 274                start++;
 275        if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
 276                return retval;
 277
 278        jsb = (journal_superblock_t *) buf;
 279        if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
 280            (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
 281                return EXT2_ET_NO_JOURNAL_SB;
 282
 283        if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
 284                return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
 285
 286        /* Check and see if this filesystem has already been added */
 287        nr_users = ntohl(jsb->s_nr_users);
 288        for (i=0; i < nr_users; i++) {
 289                if (memcmp(fs->super->s_uuid,
 290                           &jsb->s_users[i*16], 16) == 0)
 291                        break;
 292        }
 293        if (i >= nr_users) {
 294                memcpy(&jsb->s_users[nr_users*16],
 295                       fs->super->s_uuid, 16);
 296                jsb->s_nr_users = htonl(nr_users+1);
 297        }
 298
 299        /* Writeback the journal superblock */
 300        if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
 301                return retval;
 302
 303        fs->super->s_journal_inum = 0;
 304        fs->super->s_journal_dev = st.st_rdev;
 305        memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
 306               sizeof(fs->super->s_journal_uuid));
 307        fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
 308        ext2fs_mark_super_dirty(fs);
 309        return 0;
 310}
 311
 312/*
 313 * This function adds a journal inode to a filesystem, using either
 314 * POSIX routines if the filesystem is mounted, or using direct I/O
 315 * functions if it is not.
 316 */
 317errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
 318{
 319        errcode_t               retval;
 320        ext2_ino_t              journal_ino;
 321        struct stat             st;
 322        char                    jfile[1024];
 323        int                     fd, mount_flags, f;
 324
 325        retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
 326                                               jfile, sizeof(jfile)-10);
 327        if (retval)
 328                return retval;
 329
 330        if (mount_flags & EXT2_MF_MOUNTED) {
 331                strcat(jfile, "/.journal");
 332
 333                /*
 334                 * If .../.journal already exists, make sure any
 335                 * immutable or append-only flags are cleared.
 336                 */
 337#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
 338                (void) chflags (jfile, 0);
 339#else
 340#if HAVE_EXT2_IOCTLS
 341                fd = open(jfile, O_RDONLY);
 342                if (fd >= 0) {
 343                        f = 0;
 344                        ioctl(fd, EXT2_IOC_SETFLAGS, &f);
 345                        close(fd);
 346                }
 347#endif
 348#endif
 349
 350                /* Create the journal file */
 351                if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
 352                        return errno;
 353
 354                if ((retval = write_journal_file(fs, jfile, size, flags)))
 355                        goto errout;
 356
 357                /* Get inode number of the journal file */
 358                if (fstat(fd, &st) < 0)
 359                        goto errout;
 360
 361#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
 362                retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
 363#else
 364#if HAVE_EXT2_IOCTLS
 365                f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
 366                retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
 367#endif
 368#endif
 369                if (retval)
 370                        goto errout;
 371
 372                close(fd);
 373                journal_ino = st.st_ino;
 374        } else {
 375                journal_ino = EXT2_JOURNAL_INO;
 376                if ((retval = write_journal_inode(fs, journal_ino,
 377                                                  size, flags)))
 378                        return retval;
 379        }
 380
 381        fs->super->s_journal_inum = journal_ino;
 382        fs->super->s_journal_dev = 0;
 383        memset(fs->super->s_journal_uuid, 0,
 384               sizeof(fs->super->s_journal_uuid));
 385        fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
 386
 387        ext2fs_mark_super_dirty(fs);
 388        return 0;
 389errout:
 390        close(fd);
 391        return retval;
 392}
 393
 394#ifdef DEBUG
 395main(int argc, char **argv)
 396{
 397        errcode_t       retval;
 398        char            *device_name;
 399        ext2_filsys     fs;
 400
 401        if (argc < 2) {
 402                fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
 403                exit(1);
 404        }
 405        device_name = argv[1];
 406
 407        retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
 408                              unix_io_manager, &fs);
 409        if (retval) {
 410                com_err(argv[0], retval, "while opening %s", device_name);
 411                exit(1);
 412        }
 413
 414        retval = ext2fs_add_journal_inode(fs, 1024);
 415        if (retval) {
 416                com_err(argv[0], retval, "while adding journal to %s",
 417                        device_name);
 418                exit(1);
 419        }
 420        retval = ext2fs_flush(fs);
 421        if (retval) {
 422                printf("Warning, had trouble writing out superblocks.\n");
 423        }
 424        ext2fs_close(fs);
 425        exit(0);
 426
 427}
 428#endif
 429