• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * inode.c --- utility routines to read and write inodes
3  *
4  * Copyright (C) 1993, 1994, 1995, 1996, 1997 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 #if HAVE_SYS_STAT_H
21 #include <sys/stat.h>
22 #endif
23 #if HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26 
27 #include "ext2_fs.h"
28 #include "ext2fsP.h"
29 #include "e2image.h"
30 
31 struct ext2_struct_inode_scan {
32 	errcode_t		magic;
33 	ext2_filsys		fs;
34 	ext2_ino_t		current_inode;
35 	blk_t			current_block;
36 	dgrp_t			current_group;
37 	ext2_ino_t		inodes_left;
38 	blk_t			blocks_left;
39 	dgrp_t			groups_left;
40 	blk_t			inode_buffer_blocks;
41 	char *			inode_buffer;
42 	int			inode_size;
43 	char *			ptr;
44 	int			bytes_left;
45 	char			*temp_buffer;
46 	errcode_t		(*done_group)(ext2_filsys fs,
47 					      ext2_inode_scan scan,
48 					      dgrp_t group,
49 					      void * priv_data);
50 	void *			done_group_data;
51 	int			bad_block_ptr;
52 	int			scan_flags;
53 	int			reserved[6];
54 };
55 
56 /*
57  * This routine flushes the icache, if it exists.
58  */
ext2fs_flush_icache(ext2_filsys fs)59 errcode_t ext2fs_flush_icache(ext2_filsys fs)
60 {
61 	int	i;
62 
63 	if (!fs->icache)
64 		return 0;
65 
66 	for (i=0; i < fs->icache->cache_size; i++)
67 		fs->icache->cache[i].ino = 0;
68 
69 	fs->icache->buffer_blk = 0;
70 	return 0;
71 }
72 
create_icache(ext2_filsys fs)73 static errcode_t create_icache(ext2_filsys fs)
74 {
75 	errcode_t	retval;
76 
77 	if (fs->icache)
78 		return 0;
79 	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
80 	if (retval)
81 		return retval;
82 
83 	memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
84 	retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
85 	if (retval) {
86 		ext2fs_free_mem(&fs->icache);
87 		return retval;
88 	}
89 	fs->icache->buffer_blk = 0;
90 	fs->icache->cache_last = -1;
91 	fs->icache->cache_size = 4;
92 	fs->icache->refcount = 1;
93 	retval = ext2fs_get_array(fs->icache->cache_size,
94 				  sizeof(struct ext2_inode_cache_ent),
95 				  &fs->icache->cache);
96 	if (retval) {
97 		ext2fs_free_mem(&fs->icache->buffer);
98 		ext2fs_free_mem(&fs->icache);
99 		return retval;
100 	}
101 	ext2fs_flush_icache(fs);
102 	return 0;
103 }
104 
ext2fs_open_inode_scan(ext2_filsys fs,int buffer_blocks,ext2_inode_scan * ret_scan)105 errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
106 				 ext2_inode_scan *ret_scan)
107 {
108 	ext2_inode_scan	scan;
109 	errcode_t	retval;
110 	errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
111 
112 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
113 
114 	/*
115 	 * If fs->badblocks isn't set, then set it --- since the inode
116 	 * scanning functions require it.
117 	 */
118 	if (fs->badblocks == 0) {
119 		/*
120 		 * Temporarly save fs->get_blocks and set it to zero,
121 		 * for compatibility with old e2fsck's.
122 		 */
123 		save_get_blocks = fs->get_blocks;
124 		fs->get_blocks = 0;
125 		retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
126 		if (retval && fs->badblocks) {
127 			ext2fs_badblocks_list_free(fs->badblocks);
128 			fs->badblocks = 0;
129 		}
130 		fs->get_blocks = save_get_blocks;
131 	}
132 
133 	retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
134 	if (retval)
135 		return retval;
136 	memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
137 
138 	scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
139 	scan->fs = fs;
140 	scan->inode_size = EXT2_INODE_SIZE(fs->super);
141 	scan->bytes_left = 0;
142 	scan->current_group = 0;
143 	scan->groups_left = fs->group_desc_count - 1;
144 	scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
145 	scan->current_block = scan->fs->
146 		group_desc[scan->current_group].bg_inode_table;
147 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
148 	scan->blocks_left = scan->fs->inode_blocks_per_group;
149 	retval = ext2fs_get_array(scan->inode_buffer_blocks,
150 					  fs->blocksize,
151 				&scan->inode_buffer);
152 	scan->done_group = 0;
153 	scan->done_group_data = 0;
154 	scan->bad_block_ptr = 0;
155 	if (retval) {
156 		ext2fs_free_mem(&scan);
157 		return retval;
158 	}
159 	retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
160 	if (retval) {
161 		ext2fs_free_mem(&scan->inode_buffer);
162 		ext2fs_free_mem(&scan);
163 		return retval;
164 	}
165 	if (scan->fs->badblocks && scan->fs->badblocks->num)
166 		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
167 	if (EXT2_HAS_COMPAT_FEATURE(fs->super,
168 				    EXT2_FEATURE_COMPAT_LAZY_BG))
169 		scan->scan_flags |= EXT2_SF_DO_LAZY;
170 	*ret_scan = scan;
171 	return 0;
172 }
173 
ext2fs_close_inode_scan(ext2_inode_scan scan)174 void ext2fs_close_inode_scan(ext2_inode_scan scan)
175 {
176 	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
177 		return;
178 
179 	ext2fs_free_mem(&scan->inode_buffer);
180 	scan->inode_buffer = NULL;
181 	ext2fs_free_mem(&scan->temp_buffer);
182 	scan->temp_buffer = NULL;
183 	ext2fs_free_mem(&scan);
184 	return;
185 }
186 
ext2fs_set_inode_callback(ext2_inode_scan scan,errcode_t (* done_group)(ext2_filsys fs,ext2_inode_scan scan,dgrp_t group,void * priv_data),void * done_group_data)187 void ext2fs_set_inode_callback(ext2_inode_scan scan,
188 			       errcode_t (*done_group)(ext2_filsys fs,
189 						       ext2_inode_scan scan,
190 						       dgrp_t group,
191 						       void * priv_data),
192 			       void *done_group_data)
193 {
194 	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
195 		return;
196 
197 	scan->done_group = done_group;
198 	scan->done_group_data = done_group_data;
199 }
200 
ext2fs_inode_scan_flags(ext2_inode_scan scan,int set_flags,int clear_flags)201 int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
202 			    int clear_flags)
203 {
204 	int	old_flags;
205 
206 	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
207 		return 0;
208 
209 	old_flags = scan->scan_flags;
210 	scan->scan_flags &= ~clear_flags;
211 	scan->scan_flags |= set_flags;
212 	return old_flags;
213 }
214 
215 /*
216  * This function is called by ext2fs_get_next_inode when it needs to
217  * get ready to read in a new blockgroup.
218  */
get_next_blockgroup(ext2_inode_scan scan)219 static errcode_t get_next_blockgroup(ext2_inode_scan scan)
220 {
221 	scan->current_group++;
222 	scan->groups_left--;
223 
224 	scan->current_block = scan->fs->
225 		group_desc[scan->current_group].bg_inode_table;
226 
227 	scan->current_inode = scan->current_group *
228 		EXT2_INODES_PER_GROUP(scan->fs->super);
229 
230 	scan->bytes_left = 0;
231 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
232 	scan->blocks_left = scan->fs->inode_blocks_per_group;
233 	return 0;
234 }
235 
ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,int group)236 errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
237 					    int	group)
238 {
239 	scan->current_group = group - 1;
240 	scan->groups_left = scan->fs->group_desc_count - group;
241 	return get_next_blockgroup(scan);
242 }
243 
244 /*
245  * This function is called by get_next_blocks() to check for bad
246  * blocks in the inode table.
247  *
248  * This function assumes that badblocks_list->list is sorted in
249  * increasing order.
250  */
check_for_inode_bad_blocks(ext2_inode_scan scan,blk_t * num_blocks)251 static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
252 					    blk_t *num_blocks)
253 {
254 	blk_t	blk = scan->current_block;
255 	badblocks_list	bb = scan->fs->badblocks;
256 
257 	/*
258 	 * If the inode table is missing, then obviously there are no
259 	 * bad blocks.  :-)
260 	 */
261 	if (blk == 0)
262 		return 0;
263 
264 	/*
265 	 * If the current block is greater than the bad block listed
266 	 * in the bad block list, then advance the pointer until this
267 	 * is no longer the case.  If we run out of bad blocks, then
268 	 * we don't need to do any more checking!
269 	 */
270 	while (blk > bb->list[scan->bad_block_ptr]) {
271 		if (++scan->bad_block_ptr >= bb->num) {
272 			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
273 			return 0;
274 		}
275 	}
276 
277 	/*
278 	 * If the current block is equal to the bad block listed in
279 	 * the bad block list, then handle that one block specially.
280 	 * (We could try to handle runs of bad blocks, but that
281 	 * only increases CPU efficiency by a small amount, at the
282 	 * expense of a huge expense of code complexity, and for an
283 	 * uncommon case at that.)
284 	 */
285 	if (blk == bb->list[scan->bad_block_ptr]) {
286 		scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
287 		*num_blocks = 1;
288 		if (++scan->bad_block_ptr >= bb->num)
289 			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
290 		return 0;
291 	}
292 
293 	/*
294 	 * If there is a bad block in the range that we're about to
295 	 * read in, adjust the number of blocks to read so that we we
296 	 * don't read in the bad block.  (Then the next block to read
297 	 * will be the bad block, which is handled in the above case.)
298 	 */
299 	if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
300 		*num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
301 
302 	return 0;
303 }
304 
305 /*
306  * This function is called by ext2fs_get_next_inode when it needs to
307  * read in more blocks from the current blockgroup's inode table.
308  */
get_next_blocks(ext2_inode_scan scan)309 static errcode_t get_next_blocks(ext2_inode_scan scan)
310 {
311 	blk_t		num_blocks;
312 	errcode_t	retval;
313 
314 	/*
315 	 * Figure out how many blocks to read; we read at most
316 	 * inode_buffer_blocks, and perhaps less if there aren't that
317 	 * many blocks left to read.
318 	 */
319 	num_blocks = scan->inode_buffer_blocks;
320 	if (num_blocks > scan->blocks_left)
321 		num_blocks = scan->blocks_left;
322 
323 	/*
324 	 * If the past block "read" was a bad block, then mark the
325 	 * left-over extra bytes as also being bad.
326 	 */
327 	if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
328 		if (scan->bytes_left)
329 			scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
330 		scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
331 	}
332 
333 	/*
334 	 * Do inode bad block processing, if necessary.
335 	 */
336 	if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
337 		retval = check_for_inode_bad_blocks(scan, &num_blocks);
338 		if (retval)
339 			return retval;
340 	}
341 
342 	if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
343 	    (scan->current_block == 0)) {
344 		memset(scan->inode_buffer, 0,
345 		       (size_t) num_blocks * scan->fs->blocksize);
346 	} else {
347 		retval = io_channel_read_blk(scan->fs->io,
348 					     scan->current_block,
349 					     (int) num_blocks,
350 					     scan->inode_buffer);
351 		if (retval)
352 			return EXT2_ET_NEXT_INODE_READ;
353 	}
354 	scan->ptr = scan->inode_buffer;
355 	scan->bytes_left = num_blocks * scan->fs->blocksize;
356 
357 	scan->blocks_left -= num_blocks;
358 	if (scan->current_block)
359 		scan->current_block += num_blocks;
360 	return 0;
361 }
362 
363 #if 0
364 /*
365  * Returns 1 if the entire inode_buffer has a non-zero size and
366  * contains all zeros.  (Not just deleted inodes, since that means
367  * that part of the inode table was used at one point; we want all
368  * zeros, which means that the inode table is pristine.)
369  */
370 static inline int is_empty_scan(ext2_inode_scan scan)
371 {
372 	int	i;
373 
374 	if (scan->bytes_left == 0)
375 		return 0;
376 
377 	for (i=0; i < scan->bytes_left; i++)
378 		if (scan->ptr[i])
379 			return 0;
380 	return 1;
381 }
382 #endif
383 
ext2fs_get_next_inode_full(ext2_inode_scan scan,ext2_ino_t * ino,struct ext2_inode * inode,int bufsize)384 errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
385 				     struct ext2_inode *inode, int bufsize)
386 {
387 	errcode_t	retval;
388 	int		extra_bytes = 0;
389 
390 	EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
391 
392 	/*
393 	 * Do we need to start reading a new block group?
394 	 */
395 	if (scan->inodes_left <= 0) {
396 	force_new_group:
397 		if (scan->done_group) {
398 			retval = (scan->done_group)
399 				(scan->fs, scan, scan->current_group,
400 				 scan->done_group_data);
401 			if (retval)
402 				return retval;
403 		}
404 		if (scan->groups_left <= 0) {
405 			*ino = 0;
406 			return 0;
407 		}
408 		retval = get_next_blockgroup(scan);
409 		if (retval)
410 			return retval;
411 	}
412 	/*
413 	 * These checks are done outside the above if statement so
414 	 * they can be done for block group #0.
415 	 */
416 	if ((scan->scan_flags & EXT2_SF_DO_LAZY) &&
417 	    (scan->fs->group_desc[scan->current_group].bg_flags &
418 	     EXT2_BG_INODE_UNINIT))
419 		goto force_new_group;
420 	if (scan->current_block == 0) {
421 		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
422 			goto force_new_group;
423 		} else
424 			return EXT2_ET_MISSING_INODE_TABLE;
425 	}
426 
427 
428 	/*
429 	 * Have we run out of space in the inode buffer?  If so, we
430 	 * need to read in more blocks.
431 	 */
432 	if (scan->bytes_left < scan->inode_size) {
433 		memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
434 		extra_bytes = scan->bytes_left;
435 
436 		retval = get_next_blocks(scan);
437 		if (retval)
438 			return retval;
439 #if 0
440 		/*
441 		 * XXX test  Need check for used inode somehow.
442 		 * (Note: this is hard.)
443 		 */
444 		if (is_empty_scan(scan))
445 			goto force_new_group;
446 #endif
447 	}
448 
449 	retval = 0;
450 	if (extra_bytes) {
451 		memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
452 		       scan->inode_size - extra_bytes);
453 		scan->ptr += scan->inode_size - extra_bytes;
454 		scan->bytes_left -= scan->inode_size - extra_bytes;
455 
456 #ifdef EXT2FS_ENABLE_SWAPFS
457 		memset(inode, 0, bufsize);
458 		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
459 		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
460 			ext2fs_swap_inode_full(scan->fs,
461 				(struct ext2_inode_large *) inode,
462 				(struct ext2_inode_large *) scan->temp_buffer,
463 				0, bufsize);
464 		else
465 #endif
466 			*inode = *((struct ext2_inode *) scan->temp_buffer);
467 		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
468 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
469 		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
470 	} else {
471 #ifdef EXT2FS_ENABLE_SWAPFS
472 		memset(inode, 0, bufsize);
473 		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
474 		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
475 			ext2fs_swap_inode_full(scan->fs,
476 				(struct ext2_inode_large *) inode,
477 				(struct ext2_inode_large *) scan->ptr,
478 				0, bufsize);
479 		else
480 #endif
481 			memcpy(inode, scan->ptr, bufsize);
482 		scan->ptr += scan->inode_size;
483 		scan->bytes_left -= scan->inode_size;
484 		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
485 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
486 	}
487 
488 	scan->inodes_left--;
489 	scan->current_inode++;
490 	*ino = scan->current_inode;
491 	return retval;
492 }
493 
ext2fs_get_next_inode(ext2_inode_scan scan,ext2_ino_t * ino,struct ext2_inode * inode)494 errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
495 				struct ext2_inode *inode)
496 {
497 	return ext2fs_get_next_inode_full(scan, ino, inode,
498 						sizeof(struct ext2_inode));
499 }
500 
501 /*
502  * Functions to read and write a single inode.
503  */
ext2fs_read_inode_full(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode,int bufsize)504 errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
505 				 struct ext2_inode * inode, int bufsize)
506 {
507 	unsigned long 	group, block, block_nr, offset;
508 	char 		*ptr;
509 	errcode_t	retval;
510 	int 		clen, i, inodes_per_block, length;
511 	io_channel	io;
512 
513 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
514 
515 	/* Check to see if user has an override function */
516 	if (fs->read_inode) {
517 		retval = (fs->read_inode)(fs, ino, inode);
518 		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
519 			return retval;
520 	}
521 	/* Create inode cache if not present */
522 	if (!fs->icache) {
523 		retval = create_icache(fs);
524 		if (retval)
525 			return retval;
526 	}
527 	/* Check to see if it's in the inode cache */
528 	if (bufsize == sizeof(struct ext2_inode)) {
529 		/* only old good inode can be retrieve from the cache */
530 		for (i=0; i < fs->icache->cache_size; i++) {
531 			if (fs->icache->cache[i].ino == ino) {
532 				*inode = fs->icache->cache[i].inode;
533 				return 0;
534 			}
535 		}
536 	}
537 	if ((ino == 0) || (ino > fs->super->s_inodes_count))
538 		return EXT2_ET_BAD_INODE_NUM;
539 	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
540 		inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
541 		block_nr = fs->image_header->offset_inode / fs->blocksize;
542 		block_nr += (ino - 1) / inodes_per_block;
543 		offset = ((ino - 1) % inodes_per_block) *
544 			EXT2_INODE_SIZE(fs->super);
545 		io = fs->image_io;
546 	} else {
547 		group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
548 		offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
549 			EXT2_INODE_SIZE(fs->super);
550 		block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
551 		if (!fs->group_desc[(unsigned)group].bg_inode_table)
552 			return EXT2_ET_MISSING_INODE_TABLE;
553 		block_nr = fs->group_desc[(unsigned)group].bg_inode_table +
554 			block;
555 		io = fs->io;
556 	}
557 	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
558 
559 	length = EXT2_INODE_SIZE(fs->super);
560 	if (bufsize < length)
561 		length = bufsize;
562 
563 	ptr = (char *) inode;
564 	while (length) {
565 		clen = length;
566 		if ((offset + length) > fs->blocksize)
567 			clen = fs->blocksize - offset;
568 
569 		if (block_nr != fs->icache->buffer_blk) {
570 			retval = io_channel_read_blk(io, block_nr, 1,
571 						     fs->icache->buffer);
572 			if (retval)
573 				return retval;
574 			fs->icache->buffer_blk = block_nr;
575 		}
576 
577 		memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
578 		       clen);
579 
580 		offset = 0;
581 		length -= clen;
582 		ptr += clen;
583 		block_nr++;
584 	}
585 
586 #ifdef EXT2FS_ENABLE_SWAPFS
587 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
588 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
589 		ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
590 				       (struct ext2_inode_large *) inode,
591 				       0, bufsize);
592 #endif
593 
594 	/* Update the inode cache */
595 	fs->icache->cache_last = (fs->icache->cache_last + 1) %
596 		fs->icache->cache_size;
597 	fs->icache->cache[fs->icache->cache_last].ino = ino;
598 	fs->icache->cache[fs->icache->cache_last].inode = *inode;
599 
600 	return 0;
601 }
602 
ext2fs_read_inode(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode)603 errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
604 			    struct ext2_inode * inode)
605 {
606 	return ext2fs_read_inode_full(fs, ino, inode,
607 					sizeof(struct ext2_inode));
608 }
609 
ext2fs_write_inode_full(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode,int bufsize)610 errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
611 				  struct ext2_inode * inode, int bufsize)
612 {
613 	unsigned long group, block, block_nr, offset;
614 	errcode_t retval = 0;
615 	struct ext2_inode_large temp_inode, *w_inode;
616 	char *ptr;
617 	int clen, i, length;
618 
619 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
620 
621 	/* Check to see if user provided an override function */
622 	if (fs->write_inode) {
623 		retval = (fs->write_inode)(fs, ino, inode);
624 		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
625 			return retval;
626 	}
627 
628 	/* Check to see if the inode cache needs to be updated */
629 	if (fs->icache) {
630 		for (i=0; i < fs->icache->cache_size; i++) {
631 			if (fs->icache->cache[i].ino == ino) {
632 				fs->icache->cache[i].inode = *inode;
633 				break;
634 			}
635 		}
636 	} else {
637 		retval = create_icache(fs);
638 		if (retval)
639 			return retval;
640 	}
641 
642 	if (!(fs->flags & EXT2_FLAG_RW))
643 		return EXT2_ET_RO_FILSYS;
644 
645 	if ((ino == 0) || (ino > fs->super->s_inodes_count))
646 		return EXT2_ET_BAD_INODE_NUM;
647 
648 	length = bufsize;
649 	if (length < EXT2_INODE_SIZE(fs->super))
650 		length = EXT2_INODE_SIZE(fs->super);
651 
652 	if (length > (int) sizeof(struct ext2_inode_large)) {
653 		w_inode = malloc(length);
654 		if (!w_inode)
655 			return ENOMEM;
656 	} else
657 		w_inode = &temp_inode;
658 	memset(w_inode, 0, length);
659 
660 #ifdef EXT2FS_ENABLE_SWAPFS
661 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
662 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
663 		ext2fs_swap_inode_full(fs, w_inode,
664 				       (struct ext2_inode_large *) inode,
665 				       1, bufsize);
666 	else
667 #endif
668 		memcpy(w_inode, inode, bufsize);
669 
670 	group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
671 	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
672 		EXT2_INODE_SIZE(fs->super);
673 	block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
674 	if (!fs->group_desc[(unsigned) group].bg_inode_table) {
675 		retval = EXT2_ET_MISSING_INODE_TABLE;
676 		goto errout;
677 	}
678 	block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
679 
680 	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
681 
682 	length = EXT2_INODE_SIZE(fs->super);
683 	if (length > bufsize)
684 		length = bufsize;
685 
686 	ptr = (char *) w_inode;
687 
688 	while (length) {
689 		clen = length;
690 		if ((offset + length) > fs->blocksize)
691 			clen = fs->blocksize - offset;
692 
693 		if (fs->icache->buffer_blk != block_nr) {
694 			retval = io_channel_read_blk(fs->io, block_nr, 1,
695 						     fs->icache->buffer);
696 			if (retval)
697 				goto errout;
698 			fs->icache->buffer_blk = block_nr;
699 		}
700 
701 
702 		memcpy((char *) fs->icache->buffer + (unsigned) offset,
703 		       ptr, clen);
704 
705 		retval = io_channel_write_blk(fs->io, block_nr, 1,
706 					      fs->icache->buffer);
707 		if (retval)
708 			goto errout;
709 
710 		offset = 0;
711 		ptr += clen;
712 		length -= clen;
713 		block_nr++;
714 	}
715 
716 	fs->flags |= EXT2_FLAG_CHANGED;
717 errout:
718 	if (w_inode && w_inode != &temp_inode)
719 		free(w_inode);
720 	return retval;
721 }
722 
ext2fs_write_inode(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode)723 errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
724 			     struct ext2_inode *inode)
725 {
726 	return ext2fs_write_inode_full(fs, ino, inode,
727 				       sizeof(struct ext2_inode));
728 }
729 
730 /*
731  * This function should be called when writing a new inode.  It makes
732  * sure that extra part of large inodes is initialized properly.
733  */
ext2fs_write_new_inode(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode)734 errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
735 				 struct ext2_inode *inode)
736 {
737 	struct ext2_inode	*buf;
738 	int 			size = EXT2_INODE_SIZE(fs->super);
739 	struct ext2_inode_large	*large_inode;
740 	errcode_t		retval;
741 
742 	if (size == sizeof(struct ext2_inode))
743 		return ext2fs_write_inode_full(fs, ino, inode,
744 					       sizeof(struct ext2_inode));
745 
746 	buf = malloc(size);
747 	if (!buf)
748 		return ENOMEM;
749 
750 	memset(buf, 0, size);
751 	*buf = *inode;
752 
753 	large_inode = (struct ext2_inode_large *) buf;
754 	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
755 		EXT2_GOOD_OLD_INODE_SIZE;
756 
757 	retval = ext2fs_write_inode_full(fs, ino, buf, size);
758 	free(buf);
759 	return retval;
760 }
761 
762 
ext2fs_get_blocks(ext2_filsys fs,ext2_ino_t ino,blk_t * blocks)763 errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
764 {
765 	struct ext2_inode	inode;
766 	int			i;
767 	errcode_t		retval;
768 
769 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
770 
771 	if (ino > fs->super->s_inodes_count)
772 		return EXT2_ET_BAD_INODE_NUM;
773 
774 	if (fs->get_blocks) {
775 		if (!(*fs->get_blocks)(fs, ino, blocks))
776 			return 0;
777 	}
778 	retval = ext2fs_read_inode(fs, ino, &inode);
779 	if (retval)
780 		return retval;
781 	for (i=0; i < EXT2_N_BLOCKS; i++)
782 		blocks[i] = inode.i_block[i];
783 	return 0;
784 }
785 
ext2fs_check_directory(ext2_filsys fs,ext2_ino_t ino)786 errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
787 {
788 	struct	ext2_inode	inode;
789 	errcode_t		retval;
790 
791 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
792 
793 	if (ino > fs->super->s_inodes_count)
794 		return EXT2_ET_BAD_INODE_NUM;
795 
796 	if (fs->check_directory) {
797 		retval = (fs->check_directory)(fs, ino);
798 		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
799 			return retval;
800 	}
801 	retval = ext2fs_read_inode(fs, ino, &inode);
802 	if (retval)
803 		return retval;
804 	if (!LINUX_S_ISDIR(inode.i_mode))
805 		return EXT2_ET_NO_DIRECTORY;
806 	return 0;
807 }
808 
809