source: branches/stable/mindi-busybox/e2fsprogs/ext2fs/mkjournal.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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