diff options
Diffstat (limited to 'e2fsprogs/ext2fs/mkjournal.c')
-rw-r--r-- | e2fsprogs/ext2fs/mkjournal.c | 428 |
1 files changed, 0 insertions, 428 deletions
diff --git a/e2fsprogs/ext2fs/mkjournal.c b/e2fsprogs/ext2fs/mkjournal.c deleted file mode 100644 index 5bdd34682..000000000 --- a/e2fsprogs/ext2fs/mkjournal.c +++ /dev/null | |||
@@ -1,428 +0,0 @@ | |||
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 | */ | ||
46 | errcode_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 | */ | ||
94 | static errcode_t write_journal_file(ext2_filsys fs, char *filename, | ||
95 | blk_t size, int flags) | ||
96 | { | ||
97 | errcode_t retval; | ||
98 | char *buf = 0; | ||
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; | ||
134 | errout: | ||
135 | ext2fs_free_mem(&buf); | ||
136 | return retval; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Helper function for creating the journal using direct I/O routines | ||
141 | */ | ||
142 | struct mkjournal_struct { | ||
143 | int num_blocks; | ||
144 | int newblocks; | ||
145 | char *buf; | ||
146 | errcode_t err; | ||
147 | }; | ||
148 | |||
149 | static 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 | */ | ||
197 | static 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(0); | ||
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 | |||
247 | errout: | ||
248 | ext2fs_free_mem(&buf); | ||
249 | return retval; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * This function adds a journal device to a filesystem | ||
254 | */ | ||
255 | errcode_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 | */ | ||
317 | errcode_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; | ||
389 | errout: | ||
390 | close(fd); | ||
391 | return retval; | ||
392 | } | ||
393 | |||
394 | #ifdef DEBUG | ||
395 | main(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 | ||