Whamcloud - gitweb
31a20e3cf648b0b38471e8e804441b77327168f0
[tools/e2fsprogs.git] / lib / ext2fs / mkjournal.c
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
29 #if EXT2_FLAT_INCLUDES
30 #include "ext2_fs.h"
31 #else
32 #include <linux/ext2_fs.h>
33 #endif
34
35 #include "ext2fs.h"
36 #include "jfs_dat.h"
37
38 static void init_journal_superblock(journal_superblock_t *jsb,
39                                     __u32 blocksize, __u32 size)
40 {
41         jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
42         jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK);
43         jsb->s_header.h_sequence = 0;
44         jsb->s_blocksize = htonl(blocksize);
45         jsb->s_maxlen = htonl(size);
46         jsb->s_first = htonl(1);
47         jsb->s_sequence = htonl(1);
48         jsb->s_start = 0;
49 }
50         
51 /*
52  * This function adds a journal device to a filesystem
53  */
54 errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device,
55                                     blk_t size)
56 {
57         journal_superblock_t    jsb;
58         struct stat     st;
59         errcode_t       retval;
60         char            *buf = 0;
61         blk_t           dev_size;
62         int             i, fd, ret_size;
63
64         /* Make sure the device exists and is a block device */
65         if (stat(device, &st) < 0)
66                 return errno;
67         if (!S_ISBLK(st.st_mode))
68                 return EXT2_JOURNAL_NOT_BLOCK;  /* Must be a block device */
69         
70         /* Get the size of the device */
71         if ((retval = ext2fs_get_device_size(device, fs->blocksize,
72                                              &dev_size)))
73                 return retval;
74         
75         if (!size)
76                 size = dev_size; /* Default to the size of the device */
77         else if (size > dev_size) 
78                 return EINVAL;  /* Requested size bigger than device */
79
80         init_journal_superblock(&jsb, fs->blocksize, size);
81
82         /* Create a block buffer */
83         buf = malloc(fs->blocksize);
84         if (!buf)
85                 return ENOMEM;
86
87         /* Open the device */
88         if ((fd = open(device, O_WRONLY)) < 0) {
89                 retval = errno;
90                 goto errout;
91         }
92
93         /* Write the superblock out */
94         memset(buf, 0, fs->blocksize);
95         memcpy(buf, &jsb, sizeof(jsb));
96         retval = EXT2_ET_SHORT_WRITE;
97         ret_size = write(fd, buf, fs->blocksize);
98         if (ret_size < 0) {
99                 errno = retval;
100                 goto errout;
101         }
102         if (ret_size != fs->blocksize)
103                 goto errout;
104         memset(buf, 0, fs->blocksize);
105         
106         for (i=1; i < size; i++) {
107                 ret_size = write(fd, buf, fs->blocksize);
108                 if (ret_size < 0) {
109                         retval = errno;
110                         goto errout;
111                 }
112                 if (ret_size != fs->blocksize)
113                         goto errout;
114         }
115         close(fd);
116
117         fs->super->s_journal_dev = st.st_rdev;
118         fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
119         ext2fs_mark_super_dirty(fs);
120
121         return 0;
122 errout:
123         if (buf)
124                 free(buf);
125         return retval;
126 }
127
128 /*
129  * Helper function for creating the journal in the filesystem
130  */
131 struct mkjournal_struct {
132         int             num_blocks;
133         int             newblocks;
134         char            *buf;
135         errcode_t       err;
136 };
137
138 static int mkjournal_proc(ext2_filsys           fs,
139                            blk_t                *blocknr,
140                            e2_blkcnt_t          blockcnt,
141                            blk_t                ref_block,
142                            int                  ref_offset,
143                            void                 *priv_data)
144 {
145         struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
146         blk_t   new_blk;
147         static blk_t    last_blk = 0;
148         char            *block;
149         errcode_t       retval;
150         int             group;
151         
152         if (*blocknr) {
153                 last_blk = *blocknr;
154                 return 0;
155         }
156         retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
157         if (retval) {
158                 es->err = retval;
159                 return BLOCK_ABORT;
160         }
161         if (blockcnt > 0)
162                 es->num_blocks--;
163
164         es->newblocks++;
165         retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
166
167         if (blockcnt == 0)
168                 memset(es->buf, 0, fs->blocksize);
169
170         if (retval) {
171                 es->err = retval;
172                 return BLOCK_ABORT;
173         }
174         *blocknr = new_blk;
175         ext2fs_mark_block_bitmap(fs->block_map, new_blk);
176         ext2fs_mark_bb_dirty(fs);
177         group = ext2fs_group_of_blk(fs, new_blk);
178         fs->group_desc[group].bg_free_blocks_count--;
179         fs->super->s_free_blocks_count--;
180         ext2fs_mark_super_dirty(fs);
181
182         if (es->num_blocks == 0)
183                 return (BLOCK_CHANGED | BLOCK_ABORT);
184         else
185                 return BLOCK_CHANGED;
186         
187 }
188
189 /*
190  * This function adds a journal inode to a filesystem
191  */
192 errcode_t ext2fs_add_journal_fs(ext2_filsys fs, blk_t size)
193 {
194         journal_superblock_t    jsb;
195         errcode_t               retval;
196         struct ext2_inode       inode;
197         struct mkjournal_struct es;
198         char                    *buf;
199
200         init_journal_superblock(&jsb, fs->blocksize, size);
201
202         if ((retval = ext2fs_read_bitmaps(fs)))
203                 return retval;
204
205         if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode)))
206                 return retval;
207
208         if (inode.i_blocks > 0)
209                 return EEXIST;
210
211         /* Create the block buffer */
212         buf = malloc(fs->blocksize);
213         if (!buf)
214                 return ENOMEM;
215
216         memset(buf, 0, fs->blocksize);
217         memcpy(buf, &jsb, sizeof(jsb));
218
219         es.num_blocks = size;
220         es.newblocks = 0;
221         es.buf = buf;
222         es.err = 0;
223
224         retval = ext2fs_block_iterate2(fs, EXT2_JOURNAL_INO, BLOCK_FLAG_APPEND,
225                                        0, mkjournal_proc, &es);
226         free(buf);
227         if (es.err)
228                 return es.err;
229
230         if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode)))
231                 return retval;
232
233         inode.i_size += fs->blocksize * size;
234         inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
235         inode.i_mtime = inode.i_ctime = time(0);
236         inode.i_links_count = 1;
237         inode.i_mode = LINUX_S_IFREG | 0600;
238
239         if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)))
240                 return retval;
241
242         fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
243         fs->super->s_journal_inum = EXT2_JOURNAL_INO;
244
245         ext2fs_mark_super_dirty(fs);
246         return 0;
247 }
248
249 #ifdef DEBUG
250 main(int argc, char **argv)
251 {
252         errcode_t       retval;
253         char            *device_name;
254         ext2_filsys     fs;
255
256         if (argc < 2) {
257                 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
258                 exit(1);
259         }
260         device_name = argv[1];
261         
262         retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
263                               unix_io_manager, &fs);
264         if (retval) {
265                 com_err(argv[0], retval, "while opening %s", device_name);
266                 exit(1);
267         }
268
269         retval = ext2fs_add_journal_fs(fs, 1024);
270         if (retval) {
271                 com_err(argv[0], retval, "while adding journal to %s",
272                         device_name);
273                 exit(1);
274         }
275         retval = ext2fs_flush(fs);
276         if (retval) {
277                 printf("Warning, had trouble writing out superblocks.\n");
278         }
279         ext2fs_close(fs);
280         exit(0);
281         
282 }
283 #endif