• 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 * bmove.c --- Move blocks around to make way for a particular
4 *	filesystem structure.
5 *
6 * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
7 * under the terms of the GNU Public License.
8 */
9
10#include <stdio.h>
11#include <string.h>
12#if HAVE_UNISTD_H
13#include <unistd.h>
14#endif
15#if HAVE_SYS_TYPES_H
16#include <sys/types.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fsP.h"
21
22struct process_block_struct {
23	ext2_ino_t		ino;
24	struct ext2_inode *	inode;
25	ext2fs_block_bitmap	reserve;
26	ext2fs_block_bitmap	alloc_map;
27	errcode_t		error;
28	char			*buf;
29	int			add_dir;
30	int			flags;
31};
32
33static int process_block(ext2_filsys fs, blk_t	*block_nr,
34			 e2_blkcnt_t blockcnt, blk_t ref_block,
35			 int ref_offset, void *priv_data)
36{
37	struct process_block_struct *pb;
38	errcode_t	retval;
39	int		ret;
40	blk_t		block, orig;
41
42	pb = (struct process_block_struct *) priv_data;
43	block = orig = *block_nr;
44	ret = 0;
45
46	/*
47	 * Let's see if this is one which we need to relocate
48	 */
49	if (ext2fs_test_block_bitmap(pb->reserve, block)) {
50		do {
51			if (++block >= fs->super->s_blocks_count)
52				block = fs->super->s_first_data_block;
53			if (block == orig) {
54				pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
55				return BLOCK_ABORT;
56			}
57		} while (ext2fs_test_block_bitmap(pb->reserve, block) ||
58			 ext2fs_test_block_bitmap(pb->alloc_map, block));
59
60		retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
61		if (retval) {
62			pb->error = retval;
63			return BLOCK_ABORT;
64		}
65		retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
66		if (retval) {
67			pb->error = retval;
68			return BLOCK_ABORT;
69		}
70		*block_nr = block;
71		ext2fs_mark_block_bitmap(pb->alloc_map, block);
72		ret = BLOCK_CHANGED;
73		if (pb->flags & EXT2_BMOVE_DEBUG)
74			printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
75			       blockcnt, orig, block);
76	}
77	if (pb->add_dir) {
78		retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
79					      block, (int) blockcnt);
80		if (retval) {
81			pb->error = retval;
82			ret |= BLOCK_ABORT;
83		}
84	}
85	return ret;
86}
87
88errcode_t ext2fs_move_blocks(ext2_filsys fs,
89			     ext2fs_block_bitmap reserve,
90			     ext2fs_block_bitmap alloc_map,
91			     int flags)
92{
93	ext2_ino_t	ino;
94	struct ext2_inode inode;
95	errcode_t	retval;
96	struct process_block_struct pb;
97	ext2_inode_scan	scan;
98	char		*block_buf;
99
100	retval = ext2fs_open_inode_scan(fs, 0, &scan);
101	if (retval)
102		return retval;
103
104	pb.reserve = reserve;
105	pb.error = 0;
106	pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
107	pb.flags = flags;
108
109	retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
110	if (retval)
111		return retval;
112	pb.buf = block_buf + fs->blocksize * 3;
113
114	/*
115	 * If GET_DBLIST is set in the flags field, then we should
116	 * gather directory block information while we're doing the
117	 * block move.
118	 */
119	if (flags & EXT2_BMOVE_GET_DBLIST) {
120		ext2fs_free_dblist(fs->dblist);
121		fs->dblist = NULL;
122		retval = ext2fs_init_dblist(fs, 0);
123		if (retval)
124			return retval;
125	}
126
127	retval = ext2fs_get_next_inode(scan, &ino, &inode);
128	if (retval)
129		return retval;
130
131	while (ino) {
132		if ((inode.i_links_count == 0) ||
133		    !ext2fs_inode_has_valid_blocks(&inode))
134			goto next;
135
136		pb.ino = ino;
137		pb.inode = &inode;
138
139		pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
140			      flags & EXT2_BMOVE_GET_DBLIST);
141
142		retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
143					      process_block, &pb);
144		if (retval)
145			return retval;
146		if (pb.error)
147			return pb.error;
148
149	next:
150		retval = ext2fs_get_next_inode(scan, &ino, &inode);
151		if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
152			goto next;
153	}
154	return 0;
155}
156