~ubuntu-branches/debian/jessie/arcboot/jessie

« back to all changes in this revision

Viewing changes to e2fslib/mkjournal.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Guenther
  • Date: 2004-03-02 12:01:14 UTC
  • Revision ID: james.westby@ubuntu.com-20040302120114-0pukal9hlpt3k0l7
Tags: 0.3.8.1
correct subarch detection for IP32

Show diffs side-by-side

added added

removed removed

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