• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/router/busybox-1.x/e2fsprogs/old_e2fsprogs/ext2fs/
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 = 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;
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(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
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