Remove old_e2fsprogs/*
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		| @@ -1,69 +0,0 @@ | ||||
| # | ||||
| # For a description of the syntax of this configuration file, | ||||
| # see scripts/kbuild/config-language.txt. | ||||
| # | ||||
|  | ||||
| menu "Linux Ext2 FS Progs" | ||||
|  | ||||
| INSERT | ||||
|  | ||||
| config CHATTR | ||||
| 	bool "chattr" | ||||
| 	default n | ||||
| 	help | ||||
| 	  chattr changes the file attributes on a second extended file system. | ||||
|  | ||||
| config E2FSCK | ||||
| 	bool "e2fsck" | ||||
| 	default n | ||||
| 	help | ||||
| 	  e2fsck is used to check Linux second extended file systems (ext2fs). | ||||
| 	  e2fsck also supports ext2 filesystems countaining a journal (ext3). | ||||
| 	  The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also | ||||
| 	  provided. | ||||
|  | ||||
| config FSCK | ||||
| 	bool "fsck" | ||||
| 	default n | ||||
| 	help | ||||
| 	  fsck is used to check and optionally repair one or more filesystems. | ||||
| 	  In actuality, fsck is simply a front-end for the various file system | ||||
| 	  checkers (fsck.fstype) available under Linux. | ||||
|  | ||||
| config LSATTR | ||||
| 	bool "lsattr" | ||||
| 	default n | ||||
| 	help | ||||
| 	  lsattr lists the file attributes on a second extended file system. | ||||
|  | ||||
| config MKE2FS | ||||
| 	bool "mke2fs" | ||||
| 	default n | ||||
| 	help | ||||
| 	  mke2fs is used to create an ext2/ext3 filesystem. The normal compat | ||||
| 	  symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided. | ||||
|  | ||||
| config TUNE2FS | ||||
| 	bool "tune2fs" | ||||
| 	default n | ||||
| 	help | ||||
| 	  tune2fs allows the system administrator to adjust various tunable | ||||
| 	  filesystem parameters on Linux ext2/ext3 filesystems. | ||||
|  | ||||
| config E2LABEL | ||||
| 	bool "e2label" | ||||
| 	default n | ||||
| 	depends on TUNE2FS | ||||
| 	help | ||||
| 	  e2label will display or change the filesystem label on the ext2 | ||||
| 	  filesystem located on device. | ||||
|  | ||||
| config FINDFS | ||||
| 	bool "findfs" | ||||
| 	default n | ||||
| 	depends on TUNE2FS | ||||
| 	help | ||||
| 	  findfs will search the disks in the system looking for a filesystem | ||||
| 	  which has a label matching label or a UUID equal to uuid. | ||||
|  | ||||
| endmenu | ||||
| @@ -1,18 +0,0 @@ | ||||
| # Makefile for busybox | ||||
| # | ||||
| # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> | ||||
| # | ||||
| # Licensed under GPLv2, see file LICENSE in this source tree. | ||||
|  | ||||
| lib-y:= | ||||
|  | ||||
| INSERT | ||||
|  | ||||
| lib-$(CONFIG_CHATTR)     += chattr.o | ||||
| lib-$(CONFIG_E2FSCK)     += e2fsck.o util.o | ||||
| lib-$(CONFIG_FSCK)       += fsck.o util.o | ||||
| lib-$(CONFIG_LSATTR)     += lsattr.o | ||||
| lib-$(CONFIG_MKE2FS)     += mke2fs.o util.o | ||||
| lib-$(CONFIG_TUNE2FS)    += tune2fs.o util.o | ||||
|  | ||||
| CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h | ||||
| @@ -1,3 +0,0 @@ | ||||
| This is a pretty straight rip from the e2fsprogs pkg. | ||||
|  | ||||
| See README's in subdirs for specific info. | ||||
| @@ -1,26 +0,0 @@ | ||||
| # Makefile for busybox | ||||
| # | ||||
| # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> | ||||
| # | ||||
| # Licensed under GPLv2, see file LICENSE in this source tree. | ||||
|  | ||||
| NEEDED-$(CONFIG_E2FSCK) = y | ||||
| NEEDED-$(CONFIG_FSCK) = y | ||||
| NEEDED-$(CONFIG_MKE2FS) = y | ||||
| NEEDED-$(CONFIG_TUNE2FS) = y | ||||
|  | ||||
| lib-y:= | ||||
|  | ||||
| INSERT | ||||
|  | ||||
| lib-$(NEEDED-y) += cache.o dev.o devname.o devno.o blkid_getsize.o \ | ||||
|                    probe.o read.o resolve.o save.o tag.o list.o | ||||
|  | ||||
| CFLAGS_dev.o     := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_devname.o := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_devno.o   := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_blkid_getsize.o := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_probe.o   := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_save.o    := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_tag.o     := -include $(srctree)/include/busybox.h | ||||
| CFLAGS_list.o    := -include $(srctree)/include/busybox.h | ||||
| @@ -1,104 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * blkid.h - Interface for libblkid, a library to identify block devices | ||||
|  * | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * Copyright (C) 2003 Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
| #ifndef BLKID_BLKID_H | ||||
| #define BLKID_BLKID_H 1 | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <linux/types.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #define BLKID_VERSION	"1.0.0" | ||||
| #define BLKID_DATE	"12-Feb-2003" | ||||
|  | ||||
| typedef struct blkid_struct_dev *blkid_dev; | ||||
| typedef struct blkid_struct_cache *blkid_cache; | ||||
| typedef __s64 blkid_loff_t; | ||||
|  | ||||
| typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; | ||||
| typedef struct blkid_struct_dev_iterate *blkid_dev_iterate; | ||||
|  | ||||
| /* | ||||
|  * Flags for blkid_get_dev | ||||
|  * | ||||
|  * BLKID_DEV_CREATE	Create an empty device structure if not found | ||||
|  *			in the cache. | ||||
|  * BLKID_DEV_VERIFY	Make sure the device structure corresponds | ||||
|  *			with reality. | ||||
|  * BLKID_DEV_FIND	Just look up a device entry, and return NULL | ||||
|  *			if it is not found. | ||||
|  * BLKID_DEV_NORMAL	Get a valid device structure, either from the | ||||
|  *			cache or by probing the device. | ||||
|  */ | ||||
| #define BLKID_DEV_FIND		0x0000 | ||||
| #define BLKID_DEV_CREATE	0x0001 | ||||
| #define BLKID_DEV_VERIFY	0x0002 | ||||
| #define BLKID_DEV_NORMAL	(BLKID_DEV_CREATE | BLKID_DEV_VERIFY) | ||||
|  | ||||
| /* cache.c */ | ||||
| extern void blkid_put_cache(blkid_cache cache); | ||||
| extern int blkid_get_cache(blkid_cache *cache, const char *filename); | ||||
|  | ||||
| /* dev.c */ | ||||
| extern const char *blkid_dev_devname(blkid_dev dev); | ||||
|  | ||||
| extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache); | ||||
| extern int blkid_dev_set_search(blkid_dev_iterate iter, | ||||
| 				char *search_type, char *search_value); | ||||
| extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev); | ||||
| extern void blkid_dev_iterate_end(blkid_dev_iterate iterate); | ||||
|  | ||||
| /* devno.c */ | ||||
| extern char *blkid_devno_to_devname(dev_t devno); | ||||
|  | ||||
| /* devname.c */ | ||||
| extern int blkid_probe_all(blkid_cache cache); | ||||
| extern int blkid_probe_all_new(blkid_cache cache); | ||||
| extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, | ||||
| 			       int flags); | ||||
|  | ||||
| /* getsize.c */ | ||||
| extern blkid_loff_t blkid_get_dev_size(int fd); | ||||
|  | ||||
| /* probe.c */ | ||||
| int blkid_known_fstype(const char *fstype); | ||||
| extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); | ||||
|  | ||||
| /* read.c */ | ||||
|  | ||||
| /* resolve.c */ | ||||
| extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, | ||||
| 				       const char *devname); | ||||
| extern char *blkid_get_devname(blkid_cache cache, const char *token, | ||||
| 			       const char *value); | ||||
|  | ||||
| /* tag.c */ | ||||
| extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev); | ||||
| extern int blkid_tag_next(blkid_tag_iterate iterate, | ||||
| 			      const char **type, const char **value); | ||||
| extern void blkid_tag_iterate_end(blkid_tag_iterate iterate); | ||||
| extern int blkid_dev_has_tag(blkid_dev dev, const char *type, | ||||
| 			      const char *value); | ||||
| extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, | ||||
| 					 const char *type, | ||||
| 					 const char *value); | ||||
| extern int blkid_parse_tag_string(const char *token, char **ret_type, | ||||
| 				  char **ret_val); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,182 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * blkidP.h - Internal interfaces for libblkid | ||||
|  * | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * Copyright (C) 2003 Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
| #ifndef BLKID_BLKIDP_H | ||||
| #define BLKID_BLKIDP_H 1 | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "blkid.h" | ||||
| #include "list.h" | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #define __BLKID_ATTR(x) __attribute__(x) | ||||
| #else | ||||
| #define __BLKID_ATTR(x) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This describes the attributes of a specific device. | ||||
|  * We can traverse all of the tags by bid_tags (linking to the tag bit_names). | ||||
|  * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag | ||||
|  * values, if they exist. | ||||
|  */ | ||||
| struct blkid_struct_dev | ||||
| { | ||||
| 	struct list_head	bid_devs;	/* All devices in the cache */ | ||||
| 	struct list_head	bid_tags;	/* All tags for this device */ | ||||
| 	blkid_cache		bid_cache;	/* Dev belongs to this cache */ | ||||
| 	char			*bid_name;	/* Device inode pathname */ | ||||
| 	char			*bid_type;	/* Preferred device TYPE */ | ||||
| 	int			bid_pri;	/* Device priority */ | ||||
| 	dev_t			bid_devno;	/* Device major/minor number */ | ||||
| 	time_t			bid_time;	/* Last update time of device */ | ||||
| 	unsigned int		bid_flags;	/* Device status bitflags */ | ||||
| 	char			*bid_label;	/* Shortcut to device LABEL */ | ||||
| 	char			*bid_uuid;	/* Shortcut to binary UUID */ | ||||
| }; | ||||
|  | ||||
| #define BLKID_BID_FL_VERIFIED	0x0001	/* Device data validated from disk */ | ||||
| #define BLKID_BID_FL_INVALID	0x0004	/* Device is invalid */ | ||||
|  | ||||
| /* | ||||
|  * Each tag defines a NAME=value pair for a particular device.  The tags | ||||
|  * are linked via bit_names for a single device, so that traversing the | ||||
|  * names list will get you a list of all tags associated with a device. | ||||
|  * They are also linked via bit_values for all devices, so one can easily | ||||
|  * search all tags with a given NAME for a specific value. | ||||
|  */ | ||||
| struct blkid_struct_tag | ||||
| { | ||||
| 	struct list_head	bit_tags;	/* All tags for this device */ | ||||
| 	struct list_head	bit_names;	/* All tags with given NAME */ | ||||
| 	char			*bit_name;	/* NAME of tag (shared) */ | ||||
| 	char			*bit_val;	/* value of tag */ | ||||
| 	blkid_dev		bit_dev;	/* pointer to device */ | ||||
| }; | ||||
| typedef struct blkid_struct_tag *blkid_tag; | ||||
|  | ||||
| /* | ||||
|  * Minimum number of seconds between device probes, even when reading | ||||
|  * from the cache.  This is to avoid re-probing all devices which were | ||||
|  * just probed by another program that does not share the cache. | ||||
|  */ | ||||
| #define BLKID_PROBE_MIN		2 | ||||
|  | ||||
| /* | ||||
|  * Time in seconds an entry remains verified in the in-memory cache | ||||
|  * before being reverified (in case of long-running processes that | ||||
|  * keep a cache in memory and continue to use it for a long time). | ||||
|  */ | ||||
| #define BLKID_PROBE_INTERVAL	200 | ||||
|  | ||||
| /* This describes an entire blkid cache file and probed devices. | ||||
|  * We can traverse all of the found devices via bic_list. | ||||
|  * We can traverse all of the tag types by bic_tags, which hold empty tags | ||||
|  * for each tag type.  Those tags can be used as list_heads for iterating | ||||
|  * through all devices with a specific tag type (e.g. LABEL). | ||||
|  */ | ||||
| struct blkid_struct_cache | ||||
| { | ||||
| 	struct list_head	bic_devs;	/* List head of all devices */ | ||||
| 	struct list_head	bic_tags;	/* List head of all tag types */ | ||||
| 	time_t			bic_time;	/* Last probe time */ | ||||
| 	time_t			bic_ftime;	/* Mod time of the cachefile */ | ||||
| 	unsigned int		bic_flags;	/* Status flags of the cache */ | ||||
| 	char			*bic_filename;	/* filename of cache */ | ||||
| }; | ||||
|  | ||||
| #define BLKID_BIC_FL_PROBED	0x0002	/* We probed /proc/partition devices */ | ||||
| #define BLKID_BIC_FL_CHANGED	0x0004	/* Cache has changed from disk */ | ||||
|  | ||||
| extern char *blkid_strdup(const char *s); | ||||
| extern char *blkid_strndup(const char *s, const int length); | ||||
|  | ||||
| #define BLKID_CACHE_FILE "/etc/blkid.tab" | ||||
| extern const char *blkid_devdirs[]; | ||||
|  | ||||
| #define BLKID_ERR_IO	 5 | ||||
| #define BLKID_ERR_PROC	 9 | ||||
| #define BLKID_ERR_MEM	12 | ||||
| #define BLKID_ERR_CACHE	14 | ||||
| #define BLKID_ERR_DEV	19 | ||||
| #define BLKID_ERR_PARAM	22 | ||||
| #define BLKID_ERR_BIG	27 | ||||
|  | ||||
| /* | ||||
|  * Priority settings for different types of devices | ||||
|  */ | ||||
| #define BLKID_PRI_EVMS	30 | ||||
| #define BLKID_PRI_LVM	20 | ||||
| #define BLKID_PRI_MD	10 | ||||
|  | ||||
| #if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG) | ||||
| #define CONFIG_BLKID_DEBUG | ||||
| #endif | ||||
|  | ||||
| #define DEBUG_CACHE	0x0001 | ||||
| #define DEBUG_DUMP	0x0002 | ||||
| #define DEBUG_DEV	0x0004 | ||||
| #define DEBUG_DEVNAME	0x0008 | ||||
| #define DEBUG_DEVNO	0x0010 | ||||
| #define DEBUG_PROBE	0x0020 | ||||
| #define DEBUG_READ	0x0040 | ||||
| #define DEBUG_RESOLVE	0x0080 | ||||
| #define DEBUG_SAVE	0x0100 | ||||
| #define DEBUG_TAG	0x0200 | ||||
| #define DEBUG_INIT	0x8000 | ||||
| #define DEBUG_ALL	0xFFFF | ||||
|  | ||||
| #ifdef CONFIG_BLKID_DEBUG | ||||
| #include <stdio.h> | ||||
| extern int      blkid_debug_mask; | ||||
| #define DBG(m,x)	if ((m) & blkid_debug_mask) x; | ||||
| #else | ||||
| #define DBG(m,x) | ||||
| #endif | ||||
|  | ||||
| #ifdef CONFIG_BLKID_DEBUG | ||||
| extern void blkid_debug_dump_dev(blkid_dev dev); | ||||
| extern void blkid_debug_dump_tag(blkid_tag tag); | ||||
| #endif | ||||
|  | ||||
| /* lseek.c */ | ||||
| /* extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); */ | ||||
| #ifdef CONFIG_LFS | ||||
| # define blkid_llseek lseek64 | ||||
| #else | ||||
| # define blkid_llseek lseek | ||||
| #endif | ||||
|  | ||||
| /* read.c */ | ||||
| extern void blkid_read_cache(blkid_cache cache); | ||||
|  | ||||
| /* save.c */ | ||||
| extern int blkid_flush_cache(blkid_cache cache); | ||||
|  | ||||
| /* | ||||
|  * Functions to create and find a specific tag type: tag.c | ||||
|  */ | ||||
| extern void blkid_free_tag(blkid_tag tag); | ||||
| extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type); | ||||
| extern int blkid_set_tag(blkid_dev dev, const char *name, | ||||
| 			 const char *value, const int vlength); | ||||
|  | ||||
| /* | ||||
|  * Functions to create and find a specific tag type: dev.c | ||||
|  */ | ||||
| extern blkid_dev blkid_new_dev(void); | ||||
| extern void blkid_free_dev(blkid_dev dev); | ||||
|  | ||||
| #endif | ||||
| @@ -1,179 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * getsize.c --- get the size of a partition. | ||||
|  * | ||||
|  * Copyright (C) 1995, 1995 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| /* include this before sys/queues.h! */ | ||||
| #include "blkidP.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #ifdef HAVE_SYS_IOCTL_H | ||||
| #include <sys/ioctl.h> | ||||
| #endif | ||||
| #ifdef HAVE_LINUX_FD_H | ||||
| #include <linux/fd.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISKLABEL_H | ||||
| #include <sys/disklabel.h> | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISK_H | ||||
| #ifdef HAVE_SYS_QUEUE_H | ||||
| #include <sys/queue.h> /* for LIST_HEAD */ | ||||
| #endif | ||||
| #include <sys/disk.h> | ||||
| #endif | ||||
| #ifdef __linux__ | ||||
| #include <sys/utsname.h> | ||||
| #endif | ||||
|  | ||||
| #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) | ||||
| #define BLKGETSIZE _IO(0x12,96)	/* return device size */ | ||||
| #endif | ||||
|  | ||||
| #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) | ||||
| #define BLKGETSIZE64 _IOR(0x12,114,size_t)	/* return device size in bytes (u64 *arg) */ | ||||
| #endif | ||||
|  | ||||
| #ifdef APPLE_DARWIN | ||||
| #define BLKGETSIZE DKIOCGETBLOCKCOUNT32 | ||||
| #endif /* APPLE_DARWIN */ | ||||
|  | ||||
| static int valid_offset(int fd, blkid_loff_t offset) | ||||
| { | ||||
| 	char ch; | ||||
|  | ||||
| 	if (blkid_llseek(fd, offset, 0) < 0) | ||||
| 		return 0; | ||||
| 	if (read(fd, &ch, 1) < 1) | ||||
| 		return 0; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the number of blocks in a partition | ||||
|  */ | ||||
| blkid_loff_t blkid_get_dev_size(int fd) | ||||
| { | ||||
| 	int valid_blkgetsize64 = 1; | ||||
| #ifdef __linux__ | ||||
| 	struct		utsname ut; | ||||
| #endif | ||||
| 	unsigned long long size64; | ||||
| 	unsigned long size; | ||||
| 	blkid_loff_t high, low; | ||||
| #ifdef FDGETPRM | ||||
| 	struct floppy_struct this_floppy; | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISKLABEL_H | ||||
| 	int part = -1; | ||||
| 	struct disklabel lab; | ||||
| 	struct partition *pp; | ||||
| 	char ch; | ||||
| 	struct stat st; | ||||
| #endif /* HAVE_SYS_DISKLABEL_H */ | ||||
|  | ||||
| #ifdef DKIOCGETBLOCKCOUNT	/* For Apple Darwin */ | ||||
| 	if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) { | ||||
| 		if ((sizeof(blkid_loff_t) < sizeof(unsigned long long)) | ||||
| 		    && (size64 << 9 > 0xFFFFFFFF)) | ||||
| 			return 0; /* EFBIG */ | ||||
| 		return (blkid_loff_t) size64 << 9; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef BLKGETSIZE64 | ||||
| #ifdef __linux__ | ||||
| 	uname(&ut); | ||||
| 	if ((ut.release[0] == '2') && (ut.release[1] == '.') && | ||||
| 	     (ut.release[2] < '6') && (ut.release[3] == '.')) | ||||
| 		valid_blkgetsize64 = 0; | ||||
| #endif | ||||
| 	if (valid_blkgetsize64 && | ||||
| 	    ioctl(fd, BLKGETSIZE64, &size64) >= 0) { | ||||
| 		if ((sizeof(blkid_loff_t) < sizeof(unsigned long long)) | ||||
| 		    && ((size64) > 0xFFFFFFFF)) | ||||
| 			return 0; /* EFBIG */ | ||||
| 		return size64; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef BLKGETSIZE | ||||
| 	if (ioctl(fd, BLKGETSIZE, &size) >= 0) | ||||
| 		return (blkid_loff_t)size << 9; | ||||
| #endif | ||||
|  | ||||
| #ifdef FDGETPRM | ||||
| 	if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) | ||||
| 		return (blkid_loff_t)this_floppy.size << 9; | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISKLABEL_H | ||||
| #if 0 | ||||
| 	/* | ||||
| 	 * This should work in theory but I haven't tested it.  Anyone | ||||
| 	 * on a BSD system want to test this for me?  In the meantime, | ||||
| 	 * binary search mechanism should work just fine. | ||||
| 	 */ | ||||
| 	if ((fstat(fd, &st) >= 0) && S_ISBLK(st.st_mode)) | ||||
| 		part = st.st_rdev & 7; | ||||
| 	if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { | ||||
| 		pp = &lab.d_partitions[part]; | ||||
| 		if (pp->p_size) | ||||
| 			return pp->p_size << 9; | ||||
| 	} | ||||
| #endif | ||||
| #endif /* HAVE_SYS_DISKLABEL_H */ | ||||
|  | ||||
| 	/* | ||||
| 	 * OK, we couldn't figure it out by using a specialized ioctl, | ||||
| 	 * which is generally the best way.  So do binary search to | ||||
| 	 * find the size of the partition. | ||||
| 	 */ | ||||
| 	low = 0; | ||||
| 	for (high = 1024; valid_offset(fd, high); high *= 2) | ||||
| 		low = high; | ||||
| 	while (low < high - 1) | ||||
| 	{ | ||||
| 		const blkid_loff_t mid = (low + high) / 2; | ||||
|  | ||||
| 		if (valid_offset(fd, mid)) | ||||
| 			low = mid; | ||||
| 		else | ||||
| 			high = mid; | ||||
| 	} | ||||
| 	return low + 1; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blkid_loff_t bytes; | ||||
| 	int	fd; | ||||
|  | ||||
| 	if (argc < 2) { | ||||
| 		fprintf(stderr, "Usage: %s device\n" | ||||
| 			"Determine the size of a device\n", argv[0]); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if ((fd = open(argv[1], O_RDONLY)) < 0) | ||||
| 		perror(argv[0]); | ||||
|  | ||||
| 	bytes = blkid_get_dev_size(fd); | ||||
| 	printf("Device %s has %lld 1k blocks.\n", argv[1], bytes >> 10); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,125 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * cache.c - allocation/initialization/free routines for cache | ||||
|  * | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * Copyright (C) 2003 Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include "blkidP.h" | ||||
|  | ||||
| int blkid_debug_mask = 0; | ||||
|  | ||||
| int blkid_get_cache(blkid_cache *ret_cache, const char *filename) | ||||
| { | ||||
| 	blkid_cache cache; | ||||
|  | ||||
| #ifdef CONFIG_BLKID_DEBUG | ||||
| 	if (!(blkid_debug_mask & DEBUG_INIT)) { | ||||
| 		char *dstr = getenv("BLKID_DEBUG"); | ||||
|  | ||||
| 		if (dstr) | ||||
| 			blkid_debug_mask = strtoul(dstr, 0, 0); | ||||
| 		blkid_debug_mask |= DEBUG_INIT; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n", | ||||
| 				filename ? filename : "default cache")); | ||||
|  | ||||
| 	cache = xzalloc(sizeof(struct blkid_struct_cache)); | ||||
|  | ||||
| 	INIT_LIST_HEAD(&cache->bic_devs); | ||||
| 	INIT_LIST_HEAD(&cache->bic_tags); | ||||
|  | ||||
| 	if (filename && !strlen(filename)) | ||||
| 		filename = 0; | ||||
| 	if (!filename && (getuid() == geteuid())) | ||||
| 		filename = getenv("BLKID_FILE"); | ||||
| 	if (!filename) | ||||
| 		filename = BLKID_CACHE_FILE; | ||||
| 	cache->bic_filename = blkid_strdup(filename); | ||||
|  | ||||
| 	blkid_read_cache(cache); | ||||
|  | ||||
| 	*ret_cache = cache; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void blkid_put_cache(blkid_cache cache) | ||||
| { | ||||
| 	if (!cache) | ||||
| 		return; | ||||
|  | ||||
| 	(void) blkid_flush_cache(cache); | ||||
|  | ||||
| 	DBG(DEBUG_CACHE, printf("freeing cache struct\n")); | ||||
|  | ||||
| 	/* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */ | ||||
|  | ||||
| 	while (!list_empty(&cache->bic_devs)) { | ||||
| 		blkid_dev dev = list_entry(cache->bic_devs.next, | ||||
| 					   struct blkid_struct_dev, | ||||
| 					    bid_devs); | ||||
| 		blkid_free_dev(dev); | ||||
| 	} | ||||
|  | ||||
| 	while (!list_empty(&cache->bic_tags)) { | ||||
| 		blkid_tag tag = list_entry(cache->bic_tags.next, | ||||
| 					   struct blkid_struct_tag, | ||||
| 					   bit_tags); | ||||
|  | ||||
| 		while (!list_empty(&tag->bit_names)) { | ||||
| 			blkid_tag bad = list_entry(tag->bit_names.next, | ||||
| 						   struct blkid_struct_tag, | ||||
| 						   bit_names); | ||||
|  | ||||
| 			DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n", | ||||
| 						bad->bit_name, bad->bit_val)); | ||||
| 			blkid_free_tag(bad); | ||||
| 		} | ||||
| 		blkid_free_tag(tag); | ||||
| 	} | ||||
| 	free(cache->bic_filename); | ||||
|  | ||||
| 	free(cache); | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	blkid_cache cache = NULL; | ||||
| 	int ret; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if ((argc > 2)) { | ||||
| 		fprintf(stderr, "Usage: %s [filename]\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	if ((ret = blkid_get_cache(&cache, argv[1])) < 0) { | ||||
| 		fprintf(stderr, "error %d parsing cache file %s\n", ret, | ||||
| 			argv[1] ? argv[1] : BLKID_CACHE_FILE); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) { | ||||
| 		fprintf(stderr, "%s: error creating cache (%d)\n", | ||||
| 			argv[0], ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if ((ret = blkid_probe_all(cache)) < 0) | ||||
| 		fprintf(stderr, "error probing devices\n"); | ||||
|  | ||||
| 	blkid_put_cache(cache); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| @@ -1,212 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dev.c - allocation/initialization/free routines for dev | ||||
|  * | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * Copyright (C) 2003 Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "blkidP.h" | ||||
|  | ||||
| blkid_dev blkid_new_dev(void) | ||||
| { | ||||
| 	blkid_dev dev; | ||||
|  | ||||
| 	dev = xzalloc(sizeof(struct blkid_struct_dev)); | ||||
|  | ||||
| 	INIT_LIST_HEAD(&dev->bid_devs); | ||||
| 	INIT_LIST_HEAD(&dev->bid_tags); | ||||
|  | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| void blkid_free_dev(blkid_dev dev) | ||||
| { | ||||
| 	if (!dev) | ||||
| 		return; | ||||
|  | ||||
| 	DBG(DEBUG_DEV, | ||||
| 	    printf("  freeing dev %s (%s)\n", dev->bid_name, dev->bid_type)); | ||||
| 	DBG(DEBUG_DEV, blkid_debug_dump_dev(dev)); | ||||
|  | ||||
| 	list_del(&dev->bid_devs); | ||||
| 	while (!list_empty(&dev->bid_tags)) { | ||||
| 		blkid_tag tag = list_entry(dev->bid_tags.next, | ||||
| 					   struct blkid_struct_tag, | ||||
| 					   bit_tags); | ||||
| 		blkid_free_tag(tag); | ||||
| 	} | ||||
| 	free(dev->bid_name); | ||||
| 	free(dev); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Given a blkid device, return its name | ||||
|  */ | ||||
| const char *blkid_dev_devname(blkid_dev dev) | ||||
| { | ||||
| 	return dev->bid_name; | ||||
| } | ||||
|  | ||||
| #ifdef CONFIG_BLKID_DEBUG | ||||
| void blkid_debug_dump_dev(blkid_dev dev) | ||||
| { | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!dev) { | ||||
| 		printf("  dev: NULL\n"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	printf("  dev: name = %s\n", dev->bid_name); | ||||
| 	printf("  dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno); | ||||
| 	printf("  dev: TIME=\"%lu\"\n", dev->bid_time); | ||||
| 	printf("  dev: PRI=\"%d\"\n", dev->bid_pri); | ||||
| 	printf("  dev: flags = 0x%08X\n", dev->bid_flags); | ||||
|  | ||||
| 	list_for_each(p, &dev->bid_tags) { | ||||
| 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); | ||||
| 		if (tag) | ||||
| 			printf("    tag: %s=\"%s\"\n", tag->bit_name, | ||||
| 			       tag->bit_val); | ||||
| 		else | ||||
| 			printf("    tag: NULL\n"); | ||||
| 	} | ||||
| 	bb_putchar('\n'); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * dev iteration routines for the public libblkid interface. | ||||
|  * | ||||
|  * These routines do not expose the list.h implementation, which are a | ||||
|  * contamination of the namespace, and which force us to reveal far, far | ||||
|  * too much of our internal implementation.  I'm not convinced I want | ||||
|  * to keep list.h in the long term, anyway.  It's fine for kernel | ||||
|  * programming, but performance is not the #1 priority for this | ||||
|  * library, and I really don't like the tradeoff of type-safety for | ||||
|  * performance for this application.  [tytso:20030125.2007EST] | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This series of functions iterate over all devices in a blkid cache | ||||
|  */ | ||||
| #define DEV_ITERATE_MAGIC	0x01a5284c | ||||
|  | ||||
| struct blkid_struct_dev_iterate { | ||||
| 	int			magic; | ||||
| 	blkid_cache		cache; | ||||
| 	struct list_head	*p; | ||||
| }; | ||||
|  | ||||
| blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache) | ||||
| { | ||||
| 	blkid_dev_iterate	iter; | ||||
|  | ||||
| 	iter = xmalloc(sizeof(struct blkid_struct_dev_iterate)); | ||||
| 	iter->magic = DEV_ITERATE_MAGIC; | ||||
| 	iter->cache = cache; | ||||
| 	iter->p	= cache->bic_devs.next; | ||||
| 	return iter; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return 0 on success, -1 on error | ||||
|  */ | ||||
| extern int blkid_dev_next(blkid_dev_iterate iter, | ||||
| 			  blkid_dev *dev) | ||||
| { | ||||
| 	*dev = 0; | ||||
| 	if (!iter || iter->magic != DEV_ITERATE_MAGIC || | ||||
| 	    iter->p == &iter->cache->bic_devs) | ||||
| 		return -1; | ||||
| 	*dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs); | ||||
| 	iter->p = iter->p->next; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void blkid_dev_iterate_end(blkid_dev_iterate iter) | ||||
| { | ||||
| 	if (!iter || iter->magic != DEV_ITERATE_MAGIC) | ||||
| 		return; | ||||
| 	iter->magic = 0; | ||||
| 	free(iter); | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| #ifdef HAVE_GETOPT_H | ||||
| #include <getopt.h> | ||||
| #else | ||||
| extern char *optarg; | ||||
| extern int optind; | ||||
| #endif | ||||
|  | ||||
| void usage(char *prog) | ||||
| { | ||||
| 	fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); | ||||
| 	fprintf(stderr, "\tList all devices and exit\n"); | ||||
| 	exit(1); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blkid_dev_iterate	iter; | ||||
| 	blkid_cache		cache = NULL; | ||||
| 	blkid_dev		dev; | ||||
| 	int			c, ret; | ||||
| 	char			*tmp; | ||||
| 	char			*file = NULL; | ||||
| 	char			*search_type = NULL; | ||||
| 	char			*search_value = NULL; | ||||
|  | ||||
| 	while ((c = getopt (argc, argv, "m:f:")) != EOF) | ||||
| 		switch (c) { | ||||
| 		case 'f': | ||||
| 			file = optarg; | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			blkid_debug_mask = strtoul (optarg, &tmp, 0); | ||||
| 			if (*tmp) { | ||||
| 				fprintf(stderr, "Invalid debug mask: %s\n", | ||||
| 					optarg); | ||||
| 				exit(1); | ||||
| 			} | ||||
| 			break; | ||||
| 		case '?': | ||||
| 			usage(argv[0]); | ||||
| 		} | ||||
| 	if (argc >= optind+2) { | ||||
| 		search_type = argv[optind]; | ||||
| 		search_value = argv[optind+1]; | ||||
| 		optind += 2; | ||||
| 	} | ||||
| 	if (argc != optind) | ||||
| 		usage(argv[0]); | ||||
|  | ||||
| 	if ((ret = blkid_get_cache(&cache, file)) != 0) { | ||||
| 		fprintf(stderr, "%s: error creating cache (%d)\n", | ||||
| 			argv[0], ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	iter = blkid_dev_iterate_begin(cache); | ||||
| 	if (search_type) | ||||
| 		blkid_dev_set_search(iter, search_type, search_value); | ||||
| 	while (blkid_dev_next(iter, &dev) == 0) { | ||||
| 		printf("Device: %s\n", blkid_dev_devname(dev)); | ||||
| 	} | ||||
| 	blkid_dev_iterate_end(iter); | ||||
|  | ||||
|  | ||||
| 	blkid_put_cache(cache); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,367 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * devname.c - get a dev by its device inode name | ||||
|  * | ||||
|  * Copyright (C) Andries Brouwer | ||||
|  * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #ifdef HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #ifdef HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
| #include <sys/stat.h> | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_MKDEV_H | ||||
| #include <sys/mkdev.h> | ||||
| #endif | ||||
| #include <time.h> | ||||
|  | ||||
| #include "blkidP.h" | ||||
|  | ||||
| /* | ||||
|  * Find a dev struct in the cache by device name, if available. | ||||
|  * | ||||
|  * If there is no entry with the specified device name, and the create | ||||
|  * flag is set, then create an empty device entry. | ||||
|  */ | ||||
| blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) | ||||
| { | ||||
| 	blkid_dev dev = NULL, tmp; | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!cache || !devname) | ||||
| 		return NULL; | ||||
|  | ||||
| 	list_for_each(p, &cache->bic_devs) { | ||||
| 		tmp = list_entry(p, struct blkid_struct_dev, bid_devs); | ||||
| 		if (strcmp(tmp->bid_name, devname)) | ||||
| 			continue; | ||||
|  | ||||
| 		DBG(DEBUG_DEVNAME, | ||||
| 		    printf("found devname %s in cache\n", tmp->bid_name)); | ||||
| 		dev = tmp; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev && (flags & BLKID_DEV_CREATE)) { | ||||
| 		dev = blkid_new_dev(); | ||||
| 		if (!dev) | ||||
| 			return NULL; | ||||
| 		dev->bid_name = blkid_strdup(devname); | ||||
| 		dev->bid_cache = cache; | ||||
| 		list_add_tail(&dev->bid_devs, &cache->bic_devs); | ||||
| 		cache->bic_flags |= BLKID_BIC_FL_CHANGED; | ||||
| 	} | ||||
|  | ||||
| 	if (flags & BLKID_DEV_VERIFY) | ||||
| 		dev = blkid_verify(cache, dev); | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Probe a single block device to add to the device cache. | ||||
|  */ | ||||
| static void probe_one(blkid_cache cache, const char *ptname, | ||||
| 		      dev_t devno, int pri) | ||||
| { | ||||
| 	blkid_dev dev = NULL; | ||||
| 	struct list_head *p; | ||||
| 	const char **dir; | ||||
| 	char *devname = NULL; | ||||
|  | ||||
| 	/* See if we already have this device number in the cache. */ | ||||
| 	list_for_each(p, &cache->bic_devs) { | ||||
| 		blkid_dev tmp = list_entry(p, struct blkid_struct_dev, | ||||
| 					   bid_devs); | ||||
| 		if (tmp->bid_devno == devno) { | ||||
| 			dev = blkid_verify(cache, tmp); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (dev && dev->bid_devno == devno) | ||||
| 		goto set_pri; | ||||
|  | ||||
| 	/* | ||||
| 	 * Take a quick look at /dev/ptname for the device number.  We check | ||||
| 	 * all of the likely device directories.  If we don't find it, or if | ||||
| 	 * the stat information doesn't check out, use blkid_devno_to_devname() | ||||
| 	 * to find it via an exhaustive search for the device major/minor. | ||||
| 	 */ | ||||
| 	for (dir = blkid_devdirs; *dir; dir++) { | ||||
| 		struct stat st; | ||||
| 		char device[256]; | ||||
|  | ||||
| 		sprintf(device, "%s/%s", *dir, ptname); | ||||
| 		if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && | ||||
| 		    dev->bid_devno == devno) | ||||
| 			goto set_pri; | ||||
|  | ||||
| 		if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) && | ||||
| 		    st.st_rdev == devno) { | ||||
| 			devname = blkid_strdup(device); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!devname) { | ||||
| 		devname = blkid_devno_to_devname(devno); | ||||
| 		if (!devname) | ||||
| 			return; | ||||
| 	} | ||||
| 	dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); | ||||
| 	free(devname); | ||||
|  | ||||
| set_pri: | ||||
| 	if (!pri && !strncmp(ptname, "md", 2)) | ||||
| 		pri = BLKID_PRI_MD; | ||||
| 	if (dev) | ||||
| 		dev->bid_pri = pri; | ||||
| } | ||||
|  | ||||
| #define PROC_PARTITIONS "/proc/partitions" | ||||
| #define VG_DIR		"/proc/lvm/VGs" | ||||
|  | ||||
| /* | ||||
|  * This function initializes the UUID cache with devices from the LVM | ||||
|  * proc hierarchy.  We currently depend on the names of the LVM | ||||
|  * hierarchy giving us the device structure in /dev.  (XXX is this a | ||||
|  * safe thing to do?) | ||||
|  */ | ||||
| #ifdef VG_DIR | ||||
| #include <dirent.h> | ||||
| static dev_t lvm_get_devno(const char *lvm_device) | ||||
| { | ||||
| 	FILE *lvf; | ||||
| 	char buf[1024]; | ||||
| 	int ma, mi; | ||||
| 	dev_t ret = 0; | ||||
|  | ||||
| 	DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device)); | ||||
| 	if ((lvf = fopen_for_read(lvm_device)) == NULL) { | ||||
| 		DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno, | ||||
| 					  strerror(errno))); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(buf, sizeof(buf), lvf)) { | ||||
| 		if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { | ||||
| 			ret = makedev(ma, mi); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	fclose(lvf); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static void lvm_probe_all(blkid_cache cache) | ||||
| { | ||||
| 	DIR		*vg_list; | ||||
| 	struct dirent	*vg_iter; | ||||
| 	int		vg_len = strlen(VG_DIR); | ||||
| 	dev_t		dev; | ||||
|  | ||||
| 	if ((vg_list = opendir(VG_DIR)) == NULL) | ||||
| 		return; | ||||
|  | ||||
| 	DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR)); | ||||
|  | ||||
| 	while ((vg_iter = readdir(vg_list)) != NULL) { | ||||
| 		DIR		*lv_list; | ||||
| 		char		*vdirname; | ||||
| 		char		*vg_name; | ||||
| 		struct dirent	*lv_iter; | ||||
|  | ||||
| 		vg_name = vg_iter->d_name; | ||||
| 		if (LONE_CHAR(vg_name, '.') || !strcmp(vg_name, "..")) | ||||
| 			continue; | ||||
| 		vdirname = xmalloc(vg_len + strlen(vg_name) + 8); | ||||
| 		sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name); | ||||
|  | ||||
| 		lv_list = opendir(vdirname); | ||||
| 		free(vdirname); | ||||
| 		if (lv_list == NULL) | ||||
| 			continue; | ||||
|  | ||||
| 		while ((lv_iter = readdir(lv_list)) != NULL) { | ||||
| 			char		*lv_name, *lvm_device; | ||||
|  | ||||
| 			lv_name = lv_iter->d_name; | ||||
| 			if (LONE_CHAR(lv_name, '.') || !strcmp(lv_name, "..")) | ||||
| 				continue; | ||||
|  | ||||
| 			lvm_device = xmalloc(vg_len + strlen(vg_name) + | ||||
| 					    strlen(lv_name) + 8); | ||||
| 			sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name, | ||||
| 				lv_name); | ||||
| 			dev = lvm_get_devno(lvm_device); | ||||
| 			sprintf(lvm_device, "%s/%s", vg_name, lv_name); | ||||
| 			DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n", | ||||
| 						  lvm_device, | ||||
| 						  (unsigned int) dev)); | ||||
| 			probe_one(cache, lvm_device, dev, BLKID_PRI_LVM); | ||||
| 			free(lvm_device); | ||||
| 		} | ||||
| 		closedir(lv_list); | ||||
| 	} | ||||
| 	closedir(vg_list); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #define PROC_EVMS_VOLUMES "/proc/evms/volumes" | ||||
|  | ||||
| static int | ||||
| evms_probe_all(blkid_cache cache) | ||||
| { | ||||
| 	char line[100]; | ||||
| 	int ma, mi, sz, num = 0; | ||||
| 	FILE *procpt; | ||||
| 	char device[110]; | ||||
|  | ||||
| 	procpt = fopen_for_read(PROC_EVMS_VOLUMES); | ||||
| 	if (!procpt) | ||||
| 		return 0; | ||||
| 	while (fgets(line, sizeof(line), procpt)) { | ||||
| 		if (sscanf(line, " %d %d %d %*s %*s %[^\n ]", | ||||
| 			    &ma, &mi, &sz, device) != 4) | ||||
| 			continue; | ||||
|  | ||||
| 		DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n", | ||||
| 					  device, ma, mi)); | ||||
|  | ||||
| 		probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS); | ||||
| 		num++; | ||||
| 	} | ||||
| 	fclose(procpt); | ||||
| 	return num; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Read the device data for all available block devices in the system. | ||||
|  */ | ||||
| int blkid_probe_all(blkid_cache cache) | ||||
| { | ||||
| 	FILE *proc; | ||||
| 	char line[1024]; | ||||
| 	char ptname0[128], ptname1[128], *ptname = NULL; | ||||
| 	char *ptnames[2]; | ||||
| 	dev_t devs[2]; | ||||
| 	int ma, mi; | ||||
| 	unsigned long long sz; | ||||
| 	int lens[2] = { 0, 0 }; | ||||
| 	int which = 0, last = 0; | ||||
|  | ||||
| 	ptnames[0] = ptname0; | ||||
| 	ptnames[1] = ptname1; | ||||
|  | ||||
| 	if (!cache) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	if (cache->bic_flags & BLKID_BIC_FL_PROBED && | ||||
| 	    time(NULL) - cache->bic_time < BLKID_PROBE_INTERVAL) | ||||
| 		return 0; | ||||
|  | ||||
| 	blkid_read_cache(cache); | ||||
| 	evms_probe_all(cache); | ||||
| #ifdef VG_DIR | ||||
| 	lvm_probe_all(cache); | ||||
| #endif | ||||
|  | ||||
| 	proc = fopen_for_read(PROC_PARTITIONS); | ||||
| 	if (!proc) | ||||
| 		return -BLKID_ERR_PROC; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), proc)) { | ||||
| 		last = which; | ||||
| 		which ^= 1; | ||||
| 		ptname = ptnames[which]; | ||||
|  | ||||
| 		if (sscanf(line, " %d %d %llu %128[^\n ]", | ||||
| 			   &ma, &mi, &sz, ptname) != 4) | ||||
| 			continue; | ||||
| 		devs[which] = makedev(ma, mi); | ||||
|  | ||||
| 		DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname)); | ||||
|  | ||||
| 		/* Skip whole disk devs unless they have no partitions | ||||
| 		 * If we don't have a partition on this dev, also | ||||
| 		 * check previous dev to see if it didn't have a partn. | ||||
| 		 * heuristic: partition name ends in a digit. | ||||
| 		 * | ||||
| 		 * Skip extended partitions. | ||||
| 		 * heuristic: size is 1 | ||||
| 		 * | ||||
| 		 * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs | ||||
| 		 */ | ||||
|  | ||||
| 		lens[which] = strlen(ptname); | ||||
| 		if (isdigit(ptname[lens[which] - 1])) { | ||||
| 			DBG(DEBUG_DEVNAME, | ||||
| 			    printf("partition dev %s, devno 0x%04X\n", | ||||
| 				   ptname, (unsigned int) devs[which])); | ||||
|  | ||||
| 			if (sz > 1) | ||||
| 				probe_one(cache, ptname, devs[which], 0); | ||||
| 			lens[which] = 0; | ||||
| 			lens[last] = 0; | ||||
| 		} else if (lens[last] && strncmp(ptnames[last], ptname, | ||||
| 						 lens[last])) { | ||||
| 			DBG(DEBUG_DEVNAME, | ||||
| 			    printf("whole dev %s, devno 0x%04X\n", | ||||
| 				   ptnames[last], (unsigned int) devs[last])); | ||||
| 			probe_one(cache, ptnames[last], devs[last], 0); | ||||
| 			lens[last] = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Handle the last device if it wasn't partitioned */ | ||||
| 	if (lens[which]) | ||||
| 		probe_one(cache, ptname, devs[which], 0); | ||||
|  | ||||
| 	fclose(proc); | ||||
|  | ||||
| 	cache->bic_time = time(NULL); | ||||
| 	cache->bic_flags |= BLKID_BIC_FL_PROBED; | ||||
| 	blkid_flush_cache(cache); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blkid_cache cache = NULL; | ||||
| 	int ret; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if (argc != 1) { | ||||
| 		fprintf(stderr, "Usage: %s\n" | ||||
| 			"Probe all devices and exit\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) { | ||||
| 		fprintf(stderr, "%s: error creating cache (%d)\n", | ||||
| 			argv[0], ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if (blkid_probe_all(cache) < 0) | ||||
| 		printf("%s: error probing devices\n", argv[0]); | ||||
|  | ||||
| 	blkid_put_cache(cache); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,222 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * devno.c - find a particular device by its device number (major/minor) | ||||
|  * | ||||
|  * Copyright (C) 2000, 2001, 2003 Theodore Ts'o | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #ifdef HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #ifdef HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
| #include <sys/stat.h> | ||||
| #include <dirent.h> | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_MKDEV_H | ||||
| #include <sys/mkdev.h> | ||||
| #endif | ||||
|  | ||||
| #include "blkidP.h" | ||||
|  | ||||
| struct dir_list { | ||||
| 	char	*name; | ||||
| 	struct dir_list *next; | ||||
| }; | ||||
|  | ||||
| char *blkid_strndup(const char *s, int length) | ||||
| { | ||||
| 	char *ret; | ||||
|  | ||||
| 	if (!s) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!length) | ||||
| 		length = strlen(s); | ||||
|  | ||||
| 	ret = xmalloc(length + 1); | ||||
| 	strncpy(ret, s, length); | ||||
| 	ret[length] = '\0'; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| char *blkid_strdup(const char *s) | ||||
| { | ||||
| 	return blkid_strndup(s, 0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function adds an entry to the directory list | ||||
|  */ | ||||
| static void add_to_dirlist(const char *name, struct dir_list **list) | ||||
| { | ||||
| 	struct dir_list *dp; | ||||
|  | ||||
| 	dp = xmalloc(sizeof(struct dir_list)); | ||||
| 	dp->name = blkid_strdup(name); | ||||
| 	dp->next = *list; | ||||
| 	*list = dp; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function frees a directory list | ||||
|  */ | ||||
| static void free_dirlist(struct dir_list **list) | ||||
| { | ||||
| 	struct dir_list *dp, *next; | ||||
|  | ||||
| 	for (dp = *list; dp; dp = next) { | ||||
| 		next = dp->next; | ||||
| 		free(dp->name); | ||||
| 		free(dp); | ||||
| 	} | ||||
| 	*list = NULL; | ||||
| } | ||||
|  | ||||
| static void scan_dir(char *dir_name, dev_t devno, struct dir_list **list, | ||||
| 			    char **devname) | ||||
| { | ||||
| 	DIR	*dir; | ||||
| 	struct dirent *dp; | ||||
| 	char	path[1024]; | ||||
| 	int	dirlen; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if ((dir = opendir(dir_name)) == NULL) | ||||
| 		return; | ||||
| 	dirlen = strlen(dir_name) + 2; | ||||
| 	while ((dp = readdir(dir)) != 0) { | ||||
| 		if (dirlen + strlen(dp->d_name) >= sizeof(path)) | ||||
| 			continue; | ||||
|  | ||||
| 		if (dp->d_name[0] == '.' && | ||||
| 		    ((dp->d_name[1] == 0) || | ||||
| 		     ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) | ||||
| 			continue; | ||||
|  | ||||
| 		sprintf(path, "%s/%s", dir_name, dp->d_name); | ||||
| 		if (stat(path, &st) < 0) | ||||
| 			continue; | ||||
|  | ||||
| 		if (S_ISDIR(st.st_mode)) | ||||
| 			add_to_dirlist(path, list); | ||||
| 		else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) { | ||||
| 			*devname = blkid_strdup(path); | ||||
| 			DBG(DEBUG_DEVNO, | ||||
| 			    printf("found 0x%llx at %s (%p)\n", devno, | ||||
| 				   path, *devname)); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	closedir(dir); | ||||
| } | ||||
|  | ||||
| /* Directories where we will try to search for device numbers */ | ||||
| const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL }; | ||||
|  | ||||
| /* | ||||
|  * This function finds the pathname to a block device with a given | ||||
|  * device number.  It returns a pointer to allocated memory to the | ||||
|  * pathname on success, and NULL on failure. | ||||
|  */ | ||||
| char *blkid_devno_to_devname(dev_t devno) | ||||
| { | ||||
| 	struct dir_list *list = NULL, *new_list = NULL; | ||||
| 	char *devname = NULL; | ||||
| 	const char **dir; | ||||
|  | ||||
| 	/* | ||||
| 	 * Add the starting directories to search in reverse order of | ||||
| 	 * importance, since we are using a stack... | ||||
| 	 */ | ||||
| 	for (dir = blkid_devdirs; *dir; dir++) | ||||
| 		add_to_dirlist(*dir, &list); | ||||
|  | ||||
| 	while (list) { | ||||
| 		struct dir_list *current = list; | ||||
|  | ||||
| 		list = list->next; | ||||
| 		DBG(DEBUG_DEVNO, printf("directory %s\n", current->name)); | ||||
| 		scan_dir(current->name, devno, &new_list, &devname); | ||||
| 		free(current->name); | ||||
| 		free(current); | ||||
| 		if (devname) | ||||
| 			break; | ||||
| 		/* | ||||
| 		 * If we're done checking at this level, descend to | ||||
| 		 * the next level of subdirectories. (breadth-first) | ||||
| 		 */ | ||||
| 		if (list == NULL) { | ||||
| 			list = new_list; | ||||
| 			new_list = NULL; | ||||
| 		} | ||||
| 	} | ||||
| 	free_dirlist(&list); | ||||
| 	free_dirlist(&new_list); | ||||
|  | ||||
| 	if (!devname) { | ||||
| 		DBG(DEBUG_DEVNO, | ||||
| 		    printf("blkid: cannot find devno 0x%04lx\n", | ||||
| 			   (unsigned long) devno)); | ||||
| 	} else { | ||||
| 		DBG(DEBUG_DEVNO, | ||||
| 		    printf("found devno 0x%04llx as %s\n", devno, devname)); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	return devname; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	char	*devname, *tmp; | ||||
| 	int	major, minor; | ||||
| 	dev_t	devno; | ||||
| 	const char *errmsg = "Cannot parse %s: %s\n"; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if ((argc != 2) && (argc != 3)) { | ||||
| 		fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n" | ||||
| 			"Resolve a device number to a device name\n", | ||||
| 			argv[0], argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if (argc == 2) { | ||||
| 		devno = strtoul(argv[1], &tmp, 0); | ||||
| 		if (*tmp) { | ||||
| 			fprintf(stderr, errmsg, "device number", argv[1]); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 	} else { | ||||
| 		major = strtoul(argv[1], &tmp, 0); | ||||
| 		if (*tmp) { | ||||
| 			fprintf(stderr, errmsg, "major number", argv[1]); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		minor = strtoul(argv[2], &tmp, 0); | ||||
| 		if (*tmp) { | ||||
| 			fprintf(stderr, errmsg, "minor number", argv[2]); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		devno = makedev(major, minor); | ||||
| 	} | ||||
| 	printf("Looking for device 0x%04Lx\n", devno); | ||||
| 	devname = blkid_devno_to_devname(devno); | ||||
| 	free(devname); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,110 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
|  | ||||
| #include "list.h" | ||||
|  | ||||
| /* | ||||
|  * Insert a new entry between two known consecutive entries. | ||||
|  * | ||||
|  * This is only for internal list manipulation where we know | ||||
|  * the prev/next entries already! | ||||
|  */ | ||||
| void __list_add(struct list_head * add, | ||||
| 	struct list_head * prev, | ||||
| 	struct list_head * next) | ||||
| { | ||||
| 	next->prev = add; | ||||
| 	add->next = next; | ||||
| 	add->prev = prev; | ||||
| 	prev->next = add; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * list_add - add a new entry | ||||
|  * @add:	new entry to be added | ||||
|  * @head:	list head to add it after | ||||
|  * | ||||
|  * Insert a new entry after the specified head. | ||||
|  * This is good for implementing stacks. | ||||
|  */ | ||||
| void list_add(struct list_head *add, struct list_head *head) | ||||
| { | ||||
| 	__list_add(add, head, head->next); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * list_add_tail - add a new entry | ||||
|  * @add:	new entry to be added | ||||
|  * @head:	list head to add it before | ||||
|  * | ||||
|  * Insert a new entry before the specified head. | ||||
|  * This is useful for implementing queues. | ||||
|  */ | ||||
| void list_add_tail(struct list_head *add, struct list_head *head) | ||||
| { | ||||
| 	__list_add(add, head->prev, head); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Delete a list entry by making the prev/next entries | ||||
|  * point to each other. | ||||
|  * | ||||
|  * This is only for internal list manipulation where we know | ||||
|  * the prev/next entries already! | ||||
|  */ | ||||
| void __list_del(struct list_head * prev, struct list_head * next) | ||||
| { | ||||
| 	next->prev = prev; | ||||
| 	prev->next = next; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * list_del - deletes entry from list. | ||||
|  * @entry:	the element to delete from the list. | ||||
|  * | ||||
|  * list_empty() on @entry does not return true after this, @entry is | ||||
|  * in an undefined state. | ||||
|  */ | ||||
| void list_del(struct list_head *entry) | ||||
| { | ||||
| 	__list_del(entry->prev, entry->next); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * list_del_init - deletes entry from list and reinitialize it. | ||||
|  * @entry:	the element to delete from the list. | ||||
|  */ | ||||
| void list_del_init(struct list_head *entry) | ||||
| { | ||||
| 	__list_del(entry->prev, entry->next); | ||||
| 	INIT_LIST_HEAD(entry); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * list_empty - tests whether a list is empty | ||||
|  * @head:	the list to test. | ||||
|  */ | ||||
| int list_empty(struct list_head *head) | ||||
| { | ||||
| 	return head->next == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * list_splice - join two lists | ||||
|  * @list:	the new list to add. | ||||
|  * @head:	the place to add it in the first list. | ||||
|  */ | ||||
| void list_splice(struct list_head *list, struct list_head *head) | ||||
| { | ||||
| 	struct list_head *first = list->next; | ||||
|  | ||||
| 	if (first != list) { | ||||
| 		struct list_head *last = list->prev; | ||||
| 		struct list_head *at = head->next; | ||||
|  | ||||
| 		first->prev = head; | ||||
| 		head->next = first; | ||||
|  | ||||
| 		last->next = at; | ||||
| 		at->prev = last; | ||||
| 	} | ||||
| } | ||||
| @@ -1,73 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| #if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD) | ||||
| #define BLKID_LIST_H 1 | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Simple doubly linked list implementation. | ||||
|  * | ||||
|  * Some of the internal functions ("__xxx") are useful when | ||||
|  * manipulating whole lists rather than single entries, as | ||||
|  * sometimes we already know the next/prev entries and we can | ||||
|  * generate better code by using them directly rather than | ||||
|  * using the generic single-entry routines. | ||||
|  */ | ||||
|  | ||||
| struct list_head { | ||||
| 	struct list_head *next, *prev; | ||||
| }; | ||||
|  | ||||
| #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||||
|  | ||||
| #define LIST_HEAD(name) \ | ||||
| 	struct list_head name = LIST_HEAD_INIT(name) | ||||
|  | ||||
| #define INIT_LIST_HEAD(ptr) do { \ | ||||
| 	(ptr)->next = (ptr); (ptr)->prev = (ptr); \ | ||||
| } while (0) | ||||
|  | ||||
| void __list_add(struct list_head * add, struct list_head * prev,	struct list_head * next); | ||||
| void list_add(struct list_head *add, struct list_head *head); | ||||
| void list_add_tail(struct list_head *add, struct list_head *head); | ||||
| void __list_del(struct list_head * prev, struct list_head * next); | ||||
| void list_del(struct list_head *entry); | ||||
| void list_del_init(struct list_head *entry); | ||||
| int list_empty(struct list_head *head); | ||||
| void list_splice(struct list_head *list, struct list_head *head); | ||||
|  | ||||
| /** | ||||
|  * list_entry - get the struct for this entry | ||||
|  * @ptr:	the &struct list_head pointer. | ||||
|  * @type:	the type of the struct this is embedded in. | ||||
|  * @member:	the name of the list_struct within the struct. | ||||
|  */ | ||||
| #define list_entry(ptr, type, member) \ | ||||
| 	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) | ||||
|  | ||||
| /** | ||||
|  * list_for_each - iterate over elements in a list | ||||
|  * @pos:	the &struct list_head to use as a loop counter. | ||||
|  * @head:	the head for your list. | ||||
|  */ | ||||
| #define list_for_each(pos, head) \ | ||||
| 	for (pos = (head)->next; pos != (head); pos = pos->next) | ||||
|  | ||||
| /** | ||||
|  * list_for_each_safe - iterate over elements in a list, but don't dereference | ||||
|  *                      pos after the body is done (in case it is freed) | ||||
|  * @pos:	the &struct list_head to use as a loop counter. | ||||
|  * @pnext:	the &struct list_head to use as a pointer to the next item. | ||||
|  * @head:	the head for your list (not included in iteration). | ||||
|  */ | ||||
| #define list_for_each_safe(pos, pnext, head) \ | ||||
| 	for (pos = (head)->next, pnext = pos->next; pos != (head); \ | ||||
| 	     pos = pnext, pnext = pos->next) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,726 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * probe.c - identify a block device by its contents, and return a dev | ||||
|  *           struct with the details | ||||
|  * | ||||
|  * Copyright (C) 1999 by Andries Brouwer | ||||
|  * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o | ||||
|  * Copyright (C) 2001 by Andreas Dilger | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/types.h> | ||||
| #ifdef HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_MKDEV_H | ||||
| #include <sys/mkdev.h> | ||||
| #endif | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include "blkidP.h" | ||||
| #include "../uuid/uuid.h" | ||||
| #include "probe.h" | ||||
|  | ||||
| /* | ||||
|  * This is a special case code to check for an MDRAID device.  We do | ||||
|  * this special since it requires checking for a superblock at the end | ||||
|  * of the device. | ||||
|  */ | ||||
| static int check_mdraid(int fd, unsigned char *ret_uuid) | ||||
| { | ||||
| 	struct mdp_superblock_s *md; | ||||
| 	blkid_loff_t		offset; | ||||
| 	char			buf[4096]; | ||||
|  | ||||
| 	if (fd < 0) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; | ||||
|  | ||||
| 	if (blkid_llseek(fd, offset, 0) < 0 || | ||||
| 	    read(fd, buf, 4096) != 4096) | ||||
| 		return -BLKID_ERR_IO; | ||||
|  | ||||
| 	/* Check for magic number */ | ||||
| 	if (memcmp("\251+N\374", buf, 4)) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	if (!ret_uuid) | ||||
| 		return 0; | ||||
| 	*ret_uuid = 0; | ||||
|  | ||||
| 	/* The MD UUID is not contiguous in the superblock, make it so */ | ||||
| 	md = (struct mdp_superblock_s *)buf; | ||||
| 	if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { | ||||
| 		memcpy(ret_uuid, &md->set_uuid0, 4); | ||||
| 		memcpy(ret_uuid, &md->set_uuid1, 12); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void set_uuid(blkid_dev dev, uuid_t uuid) | ||||
| { | ||||
| 	char	str[37]; | ||||
|  | ||||
| 	if (!uuid_is_null(uuid)) { | ||||
| 		uuid_unparse(uuid, str); | ||||
| 		blkid_set_tag(dev, "UUID", str, sizeof(str)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void get_ext2_info(blkid_dev dev, unsigned char *buf) | ||||
| { | ||||
| 	struct ext2_super_block *es = (struct ext2_super_block *) buf; | ||||
| 	const char *label = NULL; | ||||
|  | ||||
| 	DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", | ||||
| 		   blkid_le32(es->s_feature_compat), | ||||
| 		   blkid_le32(es->s_feature_incompat), | ||||
| 		   blkid_le32(es->s_feature_ro_compat))); | ||||
|  | ||||
| 	if (strlen(es->s_volume_name)) | ||||
| 		label = es->s_volume_name; | ||||
| 	blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name)); | ||||
|  | ||||
| 	set_uuid(dev, es->s_uuid); | ||||
| } | ||||
|  | ||||
| static int probe_ext3(int fd __BLKID_ATTR((unused)), | ||||
| 		      blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		      blkid_dev dev, | ||||
| 		      const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		      unsigned char *buf) | ||||
| { | ||||
| 	struct ext2_super_block *es; | ||||
|  | ||||
| 	es = (struct ext2_super_block *)buf; | ||||
|  | ||||
| 	/* Distinguish between jbd and ext2/3 fs */ | ||||
| 	if (blkid_le32(es->s_feature_incompat) & | ||||
| 	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	/* Distinguish between ext3 and ext2 */ | ||||
| 	if (!(blkid_le32(es->s_feature_compat) & | ||||
| 	      EXT3_FEATURE_COMPAT_HAS_JOURNAL)) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	get_ext2_info(dev, buf); | ||||
|  | ||||
| 	blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2")); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_ext2(int fd __BLKID_ATTR((unused)), | ||||
| 		      blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		      blkid_dev dev, | ||||
| 		      const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		      unsigned char *buf) | ||||
| { | ||||
| 	struct ext2_super_block *es; | ||||
|  | ||||
| 	es = (struct ext2_super_block *)buf; | ||||
|  | ||||
| 	/* Distinguish between jbd and ext2/3 fs */ | ||||
| 	if (blkid_le32(es->s_feature_incompat) & | ||||
| 	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	get_ext2_info(dev, buf); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_jbd(int fd __BLKID_ATTR((unused)), | ||||
| 		     blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		     blkid_dev dev, | ||||
| 		     const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		     unsigned char *buf) | ||||
| { | ||||
| 	struct ext2_super_block *es = (struct ext2_super_block *) buf; | ||||
|  | ||||
| 	if (!(blkid_le32(es->s_feature_incompat) & | ||||
| 	      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	get_ext2_info(dev, buf); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_vfat(int fd __BLKID_ATTR((unused)), | ||||
| 		      blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		      blkid_dev dev, | ||||
| 		      const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		      unsigned char *buf) | ||||
| { | ||||
| 	struct vfat_super_block *vs; | ||||
| 	char serno[10]; | ||||
| 	const char *label = NULL; | ||||
| 	int label_len = 0; | ||||
|  | ||||
| 	vs = (struct vfat_super_block *)buf; | ||||
|  | ||||
| 	if (strncmp(vs->vs_label, "NO NAME", 7)) { | ||||
| 		char *end = vs->vs_label + sizeof(vs->vs_label) - 1; | ||||
|  | ||||
| 		while (*end == ' ' && end >= vs->vs_label) | ||||
| 			--end; | ||||
| 		if (end >= vs->vs_label) { | ||||
| 			label = vs->vs_label; | ||||
| 			label_len = end - vs->vs_label + 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* We can't just print them as %04X, because they are unaligned */ | ||||
| 	sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2], | ||||
| 		vs->vs_serno[1], vs->vs_serno[0]); | ||||
| 	blkid_set_tag(dev, "LABEL", label, label_len); | ||||
| 	blkid_set_tag(dev, "UUID", serno, sizeof(serno)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_msdos(int fd __BLKID_ATTR((unused)), | ||||
| 		       blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		       blkid_dev dev, | ||||
| 		       const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		       unsigned char *buf) | ||||
| { | ||||
| 	struct msdos_super_block *ms = (struct msdos_super_block *) buf; | ||||
| 	char serno[10]; | ||||
| 	const char *label = NULL; | ||||
| 	int label_len = 0; | ||||
|  | ||||
| 	if (strncmp(ms->ms_label, "NO NAME", 7)) { | ||||
| 		char *end = ms->ms_label + sizeof(ms->ms_label) - 1; | ||||
|  | ||||
| 		while (*end == ' ' && end >= ms->ms_label) | ||||
| 			--end; | ||||
| 		if (end >= ms->ms_label) { | ||||
| 			label = ms->ms_label; | ||||
| 			label_len = end - ms->ms_label + 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* We can't just print them as %04X, because they are unaligned */ | ||||
| 	sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2], | ||||
| 		ms->ms_serno[1], ms->ms_serno[0]); | ||||
| 	blkid_set_tag(dev, "UUID", serno, 0); | ||||
| 	blkid_set_tag(dev, "LABEL", label, label_len); | ||||
| 	blkid_set_tag(dev, "SEC_TYPE", "msdos", sizeof("msdos")); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_xfs(int fd __BLKID_ATTR((unused)), | ||||
| 		     blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		     blkid_dev dev, | ||||
| 		     const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		     unsigned char *buf) | ||||
| { | ||||
| 	struct xfs_super_block *xs; | ||||
| 	const char *label = NULL; | ||||
|  | ||||
| 	xs = (struct xfs_super_block *)buf; | ||||
|  | ||||
| 	if (strlen(xs->xs_fname)) | ||||
| 		label = xs->xs_fname; | ||||
| 	blkid_set_tag(dev, "LABEL", label, sizeof(xs->xs_fname)); | ||||
| 	set_uuid(dev, xs->xs_uuid); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_reiserfs(int fd __BLKID_ATTR((unused)), | ||||
| 			  blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 			  blkid_dev dev, | ||||
| 			  const struct blkid_magic *id, unsigned char *buf) | ||||
| { | ||||
| 	struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; | ||||
| 	unsigned int blocksize; | ||||
| 	const char *label = NULL; | ||||
|  | ||||
| 	blocksize = blkid_le16(rs->rs_blocksize); | ||||
|  | ||||
| 	/* If the superblock is inside the journal, we have the wrong one */ | ||||
| 	if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) | ||||
| 		return -BLKID_ERR_BIG; | ||||
|  | ||||
| 	/* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ | ||||
| 	if (!strcmp(id->bim_magic, "ReIsEr2Fs") || | ||||
| 	    !strcmp(id->bim_magic, "ReIsEr3Fs")) { | ||||
| 		if (strlen(rs->rs_label)) | ||||
| 			label = rs->rs_label; | ||||
| 		set_uuid(dev, rs->rs_uuid); | ||||
| 	} | ||||
| 	blkid_set_tag(dev, "LABEL", label, sizeof(rs->rs_label)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_jfs(int fd __BLKID_ATTR((unused)), | ||||
| 		     blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		     blkid_dev dev, | ||||
| 		     const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		     unsigned char *buf) | ||||
| { | ||||
| 	struct jfs_super_block *js; | ||||
| 	const char *label = NULL; | ||||
|  | ||||
| 	js = (struct jfs_super_block *)buf; | ||||
|  | ||||
| 	if (strlen((char *) js->js_label)) | ||||
| 		label = (char *) js->js_label; | ||||
| 	blkid_set_tag(dev, "LABEL", label, sizeof(js->js_label)); | ||||
| 	set_uuid(dev, js->js_uuid); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_romfs(int fd __BLKID_ATTR((unused)), | ||||
| 		       blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		       blkid_dev dev, | ||||
| 		       const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		       unsigned char *buf) | ||||
| { | ||||
| 	struct romfs_super_block *ros; | ||||
| 	const char *label = NULL; | ||||
|  | ||||
| 	ros = (struct romfs_super_block *)buf; | ||||
|  | ||||
| 	if (strlen((char *) ros->ros_volume)) | ||||
| 		label = (char *) ros->ros_volume; | ||||
| 	blkid_set_tag(dev, "LABEL", label, 0); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_cramfs(int fd __BLKID_ATTR((unused)), | ||||
| 		       blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		       blkid_dev dev, | ||||
| 		       const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		       unsigned char *buf) | ||||
| { | ||||
| 	struct cramfs_super_block *csb; | ||||
| 	const char *label = NULL; | ||||
|  | ||||
| 	csb = (struct cramfs_super_block *)buf; | ||||
|  | ||||
| 	if (strlen((char *) csb->name)) | ||||
| 		label = (char *) csb->name; | ||||
| 	blkid_set_tag(dev, "LABEL", label, 0); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_swap0(int fd __BLKID_ATTR((unused)), | ||||
| 		       blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		       blkid_dev dev, | ||||
| 		       const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		       unsigned char *buf __BLKID_ATTR((unused))) | ||||
| { | ||||
| 	blkid_set_tag(dev, "UUID", 0, 0); | ||||
| 	blkid_set_tag(dev, "LABEL", 0, 0); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_swap1(int fd, | ||||
| 		       blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		       blkid_dev dev, | ||||
| 		       const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		       unsigned char *buf __BLKID_ATTR((unused))) | ||||
| { | ||||
| 	struct swap_id_block *sws; | ||||
|  | ||||
| 	probe_swap0(fd, cache, dev, id, buf); | ||||
| 	/* | ||||
| 	 * Version 1 swap headers are always located at offset of 1024 | ||||
| 	 * bytes, although the swap signature itself is located at the | ||||
| 	 * end of the page (which may vary depending on hardware | ||||
| 	 * pagesize). | ||||
| 	 */ | ||||
| 	if (lseek(fd, 1024, SEEK_SET) < 0) return 1; | ||||
| 	sws = xmalloc(1024); | ||||
| 	if (read(fd, sws, 1024) != 1024) { | ||||
| 		free(sws); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	/* arbitrary sanity check.. is there any garbage down there? */ | ||||
| 	if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0)  { | ||||
| 		if (sws->sws_volume[0]) | ||||
| 			blkid_set_tag(dev, "LABEL", (const char*)sws->sws_volume, | ||||
| 				      sizeof(sws->sws_volume)); | ||||
| 		if (sws->sws_uuid[0]) | ||||
| 			set_uuid(dev, sws->sws_uuid); | ||||
| 	} | ||||
| 	free(sws); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static const char | ||||
| * const udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", | ||||
| 		 "NSR03", "TEA01", 0 }; | ||||
|  | ||||
| static int probe_udf(int fd, blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		     blkid_dev dev __BLKID_ATTR((unused)), | ||||
| 		     const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		     unsigned char *buf __BLKID_ATTR((unused))) | ||||
| { | ||||
| 	int j, bs; | ||||
| 	struct iso_volume_descriptor isosb; | ||||
| 	const char *const *m; | ||||
|  | ||||
| 	/* determine the block size by scanning in 2K increments | ||||
| 	   (block sizes larger than 2K will be null padded) */ | ||||
| 	for (bs = 1; bs < 16; bs++) { | ||||
| 		lseek(fd, bs*2048+32768, SEEK_SET); | ||||
| 		if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb)) | ||||
| 			return 1; | ||||
| 		if (isosb.id[0]) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	/* Scan up to another 64 blocks looking for additional VSD's */ | ||||
| 	for (j = 1; j < 64; j++) { | ||||
| 		if (j > 1) { | ||||
| 			lseek(fd, j*bs*2048+32768, SEEK_SET); | ||||
| 			if (read(fd, (char *)&isosb, sizeof(isosb)) | ||||
| 			    != sizeof(isosb)) | ||||
| 				return 1; | ||||
| 		} | ||||
| 		/* If we find NSR0x then call it udf: | ||||
| 		   NSR01 for UDF 1.00 | ||||
| 		   NSR02 for UDF 1.50 | ||||
| 		   NSR03 for UDF 2.00 */ | ||||
| 		if (!strncmp(isosb.id, "NSR0", 4)) | ||||
| 			return 0; | ||||
| 		for (m = udf_magic; *m; m++) | ||||
| 			if (!strncmp(*m, isosb.id, 5)) | ||||
| 				break; | ||||
| 		if (*m == 0) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int probe_ocfs(int fd __BLKID_ATTR((unused)), | ||||
| 		      blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		      blkid_dev dev, | ||||
| 		      const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		      unsigned char *buf) | ||||
| { | ||||
| 	struct ocfs_volume_header ovh; | ||||
| 	struct ocfs_volume_label ovl; | ||||
| 	__u32 major; | ||||
|  | ||||
| 	memcpy(&ovh, buf, sizeof(ovh)); | ||||
| 	memcpy(&ovl, buf+512, sizeof(ovl)); | ||||
|  | ||||
| 	major = ocfsmajor(ovh); | ||||
| 	if (major == 1) | ||||
| 		blkid_set_tag(dev, "SEC_TYPE", "ocfs1", sizeof("ocfs1")); | ||||
| 	else if (major >= 9) | ||||
| 		blkid_set_tag(dev, "SEC_TYPE", "ntocfs", sizeof("ntocfs")); | ||||
|  | ||||
| 	blkid_set_tag(dev, "LABEL", (const char*)ovl.label, ocfslabellen(ovl)); | ||||
| 	blkid_set_tag(dev, "MOUNT", (const char*)ovh.mount, ocfsmountlen(ovh)); | ||||
| 	set_uuid(dev, ovl.vol_id); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_ocfs2(int fd __BLKID_ATTR((unused)), | ||||
| 		       blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 		       blkid_dev dev, | ||||
| 		       const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 		       unsigned char *buf) | ||||
| { | ||||
| 	struct ocfs2_super_block *osb; | ||||
|  | ||||
| 	osb = (struct ocfs2_super_block *)buf; | ||||
|  | ||||
| 	blkid_set_tag(dev, "LABEL", (const char*)osb->s_label, sizeof(osb->s_label)); | ||||
| 	set_uuid(dev, osb->s_uuid); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int probe_oracleasm(int fd __BLKID_ATTR((unused)), | ||||
| 			   blkid_cache cache __BLKID_ATTR((unused)), | ||||
| 			   blkid_dev dev, | ||||
| 			   const struct blkid_magic *id __BLKID_ATTR((unused)), | ||||
| 			   unsigned char *buf) | ||||
| { | ||||
| 	struct oracle_asm_disk_label *dl; | ||||
|  | ||||
| 	dl = (struct oracle_asm_disk_label *)buf; | ||||
|  | ||||
| 	blkid_set_tag(dev, "LABEL", dl->dl_id, sizeof(dl->dl_id)); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined | ||||
|  * in the type_array table below + bim_kbalign. | ||||
|  * | ||||
|  * When probing for a lot of magics, we handle everything in 1kB buffers so | ||||
|  * that we don't have to worry about reading each combination of block sizes. | ||||
|  */ | ||||
| #define BLKID_BLK_OFFS	64	/* currently reiserfs */ | ||||
|  | ||||
| /* | ||||
|  * Various filesystem magics that we can check for.  Note that kboff and | ||||
|  * sboff are in kilobytes and bytes respectively.  All magics are in | ||||
|  * byte strings so we don't worry about endian issues. | ||||
|  */ | ||||
| static const struct blkid_magic type_array[] = { | ||||
| /*  type     kboff   sboff len  magic			probe */ | ||||
|   { "oracleasm", 0,	32,  8, "ORCLDISK",		probe_oracleasm }, | ||||
|   { "ntfs",      0,      3,  8, "NTFS    ",             0 }, | ||||
|   { "jbd",	 1,   0x38,  2, "\123\357",		probe_jbd }, | ||||
|   { "ext3",	 1,   0x38,  2, "\123\357",		probe_ext3 }, | ||||
|   { "ext2",	 1,   0x38,  2, "\123\357",		probe_ext2 }, | ||||
|   { "reiserfs",	 8,   0x34,  8, "ReIsErFs",		probe_reiserfs }, | ||||
|   { "reiserfs", 64,   0x34,  9, "ReIsEr2Fs",		probe_reiserfs }, | ||||
|   { "reiserfs", 64,   0x34,  9, "ReIsEr3Fs",		probe_reiserfs }, | ||||
|   { "reiserfs", 64,   0x34,  8, "ReIsErFs",		probe_reiserfs }, | ||||
|   { "reiserfs",	 8,	20,  8, "ReIsErFs",		probe_reiserfs }, | ||||
|   { "vfat",      0,   0x52,  5, "MSWIN",                probe_vfat }, | ||||
|   { "vfat",      0,   0x52,  8, "FAT32   ",             probe_vfat }, | ||||
|   { "vfat",      0,   0x36,  5, "MSDOS",                probe_msdos }, | ||||
|   { "vfat",      0,   0x36,  8, "FAT16   ",             probe_msdos }, | ||||
|   { "vfat",      0,   0x36,  8, "FAT12   ",             probe_msdos }, | ||||
|   { "minix",     1,   0x10,  2, "\177\023",             0 }, | ||||
|   { "minix",     1,   0x10,  2, "\217\023",             0 }, | ||||
|   { "minix",	 1,   0x10,  2, "\150\044",		0 }, | ||||
|   { "minix",	 1,   0x10,  2, "\170\044",		0 }, | ||||
|   { "vxfs",	 1,	 0,  4, "\365\374\001\245",	0 }, | ||||
|   { "xfs",	 0,	 0,  4, "XFSB",			probe_xfs }, | ||||
|   { "romfs",	 0,	 0,  8, "-rom1fs-",		probe_romfs }, | ||||
|   { "bfs",	 0,	 0,  4, "\316\372\173\033",	0 }, | ||||
|   { "cramfs",	 0,	 0,  4, "E=\315\050",		probe_cramfs }, | ||||
|   { "qnx4",	 0,	 4,  6, "QNX4FS",		0 }, | ||||
|   { "udf",	32,	 1,  5, "BEA01",		probe_udf }, | ||||
|   { "udf",	32,	 1,  5, "BOOT2",		probe_udf }, | ||||
|   { "udf",	32,	 1,  5, "CD001",		probe_udf }, | ||||
|   { "udf",	32,	 1,  5, "CDW02",		probe_udf }, | ||||
|   { "udf",	32,	 1,  5, "NSR02",		probe_udf }, | ||||
|   { "udf",	32,	 1,  5, "NSR03",		probe_udf }, | ||||
|   { "udf",	32,	 1,  5, "TEA01",		probe_udf }, | ||||
|   { "iso9660",	32,	 1,  5, "CD001",		0 }, | ||||
|   { "iso9660",	32,	 9,  5, "CDROM",		0 }, | ||||
|   { "jfs",	32,	 0,  4, "JFS1",			probe_jfs }, | ||||
|   { "hfs",	 1,	 0,  2, "BD",			0 }, | ||||
|   { "ufs",	 8,  0x55c,  4, "T\031\001\000",	0 }, | ||||
|   { "hpfs",	 8,	 0,  4, "I\350\225\371",	0 }, | ||||
|   { "sysv",	 0,  0x3f8,  4, "\020~\030\375",	0 }, | ||||
|   { "swap",	 0,  0xff6, 10, "SWAP-SPACE",		probe_swap0 }, | ||||
|   { "swap",	 0,  0xff6, 10, "SWAPSPACE2",		probe_swap1 }, | ||||
|   { "swap",	 0, 0x1ff6, 10, "SWAP-SPACE",		probe_swap0 }, | ||||
|   { "swap",	 0, 0x1ff6, 10, "SWAPSPACE2",		probe_swap1 }, | ||||
|   { "swap",	 0, 0x3ff6, 10, "SWAP-SPACE",		probe_swap0 }, | ||||
|   { "swap",	 0, 0x3ff6, 10, "SWAPSPACE2",		probe_swap1 }, | ||||
|   { "swap",	 0, 0x7ff6, 10, "SWAP-SPACE",		probe_swap0 }, | ||||
|   { "swap",	 0, 0x7ff6, 10, "SWAPSPACE2",		probe_swap1 }, | ||||
|   { "swap",	 0, 0xfff6, 10, "SWAP-SPACE",		probe_swap0 }, | ||||
|   { "swap",	 0, 0xfff6, 10, "SWAPSPACE2",		probe_swap1 }, | ||||
|   { "ocfs",	 0,	 8,  9,	"OracleCFS",		probe_ocfs }, | ||||
|   { "ocfs2",	 1,	 0,  6,	"OCFSV2",		probe_ocfs2 }, | ||||
|   { "ocfs2",	 2,	 0,  6,	"OCFSV2",		probe_ocfs2 }, | ||||
|   { "ocfs2",	 4,	 0,  6,	"OCFSV2",		probe_ocfs2 }, | ||||
|   { "ocfs2",	 8,	 0,  6,	"OCFSV2",		probe_ocfs2 }, | ||||
|   {   NULL,	 0,	 0,  0, NULL,			NULL } | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Verify that the data in dev is consistent with what is on the actual | ||||
|  * block device (using the devname field only).  Normally this will be | ||||
|  * called when finding items in the cache, but for long running processes | ||||
|  * is also desirable to revalidate an item before use. | ||||
|  * | ||||
|  * If we are unable to revalidate the data, we return the old data and | ||||
|  * do not set the BLKID_BID_FL_VERIFIED flag on it. | ||||
|  */ | ||||
| blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) | ||||
| { | ||||
| 	const struct blkid_magic *id; | ||||
| 	unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf; | ||||
| 	const char *type; | ||||
| 	struct stat st; | ||||
| 	time_t diff, now; | ||||
| 	int fd, idx; | ||||
|  | ||||
| 	if (!dev) | ||||
| 		return NULL; | ||||
|  | ||||
| 	now = time(NULL); | ||||
| 	diff = now - dev->bid_time; | ||||
|  | ||||
| 	if ((now < dev->bid_time) || | ||||
| 	    (diff < BLKID_PROBE_MIN) || | ||||
| 	    (dev->bid_flags & BLKID_BID_FL_VERIFIED && | ||||
| 	     diff < BLKID_PROBE_INTERVAL)) | ||||
| 		return dev; | ||||
|  | ||||
| 	DBG(DEBUG_PROBE, | ||||
| 	    printf("need to revalidate %s (time since last check %lu)\n", | ||||
| 		   dev->bid_name, diff)); | ||||
|  | ||||
| 	fd = open(dev->bid_name, O_RDONLY); | ||||
| 	if (fd < 0 | ||||
| 	 || fstat(fd, &st) < 0 | ||||
| 	) { | ||||
| 		if (fd >= 0) | ||||
| 			close(fd); | ||||
| 		if (errno == ENXIO || errno == ENODEV || errno == ENOENT) { | ||||
| 			blkid_free_dev(dev); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		/* We don't have read permission, just return cache data. */ | ||||
| 		DBG(DEBUG_PROBE, | ||||
| 		    printf("returning unverified data for %s\n", | ||||
| 			   dev->bid_name)); | ||||
| 		return dev; | ||||
| 	} | ||||
|  | ||||
| 	memset(bufs, 0, sizeof(bufs)); | ||||
|  | ||||
| 	/* | ||||
| 	 * Iterate over the type array.  If we already know the type, | ||||
| 	 * then try that first.  If it doesn't work, then blow away | ||||
| 	 * the type information, and try again. | ||||
| 	 * | ||||
| 	 */ | ||||
| try_again: | ||||
| 	type = 0; | ||||
| 	if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { | ||||
| 		uuid_t	uuid; | ||||
|  | ||||
| 		if (check_mdraid(fd, uuid) == 0) { | ||||
| 			set_uuid(dev, uuid); | ||||
| 			type = "mdraid"; | ||||
| 			goto found_type; | ||||
| 		} | ||||
| 	} | ||||
| 	for (id = type_array; id->bim_type; id++) { | ||||
| 		if (dev->bid_type && | ||||
| 		    strcmp(id->bim_type, dev->bid_type)) | ||||
| 			continue; | ||||
|  | ||||
| 		idx = id->bim_kboff + (id->bim_sboff >> 10); | ||||
| 		if (idx > BLKID_BLK_OFFS || idx < 0) | ||||
| 			continue; | ||||
| 		buf = bufs[idx]; | ||||
| 		if (!buf) { | ||||
| 			if (lseek(fd, idx << 10, SEEK_SET) < 0) | ||||
| 				continue; | ||||
|  | ||||
| 			buf = xmalloc(1024); | ||||
|  | ||||
| 			if (read(fd, buf, 1024) != 1024) { | ||||
| 				free(buf); | ||||
| 				continue; | ||||
| 			} | ||||
| 			bufs[idx] = buf; | ||||
| 		} | ||||
|  | ||||
| 		if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff), | ||||
| 			   id->bim_len)) | ||||
| 			continue; | ||||
|  | ||||
| 		if ((id->bim_probe == NULL) || | ||||
| 		    (id->bim_probe(fd, cache, dev, id, buf) == 0)) { | ||||
| 			type = id->bim_type; | ||||
| 			goto found_type; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!id->bim_type && dev->bid_type) { | ||||
| 		/* | ||||
| 		 * Zap the device filesystem type and try again | ||||
| 		 */ | ||||
| 		blkid_set_tag(dev, "TYPE", 0, 0); | ||||
| 		blkid_set_tag(dev, "SEC_TYPE", 0, 0); | ||||
| 		blkid_set_tag(dev, "LABEL", 0, 0); | ||||
| 		blkid_set_tag(dev, "UUID", 0, 0); | ||||
| 		goto try_again; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev->bid_type) { | ||||
| 		blkid_free_dev(dev); | ||||
| 		close(fd); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| found_type: | ||||
| 	if (dev && type) { | ||||
| 		dev->bid_devno = st.st_rdev; | ||||
| 		dev->bid_time = time(NULL); | ||||
| 		dev->bid_flags |= BLKID_BID_FL_VERIFIED; | ||||
| 		cache->bic_flags |= BLKID_BIC_FL_CHANGED; | ||||
|  | ||||
| 		blkid_set_tag(dev, "TYPE", type, 0); | ||||
|  | ||||
| 		DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", | ||||
| 			   dev->bid_name, st.st_rdev, type)); | ||||
| 	} | ||||
|  | ||||
| 	close(fd); | ||||
|  | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| int blkid_known_fstype(const char *fstype) | ||||
| { | ||||
| 	const struct blkid_magic *id; | ||||
|  | ||||
| 	for (id = type_array; id->bim_type; id++) { | ||||
| 		if (strcmp(fstype, id->bim_type) == 0) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blkid_dev dev; | ||||
| 	blkid_cache cache; | ||||
| 	int ret; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if (argc != 2) { | ||||
| 		fprintf(stderr, "Usage: %s device\n" | ||||
| 			"Probe a single device to determine type\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) { | ||||
| 		fprintf(stderr, "%s: error creating cache (%d)\n", | ||||
| 			argv[0], ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); | ||||
| 	if (!dev) { | ||||
| 		printf("%s: %s has an unsupported type\n", argv[0], argv[1]); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	printf("%s is type %s\n", argv[1], dev->bid_type ? | ||||
| 		dev->bid_type : "(null)"); | ||||
| 	if (dev->bid_label) | ||||
| 		printf("\tlabel is '%s'\n", dev->bid_label); | ||||
| 	if (dev->bid_uuid) | ||||
| 		printf("\tuuid is %s\n", dev->bid_uuid); | ||||
|  | ||||
| 	blkid_free_dev(dev); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,374 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * probe.h - constants and on-disk structures for extracting device data | ||||
|  * | ||||
|  * Copyright (C) 1999 by Andries Brouwer | ||||
|  * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o | ||||
|  * Copyright (C) 2001 by Andreas Dilger | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
| #ifndef BLKID_PROBE_H | ||||
| #define BLKID_PROBE_H 1 | ||||
|  | ||||
| #include <linux/types.h> | ||||
|  | ||||
| struct blkid_magic; | ||||
|  | ||||
| typedef int (*blkid_probe_t)(int fd, blkid_cache cache, blkid_dev dev, | ||||
| 			     const struct blkid_magic *id, unsigned char *buf); | ||||
|  | ||||
| struct blkid_magic { | ||||
| 	const char	*bim_type;	/* type name for this magic */ | ||||
| 	long		bim_kboff;	/* kilobyte offset of superblock */ | ||||
| 	unsigned	bim_sboff;	/* byte offset within superblock */ | ||||
| 	unsigned	bim_len;	/* length of magic */ | ||||
| 	const char	*bim_magic;	/* magic string */ | ||||
| 	blkid_probe_t	bim_probe;	/* probe function */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Structures for each of the content types we want to extract information | ||||
|  * from.  We do not necessarily need the magic field here, because we have | ||||
|  * already identified the content type before we get this far.  It may still | ||||
|  * be useful if there are probe functions which handle multiple content types. | ||||
|  */ | ||||
| struct ext2_super_block { | ||||
| 	__u32		s_inodes_count; | ||||
| 	__u32		s_blocks_count; | ||||
| 	__u32		s_r_blocks_count; | ||||
| 	__u32		s_free_blocks_count; | ||||
| 	__u32		s_free_inodes_count; | ||||
| 	__u32		s_first_data_block; | ||||
| 	__u32		s_log_block_size; | ||||
| 	__u32		s_dummy3[7]; | ||||
| 	unsigned char	s_magic[2]; | ||||
| 	__u16		s_state; | ||||
| 	__u32		s_dummy5[8]; | ||||
| 	__u32		s_feature_compat; | ||||
| 	__u32		s_feature_incompat; | ||||
| 	__u32		s_feature_ro_compat; | ||||
| 	unsigned char   s_uuid[16]; | ||||
| 	char	   s_volume_name[16]; | ||||
| }; | ||||
| #define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x00000004 | ||||
| #define EXT3_FEATURE_INCOMPAT_RECOVER		0x00000004 | ||||
| #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x00000008 | ||||
|  | ||||
| struct xfs_super_block { | ||||
| 	unsigned char	xs_magic[4]; | ||||
| 	__u32		xs_blocksize; | ||||
| 	__u64		xs_dblocks; | ||||
| 	__u64		xs_rblocks; | ||||
| 	__u32		xs_dummy1[2]; | ||||
| 	unsigned char	xs_uuid[16]; | ||||
| 	__u32		xs_dummy2[15]; | ||||
| 	char		xs_fname[12]; | ||||
| 	__u32		xs_dummy3[2]; | ||||
| 	__u64		xs_icount; | ||||
| 	__u64		xs_ifree; | ||||
| 	__u64		xs_fdblocks; | ||||
| }; | ||||
|  | ||||
| struct reiserfs_super_block { | ||||
| 	__u32		rs_blocks_count; | ||||
| 	__u32		rs_free_blocks; | ||||
| 	__u32		rs_root_block; | ||||
| 	__u32		rs_journal_block; | ||||
| 	__u32		rs_journal_dev; | ||||
| 	__u32		rs_orig_journal_size; | ||||
| 	__u32		rs_dummy2[5]; | ||||
| 	__u16		rs_blocksize; | ||||
| 	__u16		rs_dummy3[3]; | ||||
| 	unsigned char	rs_magic[12]; | ||||
| 	__u32		rs_dummy4[5]; | ||||
| 	unsigned char	rs_uuid[16]; | ||||
| 	char		rs_label[16]; | ||||
| }; | ||||
|  | ||||
| struct jfs_super_block { | ||||
| 	unsigned char	js_magic[4]; | ||||
| 	__u32		js_version; | ||||
| 	__u64		js_size; | ||||
| 	__u32		js_bsize; | ||||
| 	__u32		js_dummy1; | ||||
| 	__u32		js_pbsize; | ||||
| 	__u32		js_dummy2[27]; | ||||
| 	unsigned char	js_uuid[16]; | ||||
| 	unsigned char	js_label[16]; | ||||
| 	unsigned char	js_loguuid[16]; | ||||
| }; | ||||
|  | ||||
| struct romfs_super_block { | ||||
| 	unsigned char	ros_magic[8]; | ||||
| 	__u32		ros_dummy1[2]; | ||||
| 	unsigned char	ros_volume[16]; | ||||
| }; | ||||
|  | ||||
| struct cramfs_super_block { | ||||
| 	__u8		magic[4]; | ||||
| 	__u32		size; | ||||
| 	__u32		flags; | ||||
| 	__u32		future; | ||||
| 	__u8		signature[16]; | ||||
| 	struct cramfs_info { | ||||
| 		__u32		crc; | ||||
| 		__u32		edition; | ||||
| 		__u32		blocks; | ||||
| 		__u32		files; | ||||
| 	} info; | ||||
| 	__u8		name[16]; | ||||
| }; | ||||
|  | ||||
| struct swap_id_block { | ||||
| /*	unsigned char	sws_boot[1024]; */ | ||||
| 	__u32		sws_version; | ||||
| 	__u32		sws_lastpage; | ||||
| 	__u32		sws_nrbad; | ||||
| 	unsigned char	sws_uuid[16]; | ||||
| 	char		sws_volume[16]; | ||||
| 	unsigned char	sws_pad[117]; | ||||
| 	__u32		sws_badpg; | ||||
| }; | ||||
|  | ||||
| /* Yucky misaligned values */ | ||||
| struct vfat_super_block { | ||||
| /* 00*/	unsigned char	vs_ignored[3]; | ||||
| /* 03*/	unsigned char	vs_sysid[8]; | ||||
| /* 0b*/	unsigned char	vs_sector_size[2]; | ||||
| /* 0d*/	__u8		vs_cluster_size; | ||||
| /* 0e*/	__u16		vs_reserved; | ||||
| /* 10*/	__u8		vs_fats; | ||||
| /* 11*/	unsigned char	vs_dir_entries[2]; | ||||
| /* 13*/	unsigned char	vs_sectors[2]; | ||||
| /* 15*/	unsigned char	vs_media; | ||||
| /* 16*/	__u16		vs_fat_length; | ||||
| /* 18*/	__u16		vs_secs_track; | ||||
| /* 1a*/	__u16		vs_heads; | ||||
| /* 1c*/	__u32		vs_hidden; | ||||
| /* 20*/	__u32		vs_total_sect; | ||||
| /* 24*/	__u32		vs_fat32_length; | ||||
| /* 28*/	__u16		vs_flags; | ||||
| /* 2a*/	__u8		vs_version[2]; | ||||
| /* 2c*/	__u32		vs_root_cluster; | ||||
| /* 30*/	__u16		vs_insfo_sector; | ||||
| /* 32*/	__u16		vs_backup_boot; | ||||
| /* 34*/	__u16		vs_reserved2[6]; | ||||
| /* 40*/	unsigned char	vs_unknown[3]; | ||||
| /* 43*/	unsigned char	vs_serno[4]; | ||||
| /* 47*/	char		vs_label[11]; | ||||
| /* 52*/	unsigned char   vs_magic[8]; | ||||
| /* 5a*/	unsigned char	vs_dummy2[164]; | ||||
| /*1fe*/	unsigned char	vs_pmagic[2]; | ||||
| }; | ||||
|  | ||||
| /* Yucky misaligned values */ | ||||
| struct msdos_super_block { | ||||
| /* 00*/	unsigned char	ms_ignored[3]; | ||||
| /* 03*/	unsigned char	ms_sysid[8]; | ||||
| /* 0b*/	unsigned char	ms_sector_size[2]; | ||||
| /* 0d*/	__u8		ms_cluster_size; | ||||
| /* 0e*/	__u16		ms_reserved; | ||||
| /* 10*/	__u8		ms_fats; | ||||
| /* 11*/	unsigned char	ms_dir_entries[2]; | ||||
| /* 13*/	unsigned char	ms_sectors[2]; | ||||
| /* 15*/	unsigned char	ms_media; | ||||
| /* 16*/	__u16		ms_fat_length; | ||||
| /* 18*/	__u16		ms_secs_track; | ||||
| /* 1a*/	__u16		ms_heads; | ||||
| /* 1c*/	__u32		ms_hidden; | ||||
| /* 20*/	__u32		ms_total_sect; | ||||
| /* 24*/	unsigned char	ms_unknown[3]; | ||||
| /* 27*/	unsigned char	ms_serno[4]; | ||||
| /* 2b*/	char		ms_label[11]; | ||||
| /* 36*/	unsigned char   ms_magic[8]; | ||||
| /* 3d*/	unsigned char	ms_dummy2[192]; | ||||
| /*1fe*/	unsigned char	ms_pmagic[2]; | ||||
| }; | ||||
|  | ||||
| struct minix_super_block { | ||||
| 	__u16		ms_ninodes; | ||||
| 	__u16		ms_nzones; | ||||
| 	__u16		ms_imap_blocks; | ||||
| 	__u16		ms_zmap_blocks; | ||||
| 	__u16		ms_firstdatazone; | ||||
| 	__u16		ms_log_zone_size; | ||||
| 	__u32		ms_max_size; | ||||
| 	unsigned char	ms_magic[2]; | ||||
| 	__u16		ms_state; | ||||
| 	__u32		ms_zones; | ||||
| }; | ||||
|  | ||||
| struct mdp_superblock_s { | ||||
| 	__u32 md_magic; | ||||
| 	__u32 major_version; | ||||
| 	__u32 minor_version; | ||||
| 	__u32 patch_version; | ||||
| 	__u32 gvalid_words; | ||||
| 	__u32 set_uuid0; | ||||
| 	__u32 ctime; | ||||
| 	__u32 level; | ||||
| 	__u32 size; | ||||
| 	__u32 nr_disks; | ||||
| 	__u32 raid_disks; | ||||
| 	__u32 md_minor; | ||||
| 	__u32 not_persistent; | ||||
| 	__u32 set_uuid1; | ||||
| 	__u32 set_uuid2; | ||||
| 	__u32 set_uuid3; | ||||
| }; | ||||
|  | ||||
| struct hfs_super_block { | ||||
| 	char	h_magic[2]; | ||||
| 	char	h_dummy[18]; | ||||
| 	__u32	h_blksize; | ||||
| }; | ||||
|  | ||||
| struct ocfs_volume_header { | ||||
| 	unsigned char	minor_version[4]; | ||||
| 	unsigned char	major_version[4]; | ||||
| 	unsigned char	signature[128]; | ||||
| 	char		mount[128]; | ||||
| 	unsigned char   mount_len[2]; | ||||
| }; | ||||
|  | ||||
| struct ocfs_volume_label { | ||||
| 	unsigned char	disk_lock[48]; | ||||
| 	char		label[64]; | ||||
| 	unsigned char	label_len[2]; | ||||
| 	unsigned char  vol_id[16]; | ||||
| 	unsigned char  vol_id_len[2]; | ||||
| }; | ||||
|  | ||||
| #define ocfsmajor(o) ((__u32)o.major_version[0] \ | ||||
|                    + (((__u32) o.major_version[1]) << 8) \ | ||||
|                    + (((__u32) o.major_version[2]) << 16) \ | ||||
|                    + (((__u32) o.major_version[3]) << 24)) | ||||
| #define ocfslabellen(o)	((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8)) | ||||
| #define ocfsmountlen(o)	((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8)) | ||||
|  | ||||
| #define OCFS_MAGIC "OracleCFS" | ||||
|  | ||||
| struct ocfs2_super_block { | ||||
| 	unsigned char  signature[8]; | ||||
| 	unsigned char  s_dummy1[184]; | ||||
| 	unsigned char  s_dummy2[80]; | ||||
| 	char	       s_label[64]; | ||||
| 	unsigned char  s_uuid[16]; | ||||
| }; | ||||
|  | ||||
| #define OCFS2_MIN_BLOCKSIZE             512 | ||||
| #define OCFS2_MAX_BLOCKSIZE             4096 | ||||
|  | ||||
| #define OCFS2_SUPER_BLOCK_BLKNO         2 | ||||
|  | ||||
| #define OCFS2_SUPER_BLOCK_SIGNATURE     "OCFSV2" | ||||
|  | ||||
| struct oracle_asm_disk_label { | ||||
| 	char dummy[32]; | ||||
| 	char dl_tag[8]; | ||||
| 	char dl_id[24]; | ||||
| }; | ||||
|  | ||||
| #define ORACLE_ASM_DISK_LABEL_MARKED    "ORCLDISK" | ||||
| #define ORACLE_ASM_DISK_LABEL_OFFSET    32 | ||||
|  | ||||
| #define ISODCL(from, to) (to - from + 1) | ||||
| struct iso_volume_descriptor { | ||||
| 	char type[ISODCL(1,1)]; /* 711 */ | ||||
| 	char id[ISODCL(2,6)]; | ||||
| 	char version[ISODCL(7,7)]; | ||||
| 	char data[ISODCL(8,2048)]; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Byte swap functions | ||||
|  */ | ||||
| #ifdef __GNUC__ | ||||
| #define _INLINE_ static __inline__ | ||||
| #else				/* For Watcom C */ | ||||
| #define _INLINE_ static inline | ||||
| #endif | ||||
|  | ||||
| static __u16 blkid_swab16(__u16 val); | ||||
| static __u32 blkid_swab32(__u32 val); | ||||
| static __u64 blkid_swab64(__u64 val); | ||||
|  | ||||
| #if ((defined __GNUC__) && \ | ||||
|      (defined(__i386__) || defined(__i486__) || defined(__i586__))) | ||||
|  | ||||
| #define _BLKID_HAVE_ASM_BITOPS_ | ||||
|  | ||||
| _INLINE_ __u32 blkid_swab32(__u32 val) | ||||
| { | ||||
| #ifdef EXT2FS_REQUIRE_486 | ||||
| 	__asm__("bswap %0" : "=r" (val) : "0" (val)); | ||||
| #else | ||||
| 	__asm__("xchgb %b0,%h0\n\t"	/* swap lower bytes  */ | ||||
| 		"rorl $16,%0\n\t"	/* swap words        */ | ||||
| 		"xchgb %b0,%h0"		/* swap higher bytes */ | ||||
| 		:"=q" (val) | ||||
| 		: "0" (val)); | ||||
| #endif | ||||
| 	return val; | ||||
| } | ||||
|  | ||||
| _INLINE_ __u16 blkid_swab16(__u16 val) | ||||
| { | ||||
| 	__asm__("xchgb %b0,%h0"		/* swap bytes */ | ||||
| 		: "=q" (val) | ||||
| 		:  "0" (val)); | ||||
| 		return val; | ||||
| } | ||||
|  | ||||
| _INLINE_ __u64 blkid_swab64(__u64 val) | ||||
| { | ||||
| 	return blkid_swab32(val >> 32) | | ||||
| 	       ( ((__u64)blkid_swab32((__u32)val)) << 32 ); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if !defined(_BLKID_HAVE_ASM_BITOPS_) | ||||
|  | ||||
| _INLINE_  __u16 blkid_swab16(__u16 val) | ||||
| { | ||||
| 	return (val >> 8) | (val << 8); | ||||
| } | ||||
|  | ||||
| _INLINE_ __u32 blkid_swab32(__u32 val) | ||||
| { | ||||
| 	return (val>>24) | ((val>>8) & 0xFF00) | | ||||
| 		((val<<8) & 0xFF0000) | (val<<24); | ||||
| } | ||||
|  | ||||
| _INLINE_ __u64 blkid_swab64(__u64 val) | ||||
| { | ||||
| 	return blkid_swab32(val >> 32) | | ||||
| 	       ( ((__u64)blkid_swab32((__u32)val)) << 32 ); | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
| #if  __BYTE_ORDER == __BIG_ENDIAN | ||||
| #define blkid_le16(x) blkid_swab16(x) | ||||
| #define blkid_le32(x) blkid_swab32(x) | ||||
| #define blkid_le64(x) blkid_swab64(x) | ||||
| #define blkid_be16(x) (x) | ||||
| #define blkid_be32(x) (x) | ||||
| #define blkid_be64(x) (x) | ||||
| #else | ||||
| #define blkid_le16(x) (x) | ||||
| #define blkid_le32(x) (x) | ||||
| #define blkid_le64(x) (x) | ||||
| #define blkid_be16(x) blkid_swab16(x) | ||||
| #define blkid_be32(x) blkid_swab32(x) | ||||
| #define blkid_be64(x) blkid_swab64(x) | ||||
| #endif | ||||
|  | ||||
| #undef _INLINE_ | ||||
|  | ||||
| #endif /* _BLKID_PROBE_H */ | ||||
| @@ -1,459 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * read.c - read the blkid cache from disk, to avoid scanning all devices | ||||
|  * | ||||
|  * Copyright (C) 2001, 2003 Theodore Y. Ts'o | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <ctype.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "blkidP.h" | ||||
| #include "../uuid/uuid.h" | ||||
|  | ||||
| #ifdef HAVE_STRTOULL | ||||
| #define __USE_ISOC9X | ||||
| #define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */ | ||||
| #else | ||||
| /* FIXME: need to support real strtoull here */ | ||||
| #define STRTOULL strtoul | ||||
| #endif | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| #define blkid_debug_dump_dev(dev)  (debug_dump_dev(dev)) | ||||
| static void debug_dump_dev(blkid_dev dev); | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * File format: | ||||
|  * | ||||
|  *	<device [<NAME="value"> ...]>device_name</device> | ||||
|  * | ||||
|  *	The following tags are required for each entry: | ||||
|  *	<ID="id">	unique (within this file) ID number of this device | ||||
|  *	<TIME="time">	(ascii time_t) time this entry was last read from disk | ||||
|  *	<TYPE="type">	(detected) type of filesystem/data for this partition | ||||
|  * | ||||
|  *	The following tags may be present, depending on the device contents | ||||
|  *	<LABEL="label">	(user supplied) label (volume name, etc) | ||||
|  *	<UUID="uuid">	(generated) universally unique identifier (serial no) | ||||
|  */ | ||||
|  | ||||
| static char *skip_over_blank(char *cp) | ||||
| { | ||||
| 	while (*cp && isspace(*cp)) | ||||
| 		cp++; | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| static char *skip_over_word(char *cp) | ||||
| { | ||||
| 	char ch; | ||||
|  | ||||
| 	while ((ch = *cp)) { | ||||
| 		/* If we see a backslash, skip the next character */ | ||||
| 		if (ch == '\\') { | ||||
| 			cp++; | ||||
| 			if (*cp == '\0') | ||||
| 				break; | ||||
| 			cp++; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (isspace(ch) || ch == '<' || ch == '>') | ||||
| 			break; | ||||
| 		cp++; | ||||
| 	} | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| static char *strip_line(char *line) | ||||
| { | ||||
| 	char	*p; | ||||
|  | ||||
| 	line = skip_over_blank(line); | ||||
|  | ||||
| 	p = line + strlen(line) - 1; | ||||
|  | ||||
| 	while (*line) { | ||||
| 		if (isspace(*p)) | ||||
| 			*p-- = '\0'; | ||||
| 		else | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	return line; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Start parsing a new line from the cache. | ||||
|  * | ||||
|  * line starts with "<device" return 1 -> continue parsing line | ||||
|  * line starts with "<foo", empty, or # return 0 -> skip line | ||||
|  * line starts with other, return -BLKID_ERR_CACHE -> error | ||||
|  */ | ||||
| static int parse_start(char **cp) | ||||
| { | ||||
| 	char *p; | ||||
|  | ||||
| 	p = strip_line(*cp); | ||||
|  | ||||
| 	/* Skip comment or blank lines.  We can't just NUL the first '#' char, | ||||
| 	 * in case it is inside quotes, or escaped. | ||||
| 	 */ | ||||
| 	if (*p == '\0' || *p == '#') | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!strncmp(p, "<device", 7)) { | ||||
| 		DBG(DEBUG_READ, printf("found device header: %8s\n", p)); | ||||
| 		p += 7; | ||||
|  | ||||
| 		*cp = p; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (*p == '<') | ||||
| 		return 0; | ||||
|  | ||||
| 	return -BLKID_ERR_CACHE; | ||||
| } | ||||
|  | ||||
| /* Consume the remaining XML on the line (cosmetic only) */ | ||||
| static int parse_end(char **cp) | ||||
| { | ||||
| 	*cp = skip_over_blank(*cp); | ||||
|  | ||||
| 	if (!strncmp(*cp, "</device>", 9)) { | ||||
| 		DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp)); | ||||
| 		*cp += 9; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return -BLKID_ERR_CACHE; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Allocate a new device struct with device name filled in.  Will handle | ||||
|  * finding the device on lines of the form: | ||||
|  * <device foo=bar>devname</device> | ||||
|  * <device>devname<foo>bar</foo></device> | ||||
|  */ | ||||
| static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp) | ||||
| { | ||||
| 	char *start, *tmp, *end, *name; | ||||
| 	int ret; | ||||
|  | ||||
| 	if ((ret = parse_start(cp)) <= 0) | ||||
| 		return ret; | ||||
|  | ||||
| 	start = tmp = strchr(*cp, '>'); | ||||
| 	if (!start) { | ||||
| 		DBG(DEBUG_READ, | ||||
| 		    printf("blkid: short line parsing dev: %s\n", *cp)); | ||||
| 		return -BLKID_ERR_CACHE; | ||||
| 	} | ||||
| 	start = skip_over_blank(start + 1); | ||||
| 	end = skip_over_word(start); | ||||
|  | ||||
| 	DBG(DEBUG_READ, printf("device should be %*s\n", end - start, start)); | ||||
|  | ||||
| 	if (**cp == '>') | ||||
| 		*cp = end; | ||||
| 	else | ||||
| 		(*cp)++; | ||||
|  | ||||
| 	*tmp = '\0'; | ||||
|  | ||||
| 	if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) { | ||||
| 		DBG(DEBUG_READ, | ||||
| 		    printf("blkid: missing </device> ending: %s\n", end)); | ||||
| 	} else if (tmp) | ||||
| 		*tmp = '\0'; | ||||
|  | ||||
| 	if (end - start <= 1) { | ||||
| 		DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp)); | ||||
| 		return -BLKID_ERR_CACHE; | ||||
| 	} | ||||
|  | ||||
| 	name = blkid_strndup(start, end-start); | ||||
| 	if (name == NULL) | ||||
| 		return -BLKID_ERR_MEM; | ||||
|  | ||||
| 	DBG(DEBUG_READ, printf("found dev %s\n", name)); | ||||
|  | ||||
| 	if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) | ||||
| 		return -BLKID_ERR_MEM; | ||||
|  | ||||
| 	free(name); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Extract a tag of the form NAME="value" from the line. | ||||
|  */ | ||||
| static int parse_token(char **name, char **value, char **cp) | ||||
| { | ||||
| 	char *end; | ||||
|  | ||||
| 	if (!name || !value || !cp) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	if (!(*value = strchr(*cp, '='))) | ||||
| 		return 0; | ||||
|  | ||||
| 	**value = '\0'; | ||||
| 	*name = strip_line(*cp); | ||||
| 	*value = skip_over_blank(*value + 1); | ||||
|  | ||||
| 	if (**value == '"') { | ||||
| 		end = strchr(*value + 1, '"'); | ||||
| 		if (!end) { | ||||
| 			DBG(DEBUG_READ, | ||||
| 			    printf("unbalanced quotes at: %s\n", *value)); | ||||
| 			*cp = *value; | ||||
| 			return -BLKID_ERR_CACHE; | ||||
| 		} | ||||
| 		(*value)++; | ||||
| 		*end = '\0'; | ||||
| 		end++; | ||||
| 	} else { | ||||
| 		end = skip_over_word(*value); | ||||
| 		if (*end) { | ||||
| 			*end = '\0'; | ||||
| 			end++; | ||||
| 		} | ||||
| 	} | ||||
| 	*cp = end; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Extract a tag of the form <NAME>value</NAME> from the line. | ||||
|  */ | ||||
| /* | ||||
| static int parse_xml(char **name, char **value, char **cp) | ||||
| { | ||||
| 	char *end; | ||||
|  | ||||
| 	if (!name || !value || !cp) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	*name = strip_line(*cp); | ||||
|  | ||||
| 	if ((*name)[0] != '<' || (*name)[1] == '/') | ||||
| 		return 0; | ||||
|  | ||||
| 	FIXME: finish this. | ||||
| } | ||||
| */ | ||||
|  | ||||
| /* | ||||
|  * Extract a tag from the line. | ||||
|  * | ||||
|  * Return 1 if a valid tag was found. | ||||
|  * Return 0 if no tag found. | ||||
|  * Return -ve error code. | ||||
|  */ | ||||
| static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp) | ||||
| { | ||||
| 	char *name; | ||||
| 	char *value; | ||||
| 	int ret; | ||||
|  | ||||
| 	if (!cache || !dev) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	if ((ret = parse_token(&name, &value, cp)) <= 0 /* && | ||||
| 	    (ret = parse_xml(&name, &value, cp)) <= 0 */) | ||||
| 		return ret; | ||||
|  | ||||
| 	/* Some tags are stored directly in the device struct */ | ||||
| 	if (!strcmp(name, "DEVNO")) | ||||
| 		dev->bid_devno = STRTOULL(value, 0, 0); | ||||
| 	else if (!strcmp(name, "PRI")) | ||||
| 		dev->bid_pri = strtol(value, 0, 0); | ||||
| 	else if (!strcmp(name, "TIME")) | ||||
| 		/* FIXME: need to parse a long long eventually */ | ||||
| 		dev->bid_time = strtol(value, 0, 0); | ||||
| 	else | ||||
| 		ret = blkid_set_tag(dev, name, value, strlen(value)); | ||||
|  | ||||
| 	DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", name, value)); | ||||
|  | ||||
| 	return ret < 0 ? ret : 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Parse a single line of data, and return a newly allocated dev struct. | ||||
|  * Add the new device to the cache struct, if one was read. | ||||
|  * | ||||
|  * Lines are of the form <device [TAG="value" ...]>/dev/foo</device> | ||||
|  * | ||||
|  * Returns -ve value on error. | ||||
|  * Returns 0 otherwise. | ||||
|  * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL | ||||
|  * (e.g. comment lines, unknown XML content, etc). | ||||
|  */ | ||||
| static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp) | ||||
| { | ||||
| 	blkid_dev dev; | ||||
| 	int ret; | ||||
|  | ||||
| 	if (!cache || !dev_p) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	*dev_p = NULL; | ||||
|  | ||||
| 	DBG(DEBUG_READ, printf("line: %s\n", cp)); | ||||
|  | ||||
| 	if ((ret = parse_dev(cache, dev_p, &cp)) <= 0) | ||||
| 		return ret; | ||||
|  | ||||
| 	dev = *dev_p; | ||||
|  | ||||
| 	while ((ret = parse_tag(cache, dev, &cp)) > 0) { | ||||
| 		; | ||||
| 	} | ||||
|  | ||||
| 	if (dev->bid_type == NULL) { | ||||
| 		DBG(DEBUG_READ, | ||||
| 		    printf("blkid: device %s has no TYPE\n",dev->bid_name)); | ||||
| 		blkid_free_dev(dev); | ||||
| 	} | ||||
|  | ||||
| 	DBG(DEBUG_READ, blkid_debug_dump_dev(dev)); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Parse the specified filename, and return the data in the supplied or | ||||
|  * a newly allocated cache struct.  If the file doesn't exist, return a | ||||
|  * new empty cache struct. | ||||
|  */ | ||||
| void blkid_read_cache(blkid_cache cache) | ||||
| { | ||||
| 	FILE *file; | ||||
| 	char buf[4096]; | ||||
| 	int fd, lineno = 0; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if (!cache) | ||||
| 		return; | ||||
|  | ||||
| 	/* | ||||
| 	 * If the file doesn't exist, then we just return an empty | ||||
| 	 * struct so that the cache can be populated. | ||||
| 	 */ | ||||
| 	if ((fd = open(cache->bic_filename, O_RDONLY)) < 0) | ||||
| 		return; | ||||
| 	if (fstat(fd, &st) < 0) | ||||
| 		goto errout; | ||||
| 	if ((st.st_mtime == cache->bic_ftime) || | ||||
| 	    (cache->bic_flags & BLKID_BIC_FL_CHANGED)) { | ||||
| 		DBG(DEBUG_CACHE, printf("skipping re-read of %s\n", | ||||
| 					cache->bic_filename)); | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	DBG(DEBUG_CACHE, printf("reading cache file %s\n", | ||||
| 				cache->bic_filename)); | ||||
|  | ||||
| 	file = xfdopen_for_read(fd); | ||||
|  | ||||
| 	while (fgets(buf, sizeof(buf), file)) { | ||||
| 		blkid_dev dev; | ||||
| 		unsigned int end; | ||||
|  | ||||
| 		lineno++; | ||||
| 		if (buf[0] == 0) | ||||
| 			continue; | ||||
| 		end = strlen(buf) - 1; | ||||
| 		/* Continue reading next line if it ends with a backslash */ | ||||
| 		while (end < sizeof(buf) - 2 && buf[end] == '\\' && | ||||
| 		       fgets(buf + end, sizeof(buf) - end, file)) { | ||||
| 			end = strlen(buf) - 1; | ||||
| 			lineno++; | ||||
| 		} | ||||
|  | ||||
| 		if (blkid_parse_line(cache, &dev, buf) < 0) { | ||||
| 			DBG(DEBUG_READ, | ||||
| 			    printf("blkid: bad format on line %d\n", lineno)); | ||||
| 			continue; | ||||
| 		} | ||||
| 	} | ||||
| 	fclose(file); | ||||
|  | ||||
| 	/* | ||||
| 	 * Initially we do not need to write out the cache file. | ||||
| 	 */ | ||||
| 	cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; | ||||
| 	cache->bic_ftime = st.st_mtime; | ||||
|  | ||||
| 	return; | ||||
| errout: | ||||
| 	close(fd); | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| static void debug_dump_dev(blkid_dev dev) | ||||
| { | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!dev) { | ||||
| 		printf("  dev: NULL\n"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	printf("  dev: name = %s\n", dev->bid_name); | ||||
| 	printf("  dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno); | ||||
| 	printf("  dev: TIME=\"%lu\"\n", dev->bid_time); | ||||
| 	printf("  dev: PRI=\"%d\"\n", dev->bid_pri); | ||||
| 	printf("  dev: flags = 0x%08X\n", dev->bid_flags); | ||||
|  | ||||
| 	list_for_each(p, &dev->bid_tags) { | ||||
| 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); | ||||
| 		if (tag) | ||||
| 			printf("    tag: %s=\"%s\"\n", tag->bit_name, | ||||
| 			       tag->bit_val); | ||||
| 		else | ||||
| 			printf("    tag: NULL\n"); | ||||
| 	} | ||||
| 	bb_putchar('\n'); | ||||
| } | ||||
|  | ||||
| int main(int argc, char**argv) | ||||
| { | ||||
| 	blkid_cache cache = NULL; | ||||
| 	int ret; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if (argc > 2) { | ||||
| 		fprintf(stderr, "Usage: %s [filename]\n" | ||||
| 			"Test parsing of the cache (filename)\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if ((ret = blkid_get_cache(&cache, argv[1])) < 0) | ||||
| 		fprintf(stderr, "error %d reading cache file %s\n", ret, | ||||
| 			argv[1] ? argv[1] : BLKID_CACHE_FILE); | ||||
|  | ||||
| 	blkid_put_cache(cache); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| @@ -1,139 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * resolve.c - resolve names and tags into specific devices | ||||
|  * | ||||
|  * Copyright (C) 2001, 2003 Theodore Ts'o. | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #ifdef HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include "blkidP.h" | ||||
| #include "probe.h" | ||||
|  | ||||
| /* | ||||
|  * Find a tagname (e.g. LABEL or UUID) on a specific device. | ||||
|  */ | ||||
| char *blkid_get_tag_value(blkid_cache cache, const char *tagname, | ||||
| 			  const char *devname) | ||||
| { | ||||
| 	blkid_tag found; | ||||
| 	blkid_dev dev; | ||||
| 	blkid_cache c = cache; | ||||
| 	char *ret = NULL; | ||||
|  | ||||
| 	DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname)); | ||||
|  | ||||
| 	if (!devname) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!cache) { | ||||
| 		if (blkid_get_cache(&c, NULL) < 0) | ||||
| 			return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) && | ||||
| 	    (found = blkid_find_tag_dev(dev, tagname))) | ||||
| 		ret = blkid_strdup(found->bit_val); | ||||
|  | ||||
| 	if (!cache) | ||||
| 		blkid_put_cache(c); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Locate a device name from a token (NAME=value string), or (name, value) | ||||
|  * pair.  In the case of a token, value is ignored.  If the "token" is not | ||||
|  * of the form "NAME=value" and there is no value given, then it is assumed | ||||
|  * to be the actual devname and a copy is returned. | ||||
|  */ | ||||
| char *blkid_get_devname(blkid_cache cache, const char *token, | ||||
| 			const char *value) | ||||
| { | ||||
| 	blkid_dev dev; | ||||
| 	blkid_cache c = cache; | ||||
| 	char *t = NULL, *v = NULL; | ||||
| 	char *ret = NULL; | ||||
|  | ||||
| 	if (!token) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!cache) { | ||||
| 		if (blkid_get_cache(&c, NULL) < 0) | ||||
| 			return NULL; | ||||
| 	} | ||||
|  | ||||
| 	DBG(DEBUG_RESOLVE, | ||||
| 	    printf("looking for %s%s%s %s\n", token, value ? "=" : "", | ||||
| 		   value ? value : "", cache ? "in cache" : "from disk")); | ||||
|  | ||||
| 	if (!value) { | ||||
| 		if (!strchr(token, '=')) | ||||
| 			return blkid_strdup(token); | ||||
| 		blkid_parse_tag_string(token, &t, &v); | ||||
| 		if (!t || !v) | ||||
| 			goto errout; | ||||
| 		token = t; | ||||
| 		value = v; | ||||
| 	} | ||||
|  | ||||
| 	dev = blkid_find_dev_with_tag(c, token, value); | ||||
| 	if (!dev) | ||||
| 		goto errout; | ||||
|  | ||||
| 	ret = blkid_strdup(blkid_dev_devname(dev)); | ||||
|  | ||||
| errout: | ||||
| 	free(t); | ||||
| 	free(v); | ||||
| 	if (!cache) { | ||||
| 		blkid_put_cache(c); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	char *value; | ||||
| 	blkid_cache cache; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if (argc != 2 && argc != 3) { | ||||
| 		fprintf(stderr, "Usage:\t%s tagname=value\n" | ||||
| 			"\t%s tagname devname\n" | ||||
| 			"Find which device holds a given token or\n" | ||||
| 			"Find what the value of a tag is in a device\n", | ||||
| 			argv[0], argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if (blkid_get_cache(&cache, bb_dev_null) < 0) { | ||||
| 		fprintf(stderr, "Can't get blkid cache\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	if (argv[2]) { | ||||
| 		value = blkid_get_tag_value(cache, argv[1], argv[2]); | ||||
| 		printf("%s has tag %s=%s\n", argv[2], argv[1], | ||||
| 		       value ? value : "<missing>"); | ||||
| 	} else { | ||||
| 		value = blkid_get_devname(cache, argv[1], NULL); | ||||
| 		printf("%s has tag %s\n", value ? value : "<none>", argv[1]); | ||||
| 	} | ||||
| 	blkid_put_cache(cache); | ||||
| 	return value ? 0 : 1; | ||||
| } | ||||
| #endif | ||||
| @@ -1,189 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * save.c - write the cache struct to disk | ||||
|  * | ||||
|  * Copyright (C) 2001 by Andreas Dilger | ||||
|  * Copyright (C) 2003 Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/types.h> | ||||
| #ifdef HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_MKDEV_H | ||||
| #include <sys/mkdev.h> | ||||
| #endif | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include "blkidP.h" | ||||
|  | ||||
| static int save_dev(blkid_dev dev, FILE *file) | ||||
| { | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!dev || dev->bid_name[0] != '/') | ||||
| 		return 0; | ||||
|  | ||||
| 	DBG(DEBUG_SAVE, | ||||
| 	    printf("device %s, type %s\n", dev->bid_name, dev->bid_type)); | ||||
|  | ||||
| 	fprintf(file, | ||||
| 		"<device DEVNO=\"0x%04lx\" TIME=\"%lu\"", | ||||
| 		(unsigned long) dev->bid_devno, dev->bid_time); | ||||
| 	if (dev->bid_pri) | ||||
| 		fprintf(file, " PRI=\"%d\"", dev->bid_pri); | ||||
| 	list_for_each(p, &dev->bid_tags) { | ||||
| 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); | ||||
| 		fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); | ||||
| 	} | ||||
| 	fprintf(file, ">%s</device>\n", dev->bid_name); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write out the cache struct to the cache file on disk. | ||||
|  */ | ||||
| int blkid_flush_cache(blkid_cache cache) | ||||
| { | ||||
| 	struct list_head *p; | ||||
| 	char *tmp = NULL; | ||||
| 	const char *opened = NULL; | ||||
| 	const char *filename; | ||||
| 	FILE *file = NULL; | ||||
| 	int fd, ret = 0; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if (!cache) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	if (list_empty(&cache->bic_devs) || | ||||
| 	    !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { | ||||
| 		DBG(DEBUG_SAVE, printf("skipping cache file write\n")); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE; | ||||
|  | ||||
| 	/* If we can't write to the cache file, then don't even try */ | ||||
| 	if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || | ||||
| 	    (ret == 0 && access(filename, W_OK) < 0)) { | ||||
| 		DBG(DEBUG_SAVE, | ||||
| 		    printf("can't write to cache file %s\n", filename)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Try and create a temporary file in the same directory so | ||||
| 	 * that in case of error we don't overwrite the cache file. | ||||
| 	 * If the cache file doesn't yet exist, it isn't a regular | ||||
| 	 * file (e.g. /dev/null or a socket), or we couldn't create | ||||
| 	 * a temporary file then we open it directly. | ||||
| 	 */ | ||||
| 	if (ret == 0 && S_ISREG(st.st_mode)) { | ||||
| 		tmp = xmalloc(strlen(filename) + 8); | ||||
| 		sprintf(tmp, "%s-XXXXXX", filename); | ||||
| 		fd = mkstemp(tmp); | ||||
| 		if (fd >= 0) { | ||||
| 			file = xfdopen_for_write(fd); | ||||
| 			opened = tmp; | ||||
| 		} | ||||
| 		fchmod(fd, 0644); | ||||
| 	} | ||||
|  | ||||
| 	if (!file) { | ||||
| 		file = fopen_for_write(filename); | ||||
| 		opened = filename; | ||||
| 	} | ||||
|  | ||||
| 	DBG(DEBUG_SAVE, | ||||
| 	    printf("writing cache file %s (really %s)\n", | ||||
| 		   filename, opened)); | ||||
|  | ||||
| 	if (!file) { | ||||
| 		ret = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	list_for_each(p, &cache->bic_devs) { | ||||
| 		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); | ||||
| 		if (!dev->bid_type) | ||||
| 			continue; | ||||
| 		if ((ret = save_dev(dev, file)) < 0) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	if (ret >= 0) { | ||||
| 		cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; | ||||
| 		ret = 1; | ||||
| 	} | ||||
|  | ||||
| 	fclose(file); | ||||
| 	if (opened != filename) { | ||||
| 		if (ret < 0) { | ||||
| 			unlink(opened); | ||||
| 			DBG(DEBUG_SAVE, | ||||
| 			    printf("unlinked temp cache %s\n", opened)); | ||||
| 		} else { | ||||
| 			char *backup; | ||||
|  | ||||
| 			backup = xmalloc(strlen(filename) + 5); | ||||
| 			sprintf(backup, "%s.old", filename); | ||||
| 			unlink(backup); | ||||
| 			link(filename, backup); | ||||
| 			free(backup); | ||||
| 			rename(opened, filename); | ||||
| 			DBG(DEBUG_SAVE, | ||||
| 			    printf("moved temp cache %s\n", opened)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| errout: | ||||
| 	free(tmp); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blkid_cache cache = NULL; | ||||
| 	int ret; | ||||
|  | ||||
| 	blkid_debug_mask = DEBUG_ALL; | ||||
| 	if (argc > 2) { | ||||
| 		fprintf(stderr, "Usage: %s [filename]\n" | ||||
| 			"Test loading/saving a cache (filename)\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) { | ||||
| 		fprintf(stderr, "%s: error creating cache (%d)\n", | ||||
| 			argv[0], ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if ((ret = blkid_probe_all(cache)) < 0) { | ||||
| 		fprintf(stderr, "error (%d) probing devices\n", ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	cache->bic_filename = blkid_strdup(argv[1]); | ||||
|  | ||||
| 	if ((ret = blkid_flush_cache(cache)) < 0) { | ||||
| 		fprintf(stderr, "error (%d) saving cache\n", ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	blkid_put_cache(cache); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| @@ -1,431 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * tag.c - allocation/initialization/free routines for tag structs | ||||
|  * | ||||
|  * Copyright (C) 2001 Andreas Dilger | ||||
|  * Copyright (C) 2003 Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the | ||||
|  * GNU Lesser General Public License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "blkidP.h" | ||||
|  | ||||
| static blkid_tag blkid_new_tag(void) | ||||
| { | ||||
| 	blkid_tag tag; | ||||
|  | ||||
| 	tag = xzalloc(sizeof(struct blkid_struct_tag)); | ||||
|  | ||||
| 	INIT_LIST_HEAD(&tag->bit_tags); | ||||
| 	INIT_LIST_HEAD(&tag->bit_names); | ||||
|  | ||||
| 	return tag; | ||||
| } | ||||
|  | ||||
| #ifdef CONFIG_BLKID_DEBUG | ||||
| void blkid_debug_dump_tag(blkid_tag tag) | ||||
| { | ||||
| 	if (!tag) { | ||||
| 		printf("    tag: NULL\n"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	printf("    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void blkid_free_tag(blkid_tag tag) | ||||
| { | ||||
| 	if (!tag) | ||||
| 		return; | ||||
|  | ||||
| 	DBG(DEBUG_TAG, printf("    freeing tag %s=%s\n", tag->bit_name, | ||||
| 		   tag->bit_val ? tag->bit_val : "(NULL)")); | ||||
| 	DBG(DEBUG_TAG, blkid_debug_dump_tag(tag)); | ||||
|  | ||||
| 	list_del(&tag->bit_tags);	/* list of tags for this device */ | ||||
| 	list_del(&tag->bit_names);	/* list of tags with this type */ | ||||
|  | ||||
| 	free(tag->bit_name); | ||||
| 	free(tag->bit_val); | ||||
| 	free(tag); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Find the desired tag on a device.  If value is NULL, then the | ||||
|  * first such tag is returned, otherwise return only exact tag if found. | ||||
|  */ | ||||
| blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) | ||||
| { | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!dev || !type) | ||||
| 		return NULL; | ||||
|  | ||||
| 	list_for_each(p, &dev->bid_tags) { | ||||
| 		blkid_tag tmp = list_entry(p, struct blkid_struct_tag, | ||||
| 					   bit_tags); | ||||
|  | ||||
| 		if (!strcmp(tmp->bit_name, type)) | ||||
| 			return tmp; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Find the desired tag type in the cache. | ||||
|  * We return the head tag for this tag type. | ||||
|  */ | ||||
| static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type) | ||||
| { | ||||
| 	blkid_tag head = NULL, tmp; | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!cache || !type) | ||||
| 		return NULL; | ||||
|  | ||||
| 	list_for_each(p, &cache->bic_tags) { | ||||
| 		tmp = list_entry(p, struct blkid_struct_tag, bit_tags); | ||||
| 		if (!strcmp(tmp->bit_name, type)) { | ||||
| 			DBG(DEBUG_TAG, | ||||
| 			    printf("    found cache tag head %s\n", type)); | ||||
| 			head = tmp; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Set a tag on an existing device. | ||||
|  * | ||||
|  * If value is NULL, then delete the tagsfrom the device. | ||||
|  */ | ||||
| int blkid_set_tag(blkid_dev dev, const char *name, | ||||
| 		  const char *value, const int vlength) | ||||
| { | ||||
| 	blkid_tag	t = 0, head = 0; | ||||
| 	char		*val = NULL; | ||||
|  | ||||
| 	if (!dev || !name) | ||||
| 		return -BLKID_ERR_PARAM; | ||||
|  | ||||
| 	if (!(val = blkid_strndup(value, vlength)) && value) | ||||
| 		return -BLKID_ERR_MEM; | ||||
| 	t = blkid_find_tag_dev(dev, name); | ||||
| 	if (!value) { | ||||
| 		blkid_free_tag(t); | ||||
| 	} else if (t) { | ||||
| 		if (!strcmp(t->bit_val, val)) { | ||||
| 			/* Same thing, exit */ | ||||
| 			free(val); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		free(t->bit_val); | ||||
| 		t->bit_val = val; | ||||
| 	} else { | ||||
| 		/* Existing tag not present, add to device */ | ||||
| 		if (!(t = blkid_new_tag())) | ||||
| 			goto errout; | ||||
| 		t->bit_name = blkid_strdup(name); | ||||
| 		t->bit_val = val; | ||||
| 		t->bit_dev = dev; | ||||
|  | ||||
| 		list_add_tail(&t->bit_tags, &dev->bid_tags); | ||||
|  | ||||
| 		if (dev->bid_cache) { | ||||
| 			head = blkid_find_head_cache(dev->bid_cache, | ||||
| 						     t->bit_name); | ||||
| 			if (!head) { | ||||
| 				head = blkid_new_tag(); | ||||
| 				if (!head) | ||||
| 					goto errout; | ||||
|  | ||||
| 				DBG(DEBUG_TAG, | ||||
| 				    printf("    creating new cache tag head %s\n", name)); | ||||
| 				head->bit_name = blkid_strdup(name); | ||||
| 				if (!head->bit_name) | ||||
| 					goto errout; | ||||
| 				list_add_tail(&head->bit_tags, | ||||
| 					      &dev->bid_cache->bic_tags); | ||||
| 			} | ||||
| 			list_add_tail(&t->bit_names, &head->bit_names); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Link common tags directly to the device struct */ | ||||
| 	if (!strcmp(name, "TYPE")) | ||||
| 		dev->bid_type = val; | ||||
| 	else if (!strcmp(name, "LABEL")) | ||||
| 		dev->bid_label = val; | ||||
| 	else if (!strcmp(name, "UUID")) | ||||
| 		dev->bid_uuid = val; | ||||
|  | ||||
| 	if (dev->bid_cache) | ||||
| 		dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED; | ||||
| 	return 0; | ||||
|  | ||||
| errout: | ||||
| 	blkid_free_tag(t); | ||||
| 	if (!t) | ||||
| 		free(val); | ||||
| 	blkid_free_tag(head); | ||||
| 	return -BLKID_ERR_MEM; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Parse a "NAME=value" string.  This is slightly different than | ||||
|  * parse_token, because that will end an unquoted value at a space, while | ||||
|  * this will assume that an unquoted value is the rest of the token (e.g. | ||||
|  * if we are passed an already quoted string from the command-line we don't | ||||
|  * have to both quote and escape quote so that the quotes make it to | ||||
|  * us). | ||||
|  * | ||||
|  * Returns 0 on success, and -1 on failure. | ||||
|  */ | ||||
| int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) | ||||
| { | ||||
| 	char *name, *value, *cp; | ||||
|  | ||||
| 	DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token)); | ||||
|  | ||||
| 	if (!token || !(cp = strchr(token, '='))) | ||||
| 		return -1; | ||||
|  | ||||
| 	name = blkid_strdup(token); | ||||
| 	if (!name) | ||||
| 		return -1; | ||||
| 	value = name + (cp - token); | ||||
| 	*value++ = '\0'; | ||||
| 	if (*value == '"' || *value == '\'') { | ||||
| 		char c = *value++; | ||||
| 		if (!(cp = strrchr(value, c))) | ||||
| 			goto errout; /* missing closing quote */ | ||||
| 		*cp = '\0'; | ||||
| 	} | ||||
| 	value = blkid_strdup(value); | ||||
| 	if (!value) | ||||
| 		goto errout; | ||||
|  | ||||
| 	*ret_type = name; | ||||
| 	*ret_val = value; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| errout: | ||||
| 	free(name); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Tag iteration routines for the public libblkid interface. | ||||
|  * | ||||
|  * These routines do not expose the list.h implementation, which are a | ||||
|  * contamination of the namespace, and which force us to reveal far, far | ||||
|  * too much of our internal implementation.  I'm not convinced I want | ||||
|  * to keep list.h in the long term, anyway.  It's fine for kernel | ||||
|  * programming, but performance is not the #1 priority for this | ||||
|  * library, and I really don't like the tradeoff of type-safety for | ||||
|  * performance for this application.  [tytso:20030125.2007EST] | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This series of functions iterate over all tags in a device | ||||
|  */ | ||||
| #define TAG_ITERATE_MAGIC	0x01a5284c | ||||
|  | ||||
| struct blkid_struct_tag_iterate { | ||||
| 	int			magic; | ||||
| 	blkid_dev		dev; | ||||
| 	struct list_head	*p; | ||||
| }; | ||||
|  | ||||
| blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) | ||||
| { | ||||
| 	blkid_tag_iterate	iter; | ||||
|  | ||||
| 	iter = xmalloc(sizeof(struct blkid_struct_tag_iterate)); | ||||
| 	iter->magic = TAG_ITERATE_MAGIC; | ||||
| 	iter->dev = dev; | ||||
| 	iter->p	= dev->bid_tags.next; | ||||
| 	return iter; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return 0 on success, -1 on error | ||||
|  */ | ||||
| extern int blkid_tag_next(blkid_tag_iterate iter, | ||||
| 			  const char **type, const char **value) | ||||
| { | ||||
| 	blkid_tag tag; | ||||
|  | ||||
| 	*type = 0; | ||||
| 	*value = 0; | ||||
| 	if (!iter || iter->magic != TAG_ITERATE_MAGIC || | ||||
| 	    iter->p == &iter->dev->bid_tags) | ||||
| 		return -1; | ||||
| 	tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags); | ||||
| 	*type = tag->bit_name; | ||||
| 	*value = tag->bit_val; | ||||
| 	iter->p = iter->p->next; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void blkid_tag_iterate_end(blkid_tag_iterate iter) | ||||
| { | ||||
| 	if (!iter || iter->magic != TAG_ITERATE_MAGIC) | ||||
| 		return; | ||||
| 	iter->magic = 0; | ||||
| 	free(iter); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function returns a device which matches a particular | ||||
|  * type/value pair.  If there is more than one device that matches the | ||||
|  * search specification, it returns the one with the highest priority | ||||
|  * value.  This allows us to give preference to EVMS or LVM devices. | ||||
|  * | ||||
|  * XXX there should also be an interface which uses an iterator so we | ||||
|  * can get all of the devices which match a type/value search parameter. | ||||
|  */ | ||||
| extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, | ||||
| 					 const char *type, | ||||
| 					 const char *value) | ||||
| { | ||||
| 	blkid_tag	head; | ||||
| 	blkid_dev	dev; | ||||
| 	int		pri; | ||||
| 	struct list_head *p; | ||||
|  | ||||
| 	if (!cache || !type || !value) | ||||
| 		return NULL; | ||||
|  | ||||
| 	blkid_read_cache(cache); | ||||
|  | ||||
| 	DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value)); | ||||
|  | ||||
| try_again: | ||||
| 	pri = -1; | ||||
| 	dev = 0; | ||||
| 	head = blkid_find_head_cache(cache, type); | ||||
|  | ||||
| 	if (head) { | ||||
| 		list_for_each(p, &head->bit_names) { | ||||
| 			blkid_tag tmp = list_entry(p, struct blkid_struct_tag, | ||||
| 						   bit_names); | ||||
|  | ||||
| 			if (!strcmp(tmp->bit_val, value) && | ||||
| 			    tmp->bit_dev->bid_pri > pri) { | ||||
| 				dev = tmp->bit_dev; | ||||
| 				pri = dev->bid_pri; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) { | ||||
| 		dev = blkid_verify(cache, dev); | ||||
| 		if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) | ||||
| 			goto try_again; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) { | ||||
| 		if (blkid_probe_all(cache) < 0) | ||||
| 			return NULL; | ||||
| 		goto try_again; | ||||
| 	} | ||||
| 	return dev; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| #ifdef HAVE_GETOPT_H | ||||
| #include <getopt.h> | ||||
| #else | ||||
| extern char *optarg; | ||||
| extern int optind; | ||||
| #endif | ||||
|  | ||||
| void usage(char *prog) | ||||
| { | ||||
| 	fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " | ||||
| 		"[type value]\n", | ||||
| 		prog); | ||||
| 	fprintf(stderr, "\tList all tags for a device and exit\n"); | ||||
| 	exit(1); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blkid_tag_iterate	iter; | ||||
| 	blkid_cache		cache = NULL; | ||||
| 	blkid_dev		dev; | ||||
| 	int			c, ret, found; | ||||
| 	int			flags = BLKID_DEV_FIND; | ||||
| 	char			*tmp; | ||||
| 	char			*file = NULL; | ||||
| 	char			*devname = NULL; | ||||
| 	char			*search_type = NULL; | ||||
| 	char			*search_value = NULL; | ||||
| 	const char		*type, *value; | ||||
|  | ||||
| 	while ((c = getopt (argc, argv, "m:f:")) != EOF) | ||||
| 		switch (c) { | ||||
| 		case 'f': | ||||
| 			file = optarg; | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			blkid_debug_mask = strtoul (optarg, &tmp, 0); | ||||
| 			if (*tmp) { | ||||
| 				fprintf(stderr, "Invalid debug mask: %s\n", | ||||
| 					optarg); | ||||
| 				exit(1); | ||||
| 			} | ||||
| 			break; | ||||
| 		case '?': | ||||
| 			usage(argv[0]); | ||||
| 		} | ||||
| 	if (argc > optind) | ||||
| 		devname = argv[optind++]; | ||||
| 	if (argc > optind) | ||||
| 		search_type = argv[optind++]; | ||||
| 	if (argc > optind) | ||||
| 		search_value = argv[optind++]; | ||||
| 	if (!devname || (argc != optind)) | ||||
| 		usage(argv[0]); | ||||
|  | ||||
| 	if ((ret = blkid_get_cache(&cache, file)) != 0) { | ||||
| 		fprintf(stderr, "%s: error creating cache (%d)\n", | ||||
| 			argv[0], ret); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	dev = blkid_get_dev(cache, devname, flags); | ||||
| 	if (!dev) { | ||||
| 		fprintf(stderr, "%s: cannot find device in blkid cache\n", devname); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if (search_type) { | ||||
| 		found = blkid_dev_has_tag(dev, search_type, search_value); | ||||
| 		printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev), | ||||
| 		       search_type, search_value ? search_value : "NULL", | ||||
| 		       found ? "FOUND" : "NOT FOUND"); | ||||
| 		return !found; | ||||
| 	} | ||||
| 	printf("Device %s...\n", blkid_dev_devname(dev)); | ||||
|  | ||||
| 	iter = blkid_tag_iterate_begin(dev); | ||||
| 	while (blkid_tag_next(iter, &type, &value) == 0) { | ||||
| 		printf("\tTag %s has value %s\n", type, value); | ||||
| 	} | ||||
| 	blkid_tag_iterate_end(iter); | ||||
|  | ||||
| 	blkid_put_cache(cache); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,220 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * chattr.c		- Change file attributes on an ext2 file system | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                           Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                           Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 93/10/30	- Creation | ||||
|  * 93/11/13	- Replace stat() calls by lstat() to avoid loops | ||||
|  * 94/02/27	- Integrated in Ted's distribution | ||||
|  * 98/12/29	- Ignore symlinks when working recursively (G M Sipe) | ||||
|  * 98/12/29	- Display version info only when -V specified (G M Sipe) | ||||
|  */ | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/stat.h> | ||||
| #include "ext2fs/ext2_fs.h" | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| # define EXT2FS_ATTR(x) __attribute__(x) | ||||
| #else | ||||
| # define EXT2FS_ATTR(x) | ||||
| #endif | ||||
|  | ||||
| #include "e2fsbb.h" | ||||
| #include "e2p/e2p.h" | ||||
|  | ||||
| #define OPT_ADD 1 | ||||
| #define OPT_REM 2 | ||||
| #define OPT_SET 4 | ||||
| #define OPT_SET_VER 8 | ||||
| static int flags; | ||||
| static int recursive; | ||||
|  | ||||
| static unsigned long version; | ||||
|  | ||||
| static unsigned long af; | ||||
| static unsigned long rf; | ||||
| static unsigned long sf; | ||||
|  | ||||
| struct flags_char { | ||||
| 	unsigned long flag; | ||||
| 	char optchar; | ||||
| }; | ||||
|  | ||||
| static const struct flags_char flags_array[] = { | ||||
| 	{ EXT2_NOATIME_FL,      'A' }, | ||||
| 	{ EXT2_SYNC_FL,         'S' }, | ||||
| 	{ EXT2_DIRSYNC_FL,      'D' }, | ||||
| 	{ EXT2_APPEND_FL,       'a' }, | ||||
| 	{ EXT2_COMPR_FL,        'c' }, | ||||
| 	{ EXT2_NODUMP_FL,       'd' }, | ||||
| 	{ EXT2_IMMUTABLE_FL,    'i' }, | ||||
| 	{ EXT3_JOURNAL_DATA_FL, 'j' }, | ||||
| 	{ EXT2_SECRM_FL,        's' }, | ||||
| 	{ EXT2_UNRM_FL,         'u' }, | ||||
| 	{ EXT2_NOTAIL_FL,       't' }, | ||||
| 	{ EXT2_TOPDIR_FL,       'T' }, | ||||
| 	{ 0, 0 } | ||||
| }; | ||||
|  | ||||
| static unsigned long get_flag(char c) | ||||
| { | ||||
| 	const struct flags_char *fp; | ||||
| 	for (fp = flags_array; fp->flag; fp++) | ||||
| 		if (fp->optchar == c) | ||||
| 			return fp->flag; | ||||
| 	bb_show_usage(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int decode_arg(char *arg) | ||||
| { | ||||
| 	unsigned long *fl; | ||||
| 	char opt = *arg++; | ||||
|  | ||||
| 	if (opt == '-') { | ||||
| 		flags |= OPT_REM; | ||||
| 		fl = &rf; | ||||
| 	} else if (opt == '+') { | ||||
| 		flags |= OPT_ADD; | ||||
| 		fl = ⁡ | ||||
| 	} else if (opt == '=') { | ||||
| 		flags |= OPT_SET; | ||||
| 		fl = &sf; | ||||
| 	} else | ||||
| 		return EOF; | ||||
|  | ||||
| 	for (; *arg; ++arg) | ||||
| 		(*fl) |= get_flag(*arg); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int chattr_dir_proc(const char *, struct dirent *, void *); | ||||
|  | ||||
| static void change_attributes(const char * name) | ||||
| { | ||||
| 	unsigned long fsflags; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if (lstat(name, &st) == -1) { | ||||
| 		bb_error_msg("stat %s failed", name); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (S_ISLNK(st.st_mode) && recursive) | ||||
| 		return; | ||||
|  | ||||
| 	/* Don't try to open device files, fifos etc.  We probably | ||||
| 	 * ought to display an error if the file was explicitly given | ||||
| 	 * on the command line (whether or not recursive was | ||||
| 	 * requested).  */ | ||||
| 	if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode)) | ||||
| 		return; | ||||
|  | ||||
| 	if (flags & OPT_SET_VER) | ||||
| 		if (fsetversion(name, version) == -1) | ||||
| 			bb_error_msg("setting version on %s", name); | ||||
|  | ||||
| 	if (flags & OPT_SET) { | ||||
| 		fsflags = sf; | ||||
| 	} else { | ||||
| 		if (fgetflags(name, &fsflags) == -1) { | ||||
| 			bb_error_msg("reading flags on %s", name); | ||||
| 			goto skip_setflags; | ||||
| 		} | ||||
| 		if (flags & OPT_REM) | ||||
| 			fsflags &= ~rf; | ||||
| 		if (flags & OPT_ADD) | ||||
| 			fsflags |= af; | ||||
| 		if (!S_ISDIR(st.st_mode)) | ||||
| 			fsflags &= ~EXT2_DIRSYNC_FL; | ||||
| 	} | ||||
| 	if (fsetflags(name, fsflags) == -1) | ||||
| 		bb_error_msg("setting flags on %s", name); | ||||
|  | ||||
| skip_setflags: | ||||
| 	if (S_ISDIR(st.st_mode) && recursive) | ||||
| 		iterate_on_dir(name, chattr_dir_proc, NULL); | ||||
| } | ||||
|  | ||||
| static int chattr_dir_proc(const char *dir_name, struct dirent *de, | ||||
| 			   void *private EXT2FS_ATTR((unused))) | ||||
| { | ||||
| 	/*if (strcmp(de->d_name, ".") || strcmp(de->d_name, "..")) {*/ | ||||
| 	if (de->d_name[0] == '.' | ||||
| 	 && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2])) | ||||
| 	) { | ||||
| 		char *path = concat_subpath_file(dir_name, de->d_name); | ||||
| 		if (path) { | ||||
| 			change_attributes(path); | ||||
| 			free(path); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||||
| int chattr_main(int argc, char **argv) | ||||
| { | ||||
| 	int i; | ||||
| 	char *arg; | ||||
|  | ||||
| 	/* parse the args */ | ||||
| 	for (i = 1; i < argc; ++i) { | ||||
| 		arg = argv[i]; | ||||
|  | ||||
| 		/* take care of -R and -v <version> */ | ||||
| 		if (arg[0] == '-') { | ||||
| 			if (arg[1] == 'R' && arg[2] == '\0') { | ||||
| 				recursive = 1; | ||||
| 				continue; | ||||
| 			} else if (arg[1] == 'v' && arg[2] == '\0') { | ||||
| 				char *tmp; | ||||
| 				++i; | ||||
| 				if (i >= argc) | ||||
| 					bb_show_usage(); | ||||
| 				version = strtol(argv[i], &tmp, 0); | ||||
| 				if (*tmp) | ||||
| 					bb_error_msg_and_die("bad version '%s'", arg); | ||||
| 				flags |= OPT_SET_VER; | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (decode_arg(arg) == EOF) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	/* run sanity checks on all the arguments given us */ | ||||
| 	if (i >= argc) | ||||
| 		bb_show_usage(); | ||||
| 	if ((flags & OPT_SET) && ((flags & OPT_ADD) || (flags & OPT_REM))) | ||||
| 		bb_error_msg_and_die("= is incompatible with - and +"); | ||||
| 	if ((rf & af) != 0) | ||||
| 		bb_error_msg_and_die("Can't set and unset a flag"); | ||||
| 	if (!flags) | ||||
| 		bb_error_msg_and_die("Must use '-v', =, - or +"); | ||||
|  | ||||
| 	/* now run chattr on all the files passed to us */ | ||||
| 	while (i < argc) | ||||
| 		change_attributes(argv[i++]); | ||||
|  | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * File: e2fsbb.h | ||||
|  * | ||||
|  * Redefine a bunch of e2fsprogs stuff to use busybox routines | ||||
|  * instead.  This makes upgrade between e2fsprogs versions easy. | ||||
|  */ | ||||
|  | ||||
| #ifndef E2FSBB_H | ||||
| #define E2FSBB_H 1 | ||||
|  | ||||
| #include "libbb.h" | ||||
|  | ||||
| /* version we've last synced against */ | ||||
| #define E2FSPROGS_VERSION "1.38" | ||||
| #define E2FSPROGS_DATE "30-Jun-2005" | ||||
|  | ||||
| typedef long errcode_t; | ||||
| #define ERRCODE_RANGE 8 | ||||
| #define error_message(code) strerror((int) (code & ((1<<ERRCODE_RANGE)-1))) | ||||
|  | ||||
| /* header defines */ | ||||
| #define ENABLE_HTREE 1 | ||||
| #define HAVE_ERRNO_H 1 | ||||
| #define HAVE_EXT2_IOCTLS 1 | ||||
| #define HAVE_LINUX_FD_H 1 | ||||
| #define HAVE_MNTENT_H 1 | ||||
| #define HAVE_NETINET_IN_H 1 | ||||
| #define HAVE_NET_IF_H 1 | ||||
| #define HAVE_SYS_IOCTL_H 1 | ||||
| #define HAVE_SYS_MOUNT_H 1 | ||||
| #define HAVE_SYS_QUEUE_H 1 | ||||
| #define HAVE_SYS_STAT_H 1 | ||||
| #define HAVE_SYS_TYPES_H 1 | ||||
| #define HAVE_UNISTD_H 1 | ||||
|  | ||||
| /* Endianness */ | ||||
| #if BB_BIG_ENDIAN | ||||
| #define ENABLE_SWAPFS 1 | ||||
| #define WORDS_BIGENDIAN 1 | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,638 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| #include <sys/types.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <fcntl.h> | ||||
| #include <ctype.h> | ||||
| #include <setjmp.h> | ||||
| #include <errno.h> | ||||
| #include <getopt.h> | ||||
| #include <limits.h> | ||||
| #include <stddef.h> | ||||
| #include <assert.h> | ||||
| #include <signal.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <termios.h> | ||||
| #include <mntent.h> | ||||
| #include <dirent.h> | ||||
| #include "ext2fs/kernel-list.h" | ||||
| #include <sys/types.h> | ||||
| #include <linux/types.h> | ||||
|  | ||||
| /* | ||||
|  * Now pull in the real linux/jfs.h definitions. | ||||
|  */ | ||||
| #include "ext2fs/kernel-jbd.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| #include "fsck.h" | ||||
|  | ||||
| #include "ext2fs/ext2_fs.h" | ||||
| #include "blkid/blkid.h" | ||||
| #include "ext2fs/ext2_ext_attr.h" | ||||
| #include "uuid/uuid.h" | ||||
| #include "libbb.h" | ||||
|  | ||||
| #ifdef HAVE_CONIO_H | ||||
| #undef HAVE_TERMIOS_H | ||||
| #include <conio.h> | ||||
| #define read_a_char()   getch() | ||||
| #else | ||||
| #ifdef HAVE_TERMIOS_H | ||||
| #include <termios.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * The last ext2fs revision level that this version of e2fsck is able to | ||||
|  * support | ||||
|  */ | ||||
| #define E2FSCK_CURRENT_REV      1 | ||||
|  | ||||
| /* Used by the region allocation code */ | ||||
| typedef __u32 region_addr_t; | ||||
| typedef struct region_struct *region_t; | ||||
|  | ||||
| struct dx_dirblock_info { | ||||
| 	int             type; | ||||
| 	blk_t           phys; | ||||
| 	int             flags; | ||||
| 	blk_t           parent; | ||||
| 	ext2_dirhash_t  min_hash; | ||||
| 	ext2_dirhash_t  max_hash; | ||||
| 	ext2_dirhash_t  node_min_hash; | ||||
| 	ext2_dirhash_t  node_max_hash; | ||||
| }; | ||||
|  | ||||
| /* | ||||
| These defines are used in the type field of dx_dirblock_info | ||||
| */ | ||||
|  | ||||
| #define DX_DIRBLOCK_ROOT        1 | ||||
| #define DX_DIRBLOCK_LEAF        2 | ||||
| #define DX_DIRBLOCK_NODE        3 | ||||
|  | ||||
|  | ||||
| /* | ||||
| The following defines are used in the 'flags' field of a dx_dirblock_info | ||||
| */ | ||||
| #define DX_FLAG_REFERENCED      1 | ||||
| #define DX_FLAG_DUP_REF         2 | ||||
| #define DX_FLAG_FIRST           4 | ||||
| #define DX_FLAG_LAST            8 | ||||
|  | ||||
| /* | ||||
|  * E2fsck options | ||||
|  */ | ||||
| #define E2F_OPT_READONLY        0x0001 | ||||
| #define E2F_OPT_PREEN           0x0002 | ||||
| #define E2F_OPT_YES             0x0004 | ||||
| #define E2F_OPT_NO              0x0008 | ||||
| #define E2F_OPT_TIME            0x0010 | ||||
| #define E2F_OPT_CHECKBLOCKS     0x0040 | ||||
| #define E2F_OPT_DEBUG           0x0080 | ||||
| #define E2F_OPT_FORCE           0x0100 | ||||
| #define E2F_OPT_WRITECHECK      0x0200 | ||||
| #define E2F_OPT_COMPRESS_DIRS   0x0400 | ||||
|  | ||||
| /* | ||||
|  * E2fsck flags | ||||
|  */ | ||||
| #define E2F_FLAG_ABORT          0x0001 /* Abort signaled */ | ||||
| #define E2F_FLAG_CANCEL         0x0002 /* Cancel signaled */ | ||||
| #define E2F_FLAG_SIGNAL_MASK    0x0003 | ||||
| #define E2F_FLAG_RESTART        0x0004 /* Restart signaled */ | ||||
|  | ||||
| #define E2F_FLAG_SETJMP_OK      0x0010 /* Setjmp valid for abort */ | ||||
|  | ||||
| #define E2F_FLAG_PROG_BAR       0x0020 /* Progress bar on screen */ | ||||
| #define E2F_FLAG_PROG_SUPPRESS  0x0040 /* Progress suspended */ | ||||
| #define E2F_FLAG_JOURNAL_INODE  0x0080 /* Create a new ext3 journal inode */ | ||||
| #define E2F_FLAG_SB_SPECIFIED   0x0100 /* The superblock was explicitly | ||||
| 					* specified by the user */ | ||||
| #define E2F_FLAG_RESTARTED      0x0200 /* E2fsck has been restarted */ | ||||
| #define E2F_FLAG_RESIZE_INODE   0x0400 /* Request to recreate resize inode */ | ||||
|  | ||||
|  | ||||
| /*Don't know where these come from*/ | ||||
| #define READ 0 | ||||
| #define WRITE 1 | ||||
| #define cpu_to_be32(n) htonl(n) | ||||
| #define be32_to_cpu(n) ntohl(n) | ||||
|  | ||||
| /* | ||||
|  * We define a set of "latch groups"; these are problems which are | ||||
|  * handled as a set.  The user answers once for a particular latch | ||||
|  * group. | ||||
|  */ | ||||
| #define PR_LATCH_MASK         0x0ff0 /* Latch mask */ | ||||
| #define PR_LATCH_BLOCK        0x0010 /* Latch for illegal blocks (pass 1) */ | ||||
| #define PR_LATCH_BBLOCK       0x0020 /* Latch for bad block inode blocks (pass 1) */ | ||||
| #define PR_LATCH_IBITMAP      0x0030 /* Latch for pass 5 inode bitmap proc. */ | ||||
| #define PR_LATCH_BBITMAP      0x0040 /* Latch for pass 5 inode bitmap proc. */ | ||||
| #define PR_LATCH_RELOC        0x0050 /* Latch for superblock relocate hint */ | ||||
| #define PR_LATCH_DBLOCK       0x0060 /* Latch for pass 1b dup block headers */ | ||||
| #define PR_LATCH_LOW_DTIME    0x0070 /* Latch for pass1 orphaned list refugees */ | ||||
| #define PR_LATCH_TOOBIG       0x0080 /* Latch for file to big errors */ | ||||
| #define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */ | ||||
|  | ||||
| #define PR_LATCH(x)     ((((x) & PR_LATCH_MASK) >> 4) - 1) | ||||
|  | ||||
| /* | ||||
|  * Latch group descriptor flags | ||||
|  */ | ||||
| #define PRL_YES         0x0001  /* Answer yes */ | ||||
| #define PRL_NO          0x0002  /* Answer no */ | ||||
| #define PRL_LATCHED     0x0004  /* The latch group is latched */ | ||||
| #define PRL_SUPPRESS    0x0008  /* Suppress all latch group questions */ | ||||
|  | ||||
| #define PRL_VARIABLE    0x000f  /* All the flags that need to be reset */ | ||||
|  | ||||
| /* | ||||
|  * Pre-Pass 1 errors | ||||
|  */ | ||||
|  | ||||
| #define PR_0_BB_NOT_GROUP       0x000001  /* Block bitmap not in group */ | ||||
| #define PR_0_IB_NOT_GROUP       0x000002  /* Inode bitmap not in group */ | ||||
| #define PR_0_ITABLE_NOT_GROUP   0x000003  /* Inode table not in group */ | ||||
| #define PR_0_SB_CORRUPT         0x000004  /* Superblock corrupt */ | ||||
| #define PR_0_FS_SIZE_WRONG      0x000005  /* Filesystem size is wrong */ | ||||
| #define PR_0_NO_FRAGMENTS       0x000006  /* Fragments not supported */ | ||||
| #define PR_0_BLOCKS_PER_GROUP   0x000007  /* Bad blocks_per_group */ | ||||
| #define PR_0_FIRST_DATA_BLOCK   0x000008  /* Bad first_data_block */ | ||||
| #define PR_0_ADD_UUID           0x000009  /* Adding UUID to filesystem */ | ||||
| #define PR_0_RELOCATE_HINT      0x00000A  /* Relocate hint */ | ||||
| #define PR_0_MISC_CORRUPT_SUPER 0x00000B  /* Miscellaneous superblock corruption */ | ||||
| #define PR_0_GETSIZE_ERROR      0x00000C  /* Error determing physical device size of filesystem */ | ||||
| #define PR_0_INODE_COUNT_WRONG  0x00000D  /* Inode count in the superblock incorrect */ | ||||
| #define PR_0_HURD_CLEAR_FILETYPE 0x00000E /* The Hurd does not support the filetype feature */ | ||||
| #define PR_0_JOURNAL_BAD_INODE  0x00000F  /* The Hurd does not support the filetype feature */ | ||||
| #define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010 /* The external journal has multiple filesystems (which we can't handle yet) */ | ||||
| #define PR_0_CANT_FIND_JOURNAL  0x000011  /* Can't find external journal */ | ||||
| #define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012/* External journal has bad superblock */ | ||||
| #define PR_0_JOURNAL_BAD_UUID   0x000013  /* Superblock has a bad journal UUID */ | ||||
| #define PR_0_JOURNAL_UNSUPP_SUPER 0x000014 /* Journal has an unknown superblock type */ | ||||
| #define PR_0_JOURNAL_BAD_SUPER  0x000015  /* Journal superblock is corrupt */ | ||||
| #define PR_0_JOURNAL_HAS_JOURNAL 0x000016 /* Journal superblock is corrupt */ | ||||
| #define PR_0_JOURNAL_RECOVER_SET 0x000017 /* Superblock has recovery flag set but no journal */ | ||||
| #define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018 /* Journal has data, but recovery flag is clear */ | ||||
| #define PR_0_JOURNAL_RESET_JOURNAL 0x000019 /* Ask if we should clear the journal */ | ||||
| #define PR_0_FS_REV_LEVEL       0x00001A  /* Filesystem revision is 0, but feature flags are set */ | ||||
| #define PR_0_ORPHAN_CLEAR_INODE             0x000020 /* Clearing orphan inode */ | ||||
| #define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM       0x000021 /* Illegal block found in orphaned inode */ | ||||
| #define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK   0x000022 /* Already cleared block found in orphaned inode */ | ||||
| #define PR_0_ORPHAN_ILLEGAL_HEAD_INODE      0x000023 /* Illegal orphan inode in superblock */ | ||||
| #define PR_0_ORPHAN_ILLEGAL_INODE           0x000024 /* Illegal inode in orphaned inode list */ | ||||
| #define PR_0_JOURNAL_UNSUPP_ROCOMPAT        0x000025 /* Journal has unsupported read-only feature - abort */ | ||||
| #define PR_0_JOURNAL_UNSUPP_INCOMPAT        0x000026 /* Journal has unsupported incompatible feature - abort */ | ||||
| #define PR_0_JOURNAL_UNSUPP_VERSION         0x000027 /* Journal has unsupported version number */ | ||||
| #define PR_0_MOVE_JOURNAL                   0x000028 /* Moving journal to hidden file */ | ||||
| #define PR_0_ERR_MOVE_JOURNAL               0x000029 /* Error moving journal */ | ||||
| #define PR_0_CLEAR_V2_JOURNAL               0x00002A /* Clearing V2 journal superblock */ | ||||
| #define PR_0_JOURNAL_RUN                    0x00002B /* Run journal anyway */ | ||||
| #define PR_0_JOURNAL_RUN_DEFAULT            0x00002C /* Run journal anyway by default */ | ||||
| #define PR_0_BACKUP_JNL                     0x00002D /* Backup journal inode blocks */ | ||||
| #define PR_0_NONZERO_RESERVED_GDT_BLOCKS    0x00002E /* Reserved blocks w/o resize_inode */ | ||||
| #define PR_0_CLEAR_RESIZE_INODE             0x00002F /* Resize_inode not enabled, but resize inode is non-zero */ | ||||
| #define PR_0_RESIZE_INODE_INVALID           0x000030 /* Resize inode invalid */ | ||||
|  | ||||
| /* | ||||
|  * Pass 1 errors | ||||
|  */ | ||||
|  | ||||
| #define PR_1_PASS_HEADER              0x010000  /* Pass 1: Checking inodes, blocks, and sizes */ | ||||
| #define PR_1_ROOT_NO_DIR              0x010001  /* Root directory is not an inode */ | ||||
| #define PR_1_ROOT_DTIME               0x010002  /* Root directory has dtime set */ | ||||
| #define PR_1_RESERVED_BAD_MODE        0x010003  /* Reserved inode has bad mode */ | ||||
| #define PR_1_ZERO_DTIME               0x010004  /* Deleted inode has zero dtime */ | ||||
| #define PR_1_SET_DTIME                0x010005  /* Inode in use, but dtime set */ | ||||
| #define PR_1_ZERO_LENGTH_DIR          0x010006  /* Zero-length directory */ | ||||
| #define PR_1_BB_CONFLICT              0x010007  /* Block bitmap conflicts with some other fs block */ | ||||
| #define PR_1_IB_CONFLICT              0x010008  /* Inode bitmap conflicts with some other fs block */ | ||||
| #define PR_1_ITABLE_CONFLICT          0x010009  /* Inode table conflicts with some other fs block */ | ||||
| #define PR_1_BB_BAD_BLOCK             0x01000A  /* Block bitmap is on a bad block */ | ||||
| #define PR_1_IB_BAD_BLOCK             0x01000B  /* Inode bitmap is on a bad block */ | ||||
| #define PR_1_BAD_I_SIZE               0x01000C  /* Inode has incorrect i_size */ | ||||
| #define PR_1_BAD_I_BLOCKS             0x01000D  /* Inode has incorrect i_blocks */ | ||||
| #define PR_1_ILLEGAL_BLOCK_NUM        0x01000E  /* Illegal block number in inode */ | ||||
| #define PR_1_BLOCK_OVERLAPS_METADATA  0x01000F  /* Block number overlaps fs metadata */ | ||||
| #define PR_1_INODE_BLOCK_LATCH        0x010010  /* Inode has illegal blocks (latch question) */ | ||||
| #define PR_1_TOO_MANY_BAD_BLOCKS      0x010011  /* Too many bad blocks in inode */ | ||||
| #define PR_1_BB_ILLEGAL_BLOCK_NUM     0x010012  /* Illegal block number in bad block inode */ | ||||
| #define PR_1_INODE_BBLOCK_LATCH       0x010013  /* Bad block inode has illegal blocks (latch question) */ | ||||
| #define PR_1_DUP_BLOCKS_PREENSTOP     0x010014  /* Duplicate or bad blocks in use! */ | ||||
| #define PR_1_BBINODE_BAD_METABLOCK    0x010015  /* Bad block used as bad block indirect block */ | ||||
| #define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016 /* Inconsistency can't be fixed prompt */ | ||||
| #define PR_1_BAD_PRIMARY_BLOCK        0x010017  /* Bad primary block */ | ||||
| #define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018  /* Bad primary block prompt */ | ||||
| #define PR_1_BAD_PRIMARY_SUPERBLOCK   0x010019  /* Bad primary superblock */ | ||||
| #define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A /* Bad primary block group descriptors */ | ||||
| #define PR_1_BAD_SUPERBLOCK           0x01001B  /* Bad superblock in group */ | ||||
| #define PR_1_BAD_GROUP_DESCRIPTORS    0x01001C  /* Bad block group descriptors in group */ | ||||
| #define PR_1_PROGERR_CLAIMED_BLOCK    0x01001D  /* Block claimed for no reason */ | ||||
| #define PR_1_RELOC_BLOCK_ALLOCATE     0x01001E  /* Error allocating blocks for relocating metadata */ | ||||
| #define PR_1_RELOC_MEMORY_ALLOCATE    0x01001F  /* Error allocating block buffer during relocation process */ | ||||
| #define PR_1_RELOC_FROM_TO            0x010020  /* Relocating metadata group information from X to Y */ | ||||
| #define PR_1_RELOC_TO                 0x010021  /* Relocating metatdata group information to X */ | ||||
| #define PR_1_RELOC_READ_ERR           0x010022  /* Block read error during relocation process */ | ||||
| #define PR_1_RELOC_WRITE_ERR          0x010023  /* Block write error during relocation process */ | ||||
| #define PR_1_ALLOCATE_IBITMAP_ERROR   0x010024  /* Error allocating inode bitmap */ | ||||
| #define PR_1_ALLOCATE_BBITMAP_ERROR   0x010025  /* Error allocating block bitmap */ | ||||
| #define PR_1_ALLOCATE_ICOUNT          0x010026  /* Error allocating icount structure */ | ||||
| #define PR_1_ALLOCATE_DBCOUNT         0x010027  /* Error allocating dbcount */ | ||||
| #define PR_1_ISCAN_ERROR              0x010028  /* Error while scanning inodes */ | ||||
| #define PR_1_BLOCK_ITERATE            0x010029  /* Error while iterating over blocks */ | ||||
| #define PR_1_ICOUNT_STORE             0x01002A  /* Error while storing inode count information */ | ||||
| #define PR_1_ADD_DBLOCK               0x01002B  /* Error while storing directory block information */ | ||||
| #define PR_1_READ_INODE               0x01002C  /* Error while reading inode (for clearing) */ | ||||
| #define PR_1_SUPPRESS_MESSAGES        0x01002D  /* Suppress messages prompt */ | ||||
| #define PR_1_SET_IMAGIC    0x01002F  /* Imagic flag set on an inode when filesystem doesn't support it */ | ||||
| #define PR_1_SET_IMMUTABLE            0x010030  /* Immutable flag set on a device or socket inode */ | ||||
| #define PR_1_COMPR_SET                0x010031  /* Compression flag set on a non-compressed filesystem */ | ||||
| #define PR_1_SET_NONZSIZE             0x010032  /* Non-zero size on device, fifo or socket inode */ | ||||
| #define PR_1_FS_REV_LEVEL             0x010033  /* Filesystem revision is 0, but feature flags are set */ | ||||
| #define PR_1_JOURNAL_INODE_NOT_CLEAR  0x010034  /* Journal inode not in use, needs clearing */ | ||||
| #define PR_1_JOURNAL_BAD_MODE         0x010035  /* Journal inode has wrong mode */ | ||||
| #define PR_1_LOW_DTIME                0x010036  /* Inode that was part of orphan linked list */ | ||||
| #define PR_1_ORPHAN_LIST_REFUGEES     0x010037  /* Latch question which asks how to deal with low dtime inodes */ | ||||
| #define PR_1_ALLOCATE_REFCOUNT        0x010038  /* Error allocating refcount structure */ | ||||
| #define PR_1_READ_EA_BLOCK            0x010039  /* Error reading Extended Attribute block */ | ||||
| #define PR_1_BAD_EA_BLOCK             0x01003A  /* Invalid Extended Attribute block */ | ||||
| #define PR_1_EXTATTR_READ_ABORT   0x01003B  /* Error reading Extended Attribute block while fixing refcount -- abort */ | ||||
| #define PR_1_EXTATTR_REFCOUNT         0x01003C  /* Extended attribute reference count incorrect */ | ||||
| #define PR_1_EXTATTR_WRITE            0x01003D  /* Error writing Extended Attribute block while fixing refcount */ | ||||
| #define PR_1_EA_MULTI_BLOCK           0x01003E  /* Multiple EA blocks not supported */ | ||||
| #define PR_1_EA_ALLOC_REGION          0x01003F  /* Error allocating EA region allocation structure */ | ||||
| #define PR_1_EA_ALLOC_COLLISION       0x010040  /* Error EA allocation collision */ | ||||
| #define PR_1_EA_BAD_NAME              0x010041  /* Bad extended attribute name */ | ||||
| #define PR_1_EA_BAD_VALUE             0x010042  /* Bad extended attribute value */ | ||||
| #define PR_1_INODE_TOOBIG             0x010043  /* Inode too big (latch question) */ | ||||
| #define PR_1_TOOBIG_DIR               0x010044  /* Directory too big */ | ||||
| #define PR_1_TOOBIG_REG               0x010045  /* Regular file too big */ | ||||
| #define PR_1_TOOBIG_SYMLINK           0x010046  /* Symlink too big */ | ||||
| #define PR_1_HTREE_SET                0x010047  /* INDEX_FL flag set on a non-HTREE filesystem */ | ||||
| #define PR_1_HTREE_NODIR              0x010048  /* INDEX_FL flag set on a non-directory */ | ||||
| #define PR_1_HTREE_BADROOT            0x010049  /* Invalid root node in HTREE directory */ | ||||
| #define PR_1_HTREE_HASHV              0x01004A  /* Unsupported hash version in HTREE directory */ | ||||
| #define PR_1_HTREE_INCOMPAT           0x01004B  /* Incompatible flag in HTREE root node */ | ||||
| #define PR_1_HTREE_DEPTH              0x01004C  /* HTREE too deep */ | ||||
| #define PR_1_BB_FS_BLOCK   0x01004D  /* Bad block has indirect block that conflicts with filesystem block */ | ||||
| #define PR_1_RESIZE_INODE_CREATE      0x01004E  /* Resize inode failed */ | ||||
| #define PR_1_EXTRA_ISIZE              0x01004F  /* inode->i_size is too long */ | ||||
| #define PR_1_ATTR_NAME_LEN            0x010050  /* attribute name is too long */ | ||||
| #define PR_1_ATTR_VALUE_OFFSET        0x010051  /* wrong EA value offset */ | ||||
| #define PR_1_ATTR_VALUE_BLOCK         0x010052  /* wrong EA blocknumber */ | ||||
| #define PR_1_ATTR_VALUE_SIZE          0x010053  /* wrong EA value size */ | ||||
| #define PR_1_ATTR_HASH                0x010054  /* wrong EA hash value */ | ||||
|  | ||||
| /* | ||||
|  * Pass 1b errors | ||||
|  */ | ||||
|  | ||||
| #define PR_1B_PASS_HEADER       0x011000  /* Pass 1B: Rescan for duplicate/bad blocks */ | ||||
| #define PR_1B_DUP_BLOCK_HEADER  0x011001  /* Duplicate/bad block(s) header */ | ||||
| #define PR_1B_DUP_BLOCK         0x011002  /* Duplicate/bad block(s) in inode */ | ||||
| #define PR_1B_DUP_BLOCK_END     0x011003  /* Duplicate/bad block(s) end */ | ||||
| #define PR_1B_ISCAN_ERROR       0x011004  /* Error while scanning inodes */ | ||||
| #define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005  /* Error allocating inode bitmap */ | ||||
| #define PR_1B_BLOCK_ITERATE     0x0110006  /* Error while iterating over blocks */ | ||||
| #define PR_1B_ADJ_EA_REFCOUNT   0x0110007  /* Error adjusting EA refcount */ | ||||
| #define PR_1C_PASS_HEADER       0x012000  /* Pass 1C: Scan directories for inodes with dup blocks. */ | ||||
| #define PR_1D_PASS_HEADER       0x013000  /* Pass 1D: Reconciling duplicate blocks */ | ||||
| #define PR_1D_DUP_FILE          0x013001  /* File has duplicate blocks */ | ||||
| #define PR_1D_DUP_FILE_LIST     0x013002  /* List of files sharing duplicate blocks */ | ||||
| #define PR_1D_SHARE_METADATA    0x013003  /* File sharing blocks with filesystem metadata  */ | ||||
| #define PR_1D_NUM_DUP_INODES    0x013004  /* Report of how many duplicate/bad inodes */ | ||||
| #define PR_1D_DUP_BLOCKS_DEALT  0x013005  /* Duplicated blocks already reassigned or cloned. */ | ||||
| #define PR_1D_CLONE_QUESTION    0x013006  /* Clone duplicate/bad blocks? */ | ||||
| #define PR_1D_DELETE_QUESTION   0x013007  /* Delete file? */ | ||||
| #define PR_1D_CLONE_ERROR       0x013008  /* Couldn't clone file (error) */ | ||||
|  | ||||
| /* | ||||
|  * Pass 2 errors | ||||
|  */ | ||||
|  | ||||
| #define PR_2_PASS_HEADER        0x020000  /* Pass 2: Checking directory structure */ | ||||
| #define PR_2_BAD_INODE_DOT      0x020001  /* Bad inode number for '.' */ | ||||
| #define PR_2_BAD_INO            0x020002  /* Directory entry has bad inode number */ | ||||
| #define PR_2_UNUSED_INODE       0x020003  /* Directory entry has deleted or unused inode */ | ||||
| #define PR_2_LINK_DOT           0x020004  /* Directry entry is link to '.' */ | ||||
| #define PR_2_BB_INODE           0x020005  /* Directory entry points to inode now located in a bad block */ | ||||
| #define PR_2_LINK_DIR           0x020006  /* Directory entry contains a link to a directory */ | ||||
| #define PR_2_LINK_ROOT          0x020007  /* Directory entry contains a link to the root directry */ | ||||
| #define PR_2_BAD_NAME           0x020008  /* Directory entry has illegal characters in its name */ | ||||
| #define PR_2_MISSING_DOT        0x020009  /* Missing '.' in directory inode */ | ||||
| #define PR_2_MISSING_DOT_DOT    0x02000A  /* Missing '..' in directory inode */ | ||||
| #define PR_2_1ST_NOT_DOT        0x02000B  /* First entry in directory inode doesn't contain '.' */ | ||||
| #define PR_2_2ND_NOT_DOT_DOT    0x02000C  /* Second entry in directory inode doesn't contain '..' */ | ||||
| #define PR_2_FADDR_ZERO         0x02000D  /* i_faddr should be zero */ | ||||
| #define PR_2_FILE_ACL_ZERO      0x02000E  /* i_file_acl should be zero */ | ||||
| #define PR_2_DIR_ACL_ZERO       0x02000F  /* i_dir_acl should be zero */ | ||||
| #define PR_2_FRAG_ZERO          0x020010  /* i_frag should be zero */ | ||||
| #define PR_2_FSIZE_ZERO         0x020011  /* i_fsize should be zero */ | ||||
| #define PR_2_BAD_MODE           0x020012  /* inode has bad mode */ | ||||
| #define PR_2_DIR_CORRUPTED      0x020013  /* directory corrupted */ | ||||
| #define PR_2_FILENAME_LONG      0x020014  /* filename too long */ | ||||
| #define PR_2_DIRECTORY_HOLE     0x020015  /* Directory inode has a missing block (hole) */ | ||||
| #define PR_2_DOT_NULL_TERM      0x020016  /* '.' is not NULL terminated */ | ||||
| #define PR_2_DOT_DOT_NULL_TERM  0x020017  /* '..' is not NULL terminated */ | ||||
| #define PR_2_BAD_CHAR_DEV       0x020018  /* Illegal character device in inode */ | ||||
| #define PR_2_BAD_BLOCK_DEV      0x020019  /* Illegal block device in inode */ | ||||
| #define PR_2_DUP_DOT            0x02001A  /* Duplicate '.' entry */ | ||||
| #define PR_2_DUP_DOT_DOT        0x02001B  /* Duplicate '..' entry */ | ||||
| #define PR_2_NO_DIRINFO         0x02001C  /* Internal error: couldn't find dir_info */ | ||||
| #define PR_2_FINAL_RECLEN       0x02001D  /* Final rec_len is wrong */ | ||||
| #define PR_2_ALLOCATE_ICOUNT    0x02001E  /* Error allocating icount structure */ | ||||
| #define PR_2_DBLIST_ITERATE     0x02001F  /* Error iterating over directory blocks */ | ||||
| #define PR_2_READ_DIRBLOCK      0x020020  /* Error reading directory block */ | ||||
| #define PR_2_WRITE_DIRBLOCK     0x020021  /* Error writing directory block */ | ||||
| #define PR_2_ALLOC_DIRBOCK      0x020022  /* Error allocating new directory block */ | ||||
| #define PR_2_DEALLOC_INODE      0x020023  /* Error deallocating inode */ | ||||
| #define PR_2_SPLIT_DOT          0x020024  /* Directory entry for '.' is big.  Split? */ | ||||
| #define PR_2_BAD_FIFO           0x020025  /* Illegal FIFO */ | ||||
| #define PR_2_BAD_SOCKET         0x020026  /* Illegal socket */ | ||||
| #define PR_2_SET_FILETYPE       0x020027  /* Directory filetype not set */ | ||||
| #define PR_2_BAD_FILETYPE       0x020028  /* Directory filetype incorrect */ | ||||
| #define PR_2_CLEAR_FILETYPE     0x020029  /* Directory filetype set when it shouldn't be */ | ||||
| #define PR_2_NULL_NAME          0x020030  /* Directory filename can't be zero-length  */ | ||||
| #define PR_2_INVALID_SYMLINK    0x020031  /* Invalid symlink */ | ||||
| #define PR_2_FILE_ACL_BAD       0x020032  /* i_file_acl (extended attribute) is bad */ | ||||
| #define PR_2_FEATURE_LARGE_FILES 0x020033  /* Filesystem contains large files, but has no such flag in sb */ | ||||
| #define PR_2_HTREE_NOTREF       0x020034  /* Node in HTREE directory not referenced */ | ||||
| #define PR_2_HTREE_DUPREF       0x020035  /* Node in HTREE directory referenced twice */ | ||||
| #define PR_2_HTREE_MIN_HASH     0x020036  /* Node in HTREE directory has bad min hash */ | ||||
| #define PR_2_HTREE_MAX_HASH     0x020037  /* Node in HTREE directory has bad max hash */ | ||||
| #define PR_2_HTREE_CLEAR        0x020038  /* Clear invalid HTREE directory */ | ||||
| #define PR_2_HTREE_BADBLK       0x02003A  /* Bad block in htree interior node */ | ||||
| #define PR_2_ADJ_EA_REFCOUNT    0x02003B  /* Error adjusting EA refcount */ | ||||
| #define PR_2_HTREE_BAD_ROOT     0x02003C  /* Invalid HTREE root node */ | ||||
| #define PR_2_HTREE_BAD_LIMIT    0x02003D  /* Invalid HTREE limit */ | ||||
| #define PR_2_HTREE_BAD_COUNT    0x02003E  /* Invalid HTREE count */ | ||||
| #define PR_2_HTREE_HASH_ORDER   0x02003F  /* HTREE interior node has out-of-order hashes in table */ | ||||
| #define PR_2_HTREE_BAD_DEPTH    0x020040  /* Node in HTREE directory has bad depth */ | ||||
| #define PR_2_DUPLICATE_DIRENT   0x020041  /* Duplicate directory entry found */ | ||||
| #define PR_2_NON_UNIQUE_FILE    0x020042  /* Non-unique filename found */ | ||||
| #define PR_2_REPORT_DUP_DIRENT  0x020043  /* Duplicate directory entry found */ | ||||
|  | ||||
| /* | ||||
|  * Pass 3 errors | ||||
|  */ | ||||
|  | ||||
| #define PR_3_PASS_HEADER            0x030000  /* Pass 3: Checking directory connectivity */ | ||||
| #define PR_3_NO_ROOT_INODE          0x030001  /* Root inode not allocated */ | ||||
| #define PR_3_EXPAND_LF_DIR          0x030002  /* No room in lost+found */ | ||||
| #define PR_3_UNCONNECTED_DIR        0x030003  /* Unconnected directory inode */ | ||||
| #define PR_3_NO_LF_DIR              0x030004  /* /lost+found not found */ | ||||
| #define PR_3_BAD_DOT_DOT            0x030005  /* .. entry is incorrect */ | ||||
| #define PR_3_NO_LPF                 0x030006  /* Bad or non-existent /lost+found.  Cannot reconnect */ | ||||
| #define PR_3_CANT_EXPAND_LPF        0x030007  /* Could not expand /lost+found */ | ||||
| #define PR_3_CANT_RECONNECT         0x030008  /* Could not reconnect inode */ | ||||
| #define PR_3_ERR_FIND_LPF           0x030009  /* Error while trying to find /lost+found */ | ||||
| #define PR_3_ERR_LPF_NEW_BLOCK      0x03000A  /* Error in ext2fs_new_block while creating /lost+found */ | ||||
| #define PR_3_ERR_LPF_NEW_INODE      0x03000B  /* Error in ext2fs_new_inode while creating /lost+found */ | ||||
| #define PR_3_ERR_LPF_NEW_DIR_BLOCK  0x03000C  /* Error in ext2fs_new_dir_block while creating /lost+found */ | ||||
| #define PR_3_ERR_LPF_WRITE_BLOCK    0x03000D  /* Error while writing directory block for /lost+found */ | ||||
| #define PR_3_ADJUST_INODE           0x03000E  /* Error while adjusting inode count */ | ||||
| #define PR_3_FIX_PARENT_ERR         0x03000F  /* Couldn't fix parent directory -- error */ | ||||
| #define PR_3_FIX_PARENT_NOFIND      0x030010  /* Couldn't fix parent directory -- couldn't find it */ | ||||
| #define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011  /* Error allocating inode bitmap */ | ||||
| #define PR_3_CREATE_ROOT_ERROR      0x030012  /* Error creating root directory */ | ||||
| #define PR_3_CREATE_LPF_ERROR       0x030013  /* Error creating lost and found directory */ | ||||
| #define PR_3_ROOT_NOT_DIR_ABORT     0x030014  /* Root inode is not directory; aborting */ | ||||
| #define PR_3_NO_ROOT_INODE_ABORT    0x030015  /* Cannot proceed without a root inode. */ | ||||
| #define PR_3_NO_DIRINFO             0x030016  /* Internal error: couldn't find dir_info */ | ||||
| #define PR_3_LPF_NOTDIR             0x030017  /* Lost+found is not a directory */ | ||||
|  | ||||
| /* | ||||
|  * Pass 3a --- rehashing diretories | ||||
|  */ | ||||
| #define PR_3A_PASS_HEADER         0x031000  /* Pass 3a: Reindexing directories */ | ||||
| #define PR_3A_OPTIMIZE_ITER       0x031001  /* Error iterating over directories */ | ||||
| #define PR_3A_OPTIMIZE_DIR_ERR    0x031002  /* Error rehash directory */ | ||||
| #define PR_3A_OPTIMIZE_DIR_HEADER 0x031003  /* Rehashing dir header */ | ||||
| #define PR_3A_OPTIMIZE_DIR        0x031004  /* Rehashing directory %d */ | ||||
| #define PR_3A_OPTIMIZE_DIR_END    0x031005  /* Rehashing dir end */ | ||||
|  | ||||
| /* | ||||
|  * Pass 4 errors | ||||
|  */ | ||||
|  | ||||
| #define PR_4_PASS_HEADER        0x040000  /* Pass 4: Checking reference counts */ | ||||
| #define PR_4_ZERO_LEN_INODE     0x040001  /* Unattached zero-length inode */ | ||||
| #define PR_4_UNATTACHED_INODE   0x040002  /* Unattached inode */ | ||||
| #define PR_4_BAD_REF_COUNT      0x040003  /* Inode ref count wrong */ | ||||
| #define PR_4_INCONSISTENT_COUNT 0x040004  /* Inconsistent inode count information cached */ | ||||
|  | ||||
| /* | ||||
|  * Pass 5 errors | ||||
|  */ | ||||
|  | ||||
| #define PR_5_PASS_HEADER            0x050000  /* Pass 5: Checking group summary information */ | ||||
| #define PR_5_INODE_BMAP_PADDING     0x050001  /* Padding at end of inode bitmap is not set. */ | ||||
| #define PR_5_BLOCK_BMAP_PADDING     0x050002  /* Padding at end of block bitmap is not set. */ | ||||
| #define PR_5_BLOCK_BITMAP_HEADER    0x050003  /* Block bitmap differences header */ | ||||
| #define PR_5_BLOCK_UNUSED           0x050004  /* Block not used, but marked in bitmap */ | ||||
| #define PR_5_BLOCK_USED             0x050005  /* Block used, but not marked used in bitmap */ | ||||
| #define PR_5_BLOCK_BITMAP_END       0x050006  /* Block bitmap differences end */ | ||||
| #define PR_5_INODE_BITMAP_HEADER    0x050007  /* Inode bitmap differences header */ | ||||
| #define PR_5_INODE_UNUSED           0x050008  /* Inode not used, but marked in bitmap */ | ||||
| #define PR_5_INODE_USED             0x050009  /* Inode used, but not marked used in bitmap */ | ||||
| #define PR_5_INODE_BITMAP_END       0x05000A  /* Inode bitmap differences end */ | ||||
| #define PR_5_FREE_INODE_COUNT_GROUP 0x05000B  /* Free inodes count for group wrong */ | ||||
| #define PR_5_FREE_DIR_COUNT_GROUP   0x05000C  /* Directories count for group wrong */ | ||||
| #define PR_5_FREE_INODE_COUNT       0x05000D  /* Free inodes count wrong */ | ||||
| #define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E  /* Free blocks count for group wrong */ | ||||
| #define PR_5_FREE_BLOCK_COUNT       0x05000F  /* Free blocks count wrong */ | ||||
| #define PR_5_BMAP_ENDPOINTS         0x050010  /* Programming error: bitmap endpoints don't match */ | ||||
| #define PR_5_FUDGE_BITMAP_ERROR     0x050011  /* Internal error: fudging end of bitmap */ | ||||
| #define PR_5_COPY_IBITMAP_ERROR     0x050012  /* Error copying in replacement inode bitmap */ | ||||
| #define PR_5_COPY_BBITMAP_ERROR     0x050013  /* Error copying in replacement block bitmap */ | ||||
| #define PR_5_BLOCK_RANGE_UNUSED     0x050014  /* Block range not used, but marked in bitmap */ | ||||
| #define PR_5_BLOCK_RANGE_USED       0x050015  /* Block range used, but not marked used in bitmap */ | ||||
| #define PR_5_INODE_RANGE_UNUSED     0x050016  /* Inode range not used, but marked in bitmap */ | ||||
| #define PR_5_INODE_RANGE_USED       0x050017  /* Inode rangeused, but not marked used in bitmap */ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * The directory information structure; stores directory information | ||||
|  * collected in earlier passes, to avoid disk i/o in fetching the | ||||
|  * directory information. | ||||
|  */ | ||||
| struct dir_info { | ||||
| 	ext2_ino_t              ino;    /* Inode number */ | ||||
| 	ext2_ino_t              dotdot; /* Parent according to '..' */ | ||||
| 	ext2_ino_t              parent; /* Parent according to treewalk */ | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * The indexed directory information structure; stores information for | ||||
|  * directories which contain a hash tree index. | ||||
|  */ | ||||
| struct dx_dir_info { | ||||
| 	ext2_ino_t              ino;            /* Inode number */ | ||||
| 	int                     numblocks;      /* number of blocks */ | ||||
| 	int                     hashversion; | ||||
| 	short                   depth;          /* depth of tree */ | ||||
| 	struct dx_dirblock_info *dx_block;      /* Array of size numblocks */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Define the extended attribute refcount structure | ||||
|  */ | ||||
| typedef struct ea_refcount *ext2_refcount_t; | ||||
|  | ||||
| struct e2fsck_struct { | ||||
| 	ext2_filsys fs; | ||||
| 	const char *program_name; | ||||
| 	char *filesystem_name; | ||||
| 	char *device_name; | ||||
| 	char *io_options; | ||||
| 	int     flags;          /* E2fsck internal flags */ | ||||
| 	int     options; | ||||
| 	blk_t   use_superblock; /* sb requested by user */ | ||||
| 	blk_t   superblock;     /* sb used to open fs */ | ||||
| 	int     blocksize;      /* blocksize */ | ||||
| 	blk_t   num_blocks;     /* Total number of blocks */ | ||||
| 	int     mount_flags; | ||||
| 	blkid_cache blkid;      /* blkid cache */ | ||||
|  | ||||
| 	jmp_buf abort_loc; | ||||
|  | ||||
| 	unsigned long abort_code; | ||||
|  | ||||
| 	int (*progress)(e2fsck_t ctx, int pass, unsigned long cur, | ||||
| 			unsigned long max); | ||||
|  | ||||
| 	ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */ | ||||
| 	ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */ | ||||
| 	ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */ | ||||
| 	ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */ | ||||
| 	ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/ | ||||
|  | ||||
| 	ext2fs_block_bitmap block_found_map; /* Blocks which are in use */ | ||||
| 	ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */ | ||||
| 	ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */ | ||||
|  | ||||
| 	/* | ||||
| 	 * Inode count arrays | ||||
| 	 */ | ||||
| 	ext2_icount_t   inode_count; | ||||
| 	ext2_icount_t inode_link_info; | ||||
|  | ||||
| 	ext2_refcount_t refcount; | ||||
| 	ext2_refcount_t refcount_extra; | ||||
|  | ||||
| 	/* | ||||
| 	 * Array of flags indicating whether an inode bitmap, block | ||||
| 	 * bitmap, or inode table is invalid | ||||
| 	 */ | ||||
| 	int *invalid_inode_bitmap_flag; | ||||
| 	int *invalid_block_bitmap_flag; | ||||
| 	int *invalid_inode_table_flag; | ||||
| 	int invalid_bitmaps;    /* There are invalid bitmaps/itable */ | ||||
|  | ||||
| 	/* | ||||
| 	 * Block buffer | ||||
| 	 */ | ||||
| 	char *block_buf; | ||||
|  | ||||
| 	/* | ||||
| 	 * For pass1_check_directory and pass1_get_blocks | ||||
| 	 */ | ||||
| 	ext2_ino_t stashed_ino; | ||||
| 	struct ext2_inode *stashed_inode; | ||||
|  | ||||
| 	/* | ||||
| 	 * Location of the lost and found directory | ||||
| 	 */ | ||||
| 	ext2_ino_t lost_and_found; | ||||
| 	int bad_lost_and_found; | ||||
|  | ||||
| 	/* | ||||
| 	 * Directory information | ||||
| 	 */ | ||||
| 	int             dir_info_count; | ||||
| 	int             dir_info_size; | ||||
| 	struct dir_info *dir_info; | ||||
|  | ||||
| 	/* | ||||
| 	 * Indexed directory information | ||||
| 	 */ | ||||
| 	int             dx_dir_info_count; | ||||
| 	int             dx_dir_info_size; | ||||
| 	struct dx_dir_info *dx_dir_info; | ||||
|  | ||||
| 	/* | ||||
| 	 * Directories to hash | ||||
| 	 */ | ||||
| 	ext2_u32_list   dirs_to_hash; | ||||
|  | ||||
| 	/* | ||||
| 	 * Tuning parameters | ||||
| 	 */ | ||||
| 	int process_inode_size; | ||||
| 	int inode_buffer_blocks; | ||||
|  | ||||
| 	/* | ||||
| 	 * ext3 journal support | ||||
| 	 */ | ||||
| 	io_channel      journal_io; | ||||
| 	char    *journal_name; | ||||
|  | ||||
| 	/* | ||||
| 	 * How we display the progress update (for unix) | ||||
| 	 */ | ||||
| 	int progress_fd; | ||||
| 	int progress_pos; | ||||
| 	int progress_last_percent; | ||||
| 	unsigned int progress_last_time; | ||||
| 	int interactive;        /* Are we connected directly to a tty? */ | ||||
| 	char start_meta[2], stop_meta[2]; | ||||
|  | ||||
| 	/* File counts */ | ||||
| 	int fs_directory_count; | ||||
| 	int fs_regular_count; | ||||
| 	int fs_blockdev_count; | ||||
| 	int fs_chardev_count; | ||||
| 	int fs_links_count; | ||||
| 	int fs_symlinks_count; | ||||
| 	int fs_fast_symlinks_count; | ||||
| 	int fs_fifo_count; | ||||
| 	int fs_total_count; | ||||
| 	int fs_sockets_count; | ||||
| 	int fs_ind_count; | ||||
| 	int fs_dind_count; | ||||
| 	int fs_tind_count; | ||||
| 	int fs_fragmented; | ||||
| 	int large_files; | ||||
| 	int fs_ext_attr_inodes; | ||||
| 	int fs_ext_attr_blocks; | ||||
|  | ||||
| 	int ext_attr_ver; | ||||
|  | ||||
| 	/* | ||||
| 	 * For the use of callers of the e2fsck functions; not used by | ||||
| 	 * e2fsck functions themselves. | ||||
| 	 */ | ||||
| 	void *priv_data; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #define tid_gt(x, y)  ((x - y) > 0) | ||||
|  | ||||
| static inline int tid_geq(tid_t x, tid_t y) | ||||
| { | ||||
| 	int difference = (x - y); | ||||
| 	return (difference >= 0); | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| # Makefile for busybox | ||||
| # | ||||
| # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> | ||||
| # | ||||
| # Licensed under GPLv2, see file LICENSE in this source tree. | ||||
|  | ||||
| NEEDED-$(CONFIG_CHATTR) = y | ||||
| NEEDED-$(CONFIG_LSATTR) = y | ||||
| NEEDED-$(CONFIG_MKE2FS) = y | ||||
| NEEDED-$(CONFIG_TUNE2FS) = y | ||||
|  | ||||
| lib-y:= | ||||
|  | ||||
| INSERT | ||||
|  | ||||
| lib-$(NEEDED-y) += fgetsetflags.o fgetsetversion.o pf.o iod.o mntopts.o \ | ||||
|            feature.o ls.o uuid.o pe.o ostype.o ps.o hashstr.o \ | ||||
|            parse_num.o | ||||
| @@ -1,64 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| #include "libbb.h" | ||||
| #include <sys/types.h>		/* Needed by dirent.h on netbsd */ | ||||
| #include <stdio.h> | ||||
| #include <dirent.h> | ||||
|  | ||||
| #include "../ext2fs/ext2_fs.h" | ||||
|  | ||||
| #define E2P_FEATURE_COMPAT	0 | ||||
| #define E2P_FEATURE_INCOMPAT	1 | ||||
| #define E2P_FEATURE_RO_INCOMPAT	2 | ||||
| #ifndef EXT3_FEATURE_INCOMPAT_EXTENTS | ||||
| #define EXT3_FEATURE_INCOMPAT_EXTENTS           0x0040 | ||||
| #endif | ||||
|  | ||||
| /* `options' for print_e2flags() */ | ||||
|  | ||||
| #define PFOPT_LONG  1 /* Must be 1 for compatibility with `int long_format'. */ | ||||
|  | ||||
| /*int fgetversion (const char * name, unsigned long * version);*/ | ||||
| /*int fsetversion (const char * name, unsigned long version);*/ | ||||
| int fgetsetversion(const char * name, unsigned long * get_version, unsigned long set_version); | ||||
| #define fgetversion(name, version) fgetsetversion(name, version, 0) | ||||
| #define fsetversion(name, version) fgetsetversion(name, NULL, version) | ||||
|  | ||||
| /*int fgetflags (const char * name, unsigned long * flags);*/ | ||||
| /*int fsetflags (const char * name, unsigned long flags);*/ | ||||
| int fgetsetflags(const char * name, unsigned long * get_flags, unsigned long set_flags); | ||||
| #define fgetflags(name, flags) fgetsetflags(name, flags, 0) | ||||
| #define fsetflags(name, flags) fgetsetflags(name, NULL, flags) | ||||
|  | ||||
| int getflags (int fd, unsigned long * flags); | ||||
| int getversion (int fd, unsigned long * version); | ||||
| int iterate_on_dir (const char * dir_name, | ||||
| 		    int (*func) (const char *, struct dirent *, void *), | ||||
| 		    void * private); | ||||
| /*void list_super(struct ext2_super_block * s);*/ | ||||
| void list_super2(struct ext2_super_block * s, FILE *f); | ||||
| #define list_super(s) list_super2(s, stdout) | ||||
| void print_fs_errors (FILE *f, unsigned short errors); | ||||
| void print_flags (FILE *f, unsigned long flags, unsigned options); | ||||
| void print_fs_state (FILE *f, unsigned short state); | ||||
| int setflags (int fd, unsigned long flags); | ||||
| int setversion (int fd, unsigned long version); | ||||
|  | ||||
| const char *e2p_feature2string(int compat, unsigned int mask); | ||||
| int e2p_string2feature(char *string, int *compat, unsigned int *mask); | ||||
| int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array); | ||||
|  | ||||
| int e2p_is_null_uuid(void *uu); | ||||
| void e2p_uuid_to_str(void *uu, char *out); | ||||
| const char *e2p_uuid2str(void *uu); | ||||
|  | ||||
| const char *e2p_hash2string(int num); | ||||
| int e2p_string2hash(char *string); | ||||
|  | ||||
| const char *e2p_mntopt2string(unsigned int mask); | ||||
| int e2p_string2mntopt(char *string, unsigned int *mask); | ||||
| int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok); | ||||
|  | ||||
| unsigned long parse_num_blocks(const char *arg, int log_block_size); | ||||
|  | ||||
| char *e2p_os2string(int os_type); | ||||
| int e2p_string2os(char *str); | ||||
| @@ -1,187 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * feature.c --- convert between features and strings | ||||
|  * | ||||
|  * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu> | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| struct feature { | ||||
| 	int		compat; | ||||
| 	unsigned int	mask; | ||||
| 	const char	*string; | ||||
| }; | ||||
|  | ||||
| static const struct feature feature_list[] = { | ||||
| 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC, | ||||
| 			"dir_prealloc" }, | ||||
| 	{	E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL, | ||||
| 			"has_journal" }, | ||||
| 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES, | ||||
| 			"imagic_inodes" }, | ||||
| 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR, | ||||
| 			"ext_attr" }, | ||||
| 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, | ||||
| 			"dir_index" }, | ||||
| 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INO, | ||||
| 			"resize_inode" }, | ||||
| 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, | ||||
| 			"sparse_super" }, | ||||
| 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE, | ||||
| 			"large_file" }, | ||||
| 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, | ||||
| 			"compression" }, | ||||
| 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, | ||||
| 			"filetype" }, | ||||
| 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, | ||||
| 			"needs_recovery" }, | ||||
| 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, | ||||
| 			"journal_dev" }, | ||||
| 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, | ||||
| 			"extents" }, | ||||
| 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, | ||||
| 			"meta_bg" }, | ||||
| 	{	0, 0, 0 }, | ||||
| }; | ||||
|  | ||||
| const char *e2p_feature2string(int compat, unsigned int mask) | ||||
| { | ||||
| 	const struct feature *f; | ||||
| 	static char buf[20]; | ||||
| 	char fchar; | ||||
| 	int fnum; | ||||
|  | ||||
| 	for (f = feature_list; f->string; f++) { | ||||
| 		if ((compat == f->compat) && | ||||
| 		    (mask == f->mask)) | ||||
| 			return f->string; | ||||
| 	} | ||||
| 	switch (compat) { | ||||
| 	case E2P_FEATURE_COMPAT: | ||||
| 		fchar = 'C'; | ||||
| 		break; | ||||
| 	case E2P_FEATURE_INCOMPAT: | ||||
| 		fchar = 'I'; | ||||
| 		break; | ||||
| 	case E2P_FEATURE_RO_INCOMPAT: | ||||
| 		fchar = 'R'; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fchar = '?'; | ||||
| 		break; | ||||
| 	} | ||||
| 	for (fnum = 0; mask >>= 1; fnum++); | ||||
| 		sprintf(buf, "FEATURE_%c%d", fchar, fnum); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) | ||||
| { | ||||
| 	const struct feature *f; | ||||
| 	char *eptr; | ||||
| 	int num; | ||||
|  | ||||
| 	for (f = feature_list; f->string; f++) { | ||||
| 		if (!strcasecmp(string, f->string)) { | ||||
| 			*compat_type = f->compat; | ||||
| 			*mask = f->mask; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	if (strncasecmp(string, "FEATURE_", 8)) | ||||
| 		return 1; | ||||
|  | ||||
| 	switch (string[8]) { | ||||
| 	case 'c': | ||||
| 	case 'C': | ||||
| 		*compat_type = E2P_FEATURE_COMPAT; | ||||
| 		break; | ||||
| 	case 'i': | ||||
| 	case 'I': | ||||
| 		*compat_type = E2P_FEATURE_INCOMPAT; | ||||
| 		break; | ||||
| 	case 'r': | ||||
| 	case 'R': | ||||
| 		*compat_type = E2P_FEATURE_RO_INCOMPAT; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return 1; | ||||
| 	} | ||||
| 	if (string[9] == 0) | ||||
| 		return 1; | ||||
| 	num = strtol(string+9, &eptr, 10); | ||||
| 	if (num > 32 || num < 0) | ||||
| 		return 1; | ||||
| 	if (*eptr) | ||||
| 		return 1; | ||||
| 	*mask = 1 << num; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static inline char *skip_over_blanks(char *cp) | ||||
| { | ||||
| 	while (*cp && isspace(*cp)) | ||||
| 		cp++; | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| static inline char *skip_over_word(char *cp) | ||||
| { | ||||
| 	while (*cp && !isspace(*cp) && *cp != ',') | ||||
| 		cp++; | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Edit a feature set array as requested by the user.  The ok_array, | ||||
|  * if set, allows the application to limit what features the user is | ||||
|  * allowed to set or clear using this function. | ||||
|  */ | ||||
| int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) | ||||
| { | ||||
| 	char	*cp, *buf, *next; | ||||
| 	int	neg; | ||||
| 	unsigned int	mask; | ||||
| 	int		compat_type; | ||||
|  | ||||
| 	buf = xstrdup(str); | ||||
| 	cp = buf; | ||||
| 	while (cp && *cp) { | ||||
| 		neg = 0; | ||||
| 		cp = skip_over_blanks(cp); | ||||
| 		next = skip_over_word(cp); | ||||
| 		if (*next == 0) | ||||
| 			next = 0; | ||||
| 		else | ||||
| 			*next = 0; | ||||
| 		switch (*cp) { | ||||
| 		case '-': | ||||
| 		case '^': | ||||
| 			neg++; | ||||
| 		case '+': | ||||
| 			cp++; | ||||
| 			break; | ||||
| 		} | ||||
| 		if (e2p_string2feature(cp, &compat_type, &mask)) | ||||
| 			return 1; | ||||
| 		if (ok_array && !(ok_array[compat_type] & mask)) | ||||
| 			return 1; | ||||
| 		if (neg) | ||||
| 			compat_array[compat_type] &= ~mask; | ||||
| 		else | ||||
| 			compat_array[compat_type] |= mask; | ||||
| 		cp = next ? next+1 : 0; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * fgetflags.c		- Get a file flags on an ext2 file system | ||||
|  * fsetflags.c		- Set a file flags on an ext2 file system | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                           Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                           Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 93/10/30	- Creation | ||||
|  */ | ||||
|  | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #ifdef HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #ifdef HAVE_EXT2_IOCTLS | ||||
| #include <fcntl.h> | ||||
| #include <sys/ioctl.h> | ||||
| #endif | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| #ifdef O_LARGEFILE | ||||
| #define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) | ||||
| #else | ||||
| #define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) | ||||
| #endif | ||||
|  | ||||
| int fgetsetflags (const char * name, unsigned long * get_flags, unsigned long set_flags) | ||||
| { | ||||
| #ifdef HAVE_EXT2_IOCTLS | ||||
| 	struct stat buf; | ||||
| 	int fd, r, f, save_errno = 0; | ||||
|  | ||||
| 	if (!stat(name, &buf) && | ||||
| 	    !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { | ||||
| 		goto notsupp; | ||||
| 	} | ||||
| 	fd = open (name, OPEN_FLAGS); | ||||
| 	if (fd == -1) | ||||
| 		return -1; | ||||
| 	if (!get_flags) { | ||||
| 		f = (int) set_flags; | ||||
| 		r = ioctl (fd, EXT2_IOC_SETFLAGS, &f); | ||||
| 	} else { | ||||
| 		r = ioctl (fd, EXT2_IOC_GETFLAGS, &f); | ||||
| 		*get_flags = f; | ||||
| 	} | ||||
| 	if (r == -1) | ||||
| 		save_errno = errno; | ||||
| 	close (fd); | ||||
| 	if (save_errno) | ||||
| 		errno = save_errno; | ||||
| 	return r; | ||||
| notsupp: | ||||
| #endif /* HAVE_EXT2_IOCTLS */ | ||||
| 	errno = EOPNOTSUPP; | ||||
| 	return -1; | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * fgetversion.c	- Get a file version on an ext2 file system | ||||
|  * fsetversion.c	- Set a file version on an ext2 file system | ||||
|  * | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                           Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                           Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 93/10/30	- Creation | ||||
|  */ | ||||
|  | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #ifdef HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <sys/ioctl.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| #ifdef O_LARGEFILE | ||||
| #define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) | ||||
| #else | ||||
| #define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|    To do fsetversion:     unsigned long *ptr_version must be set to NULL. | ||||
| 		      and unsigned long version must be set to a value | ||||
|    To do fgetversion:     unsigned long *ptr_version must NOT be set to NULL | ||||
| 		      and unsigned long version is ignored. | ||||
| 	TITO. | ||||
| */ | ||||
|  | ||||
| int fgetsetversion (const char * name, unsigned long * get_version, unsigned long set_version) | ||||
| { | ||||
| #ifdef HAVE_EXT2_IOCTLS | ||||
| 	int fd, r, ver, save_errno = 0; | ||||
|  | ||||
| 	fd = open (name, OPEN_FLAGS); | ||||
| 	if (fd == -1) | ||||
| 		return -1; | ||||
| 	if (!get_version) { | ||||
| 		ver = (int) set_version; | ||||
| 		r = ioctl (fd, EXT2_IOC_SETVERSION, &ver); | ||||
| 	} else { | ||||
| 		r = ioctl (fd, EXT2_IOC_GETVERSION, &ver); | ||||
| 		*get_version = ver; | ||||
| 	} | ||||
| 	if (r == -1) | ||||
| 		save_errno = errno; | ||||
| 	close (fd); | ||||
| 	if (save_errno) | ||||
| 		errno = save_errno; | ||||
| 	return r; | ||||
| #else /* ! HAVE_EXT2_IOCTLS */ | ||||
| 	errno = EOPNOTSUPP; | ||||
| 	return -1; | ||||
| #endif /* ! HAVE_EXT2_IOCTLS */ | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * feature.c --- convert between features and strings | ||||
|  * | ||||
|  * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu> | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| struct hash { | ||||
| 	int num; | ||||
| 	const char *string; | ||||
| }; | ||||
|  | ||||
| static const struct hash hash_list[] = { | ||||
| 	{ EXT2_HASH_LEGACY,   "legacy" }, | ||||
| 	{ EXT2_HASH_HALF_MD4, "half_md4" }, | ||||
| 	{ EXT2_HASH_TEA,      "tea" }, | ||||
| 	{ 0, 0 }, | ||||
| }; | ||||
|  | ||||
| const char *e2p_hash2string(int num) | ||||
| { | ||||
| 	const struct hash *p; | ||||
| 	static char buf[20]; | ||||
|  | ||||
| 	for (p = hash_list; p->string; p++) { | ||||
| 		if (num == p->num) | ||||
| 			return p->string; | ||||
| 	} | ||||
| 	sprintf(buf, "HASHALG_%d", num); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the hash algorithm, or -1 on error | ||||
|  */ | ||||
| int e2p_string2hash(char *string) | ||||
| { | ||||
| 	const struct hash *p; | ||||
| 	char *eptr; | ||||
| 	int num; | ||||
|  | ||||
| 	for (p = hash_list; p->string; p++) { | ||||
| 		if (!strcasecmp(string, p->string)) { | ||||
| 			return p->num; | ||||
| 		} | ||||
| 	} | ||||
| 	if (strncasecmp(string, "HASHALG_", 8)) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (string[8] == 0) | ||||
| 		return -1; | ||||
| 	num = strtol(string+8, &eptr, 10); | ||||
| 	if (num > 255 || num < 0) | ||||
| 		return -1; | ||||
| 	if (*eptr) | ||||
| 		return -1; | ||||
| 	return num; | ||||
| } | ||||
| @@ -1,52 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * iod.c		- Iterate a function on each entry of a directory | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                           Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                           Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 93/10/30	- Creation | ||||
|  */ | ||||
|  | ||||
| #include "e2p.h" | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| int iterate_on_dir (const char * dir_name, | ||||
| 		    int (*func) (const char *, struct dirent *, void *), | ||||
| 		    void * private) | ||||
| { | ||||
| 	DIR * dir; | ||||
| 	struct dirent *de, *dep; | ||||
| 	int	max_len, len; | ||||
|  | ||||
| 	max_len = PATH_MAX + sizeof(struct dirent); | ||||
| 	de = xmalloc(max_len+1); | ||||
| 	memset(de, 0, max_len+1); | ||||
|  | ||||
| 	dir = opendir (dir_name); | ||||
| 	if (dir == NULL) { | ||||
| 		free(de); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	while ((dep = readdir (dir))) { | ||||
| 		len = sizeof(struct dirent); | ||||
| 		if (len < dep->d_reclen) | ||||
| 			len = dep->d_reclen; | ||||
| 		if (len > max_len) | ||||
| 			len = max_len; | ||||
| 		memcpy(de, dep, len); | ||||
| 		(*func) (dir_name, de, private); | ||||
| 	} | ||||
| 	free(de); | ||||
| 	closedir(dir); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,273 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ls.c			- List the contents of an ext2fs superblock | ||||
|  * | ||||
|  * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                                 Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                                 Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * Copyright (C) 1995, 1996, 1997  Theodore Ts'o <tytso@mit.edu> | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <sys/types.h> | ||||
| #include <string.h> | ||||
| #include <grp.h> | ||||
| #include <pwd.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| static void print_user(unsigned short uid, FILE *f) | ||||
| { | ||||
| 	struct passwd *pw = getpwuid(uid); | ||||
| 	fprintf(f, "%u (user %s)\n", uid, | ||||
| 			(pw == NULL ? "unknown" : pw->pw_name)); | ||||
| } | ||||
|  | ||||
| static void print_group(unsigned short gid, FILE *f) | ||||
| { | ||||
| 	struct group *gr = getgrgid(gid); | ||||
| 	fprintf(f, "%u (group %s)\n", gid, | ||||
| 			(gr == NULL ? "unknown" : gr->gr_name)); | ||||
| } | ||||
|  | ||||
| #define MONTH_INT (86400 * 30) | ||||
| #define WEEK_INT (86400 * 7) | ||||
| #define DAY_INT	(86400) | ||||
| #define HOUR_INT (60 * 60) | ||||
| #define MINUTE_INT (60) | ||||
|  | ||||
| static const char *interval_string(unsigned int secs) | ||||
| { | ||||
| 	static char buf[256], tmp[80]; | ||||
| 	int		hr, min, num; | ||||
|  | ||||
| 	buf[0] = 0; | ||||
|  | ||||
| 	if (secs == 0) | ||||
| 		return "<none>"; | ||||
|  | ||||
| 	if (secs >= MONTH_INT) { | ||||
| 		num = secs / MONTH_INT; | ||||
| 		secs -= num*MONTH_INT; | ||||
| 		sprintf(buf, "%d month%s", num, (num>1) ? "s" : ""); | ||||
| 	} | ||||
| 	if (secs >= WEEK_INT) { | ||||
| 		num = secs / WEEK_INT; | ||||
| 		secs -= num*WEEK_INT; | ||||
| 		sprintf(tmp, "%s%d week%s", buf[0] ? ", " : "", | ||||
| 			num, (num>1) ? "s" : ""); | ||||
| 		strcat(buf, tmp); | ||||
| 	} | ||||
| 	if (secs >= DAY_INT) { | ||||
| 		num = secs / DAY_INT; | ||||
| 		secs -= num*DAY_INT; | ||||
| 		sprintf(tmp, "%s%d day%s", buf[0] ? ", " : "", | ||||
| 			num, (num>1) ? "s" : ""); | ||||
| 		strcat(buf, tmp); | ||||
| 	} | ||||
| 	if (secs > 0) { | ||||
| 		hr = secs / HOUR_INT; | ||||
| 		secs -= hr*HOUR_INT; | ||||
| 		min = secs / MINUTE_INT; | ||||
| 		secs -= min*MINUTE_INT; | ||||
| 		sprintf(tmp, "%s%d:%02d:%02d", buf[0] ? ", " : "", | ||||
| 			hr, min, secs); | ||||
| 		strcat(buf, tmp); | ||||
| 	} | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| static void print_features(struct ext2_super_block * s, FILE *f) | ||||
| { | ||||
| #ifdef EXT2_DYNAMIC_REV | ||||
| 	int	i, j, printed=0; | ||||
| 	__u32	*mask = &s->s_feature_compat, m; | ||||
|  | ||||
| 	fprintf(f, "Filesystem features:     "); | ||||
| 	for (i=0; i <3; i++,mask++) { | ||||
| 		for (j=0,m=1; j < 32; j++, m<<=1) { | ||||
| 			if (*mask & m) { | ||||
| 				fprintf(f, " %s", e2p_feature2string(i, m)); | ||||
| 				printed++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (printed == 0) | ||||
| 		fprintf(f, " (none)"); | ||||
| 	fprintf(f, "\n"); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void print_mntopts(struct ext2_super_block * s, FILE *f) | ||||
| { | ||||
| #ifdef EXT2_DYNAMIC_REV | ||||
| 	int	i, printed=0; | ||||
| 	__u32	mask = s->s_default_mount_opts, m; | ||||
|  | ||||
| 	fprintf(f, "Default mount options:   "); | ||||
| 	if (mask & EXT3_DEFM_JMODE) { | ||||
| 		fprintf(f, " %s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE)); | ||||
| 		printed++; | ||||
| 	} | ||||
| 	for (i=0,m=1; i < 32; i++, m<<=1) { | ||||
| 		if (m & EXT3_DEFM_JMODE) | ||||
| 			continue; | ||||
| 		if (mask & m) { | ||||
| 			fprintf(f, " %s", e2p_mntopt2string(m)); | ||||
| 			printed++; | ||||
| 		} | ||||
| 	} | ||||
| 	if (printed == 0) | ||||
| 		fprintf(f, " (none)"); | ||||
| 	fprintf(f, "\n"); | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifndef EXT2_INODE_SIZE | ||||
| #define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode) | ||||
| #endif | ||||
|  | ||||
| #ifndef EXT2_GOOD_OLD_REV | ||||
| #define EXT2_GOOD_OLD_REV 0 | ||||
| #endif | ||||
|  | ||||
| void list_super2(struct ext2_super_block * sb, FILE *f) | ||||
| { | ||||
| 	int inode_blocks_per_group; | ||||
| 	char buf[80], *str; | ||||
| 	time_t	tm; | ||||
|  | ||||
| 	inode_blocks_per_group = (((sb->s_inodes_per_group * | ||||
| 				    EXT2_INODE_SIZE(sb)) + | ||||
| 				   EXT2_BLOCK_SIZE(sb) - 1) / | ||||
| 				  EXT2_BLOCK_SIZE(sb)); | ||||
| 	if (sb->s_volume_name[0]) { | ||||
| 		memset(buf, 0, sizeof(buf)); | ||||
| 		strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name)); | ||||
| 	} else | ||||
| 		strcpy(buf, "<none>"); | ||||
| 	fprintf(f, "Filesystem volume name:   %s\n", buf); | ||||
| 	if (sb->s_last_mounted[0]) { | ||||
| 		memset(buf, 0, sizeof(buf)); | ||||
| 		strncpy(buf, sb->s_last_mounted, sizeof(sb->s_last_mounted)); | ||||
| 	} else | ||||
| 		strcpy(buf, "<not available>"); | ||||
| 	fprintf(f, | ||||
| 		"Last mounted on:          %s\n" | ||||
| 		"Filesystem UUID:          %s\n" | ||||
| 		"Filesystem magic number:  0x%04X\n" | ||||
| 		"Filesystem revision #:    %d", | ||||
| 		buf, e2p_uuid2str(sb->s_uuid), sb->s_magic, sb->s_rev_level); | ||||
| 	if (sb->s_rev_level == EXT2_GOOD_OLD_REV) { | ||||
| 		fprintf(f, " (original)\n"); | ||||
| #ifdef EXT2_DYNAMIC_REV | ||||
| 	} else if (sb->s_rev_level == EXT2_DYNAMIC_REV) { | ||||
| 		fprintf(f, " (dynamic)\n"); | ||||
| #endif | ||||
| 	} else | ||||
| 		fprintf(f, " (unknown)\n"); | ||||
| 	print_features(sb, f); | ||||
| 	print_mntopts(sb, f); | ||||
| 	fprintf(f, "Filesystem state:        "); | ||||
| 	print_fs_state (f, sb->s_state); | ||||
| 	fprintf(f, "\nErrors behavior:          "); | ||||
| 	print_fs_errors(f, sb->s_errors); | ||||
| 	str = e2p_os2string(sb->s_creator_os); | ||||
| 	fprintf(f, | ||||
| 		"\n" | ||||
| 		"Filesystem OS type:       %s\n" | ||||
| 		"Inode count:              %u\n" | ||||
| 		"Block count:              %u\n" | ||||
| 		"Reserved block count:     %u\n" | ||||
| 		"Free blocks:              %u\n" | ||||
| 		"Free inodes:              %u\n" | ||||
| 		"First block:              %u\n" | ||||
| 		"Block size:               %u\n" | ||||
| 		"Fragment size:            %u\n", | ||||
| 		str, sb->s_inodes_count, sb->s_blocks_count, sb->s_r_blocks_count, | ||||
| 		sb->s_free_blocks_count, sb->s_free_inodes_count, | ||||
| 		sb->s_first_data_block, EXT2_BLOCK_SIZE(sb), EXT2_FRAG_SIZE(sb)); | ||||
| 	free(str); | ||||
| 	if (sb->s_reserved_gdt_blocks) | ||||
| 		fprintf(f, "Reserved GDT blocks:      %u\n", | ||||
| 			sb->s_reserved_gdt_blocks); | ||||
| 	fprintf(f, | ||||
| 		"Blocks per group:         %u\n" | ||||
| 		"Fragments per group:      %u\n" | ||||
| 		"Inodes per group:         %u\n" | ||||
| 		"Inode blocks per group:   %u\n", | ||||
| 		sb->s_blocks_per_group, sb->s_frags_per_group, | ||||
| 		sb->s_inodes_per_group, inode_blocks_per_group); | ||||
| 	if (sb->s_first_meta_bg) | ||||
| 		fprintf(f, "First meta block group:   %u\n", | ||||
| 			sb->s_first_meta_bg); | ||||
| 	if (sb->s_mkfs_time) { | ||||
| 		tm = sb->s_mkfs_time; | ||||
| 		fprintf(f, "Filesystem created:       %s", ctime(&tm)); | ||||
| 	} | ||||
| 	tm = sb->s_mtime; | ||||
| 	fprintf(f, "Last mount time:          %s", | ||||
| 		sb->s_mtime ? ctime(&tm) : "n/a\n"); | ||||
| 	tm = sb->s_wtime; | ||||
| 	fprintf(f, | ||||
| 		"Last write time:          %s" | ||||
| 		"Mount count:              %u\n" | ||||
| 		"Maximum mount count:      %d\n", | ||||
| 		ctime(&tm), sb->s_mnt_count, sb->s_max_mnt_count); | ||||
| 	tm = sb->s_lastcheck; | ||||
| 	fprintf(f, | ||||
| 		"Last checked:             %s" | ||||
| 		"Check interval:           %u (%s)\n", | ||||
| 		ctime(&tm), | ||||
| 		sb->s_checkinterval, interval_string(sb->s_checkinterval)); | ||||
| 	if (sb->s_checkinterval) | ||||
| 	{ | ||||
| 		time_t next; | ||||
|  | ||||
| 		next = sb->s_lastcheck + sb->s_checkinterval; | ||||
| 		fprintf(f, "Next check after:         %s", ctime(&next)); | ||||
| 	} | ||||
| 	fprintf(f, "Reserved blocks uid:      "); | ||||
| 	print_user(sb->s_def_resuid, f); | ||||
| 	fprintf(f, "Reserved blocks gid:      "); | ||||
| 	print_group(sb->s_def_resgid, f); | ||||
| 	if (sb->s_rev_level >= EXT2_DYNAMIC_REV) { | ||||
| 		fprintf(f, | ||||
| 			"First inode:              %d\n" | ||||
| 			"Inode size:		  %d\n", | ||||
| 			sb->s_first_ino, sb->s_inode_size); | ||||
| 	} | ||||
| 	if (!e2p_is_null_uuid(sb->s_journal_uuid)) | ||||
| 		fprintf(f, "Journal UUID:             %s\n", | ||||
| 			e2p_uuid2str(sb->s_journal_uuid)); | ||||
| 	if (sb->s_journal_inum) | ||||
| 		fprintf(f, "Journal inode:            %u\n", | ||||
| 			sb->s_journal_inum); | ||||
| 	if (sb->s_journal_dev) | ||||
| 		fprintf(f, "Journal device:	          0x%04x\n", | ||||
| 			sb->s_journal_dev); | ||||
| 	if (sb->s_last_orphan) | ||||
| 		fprintf(f, "First orphan inode:       %u\n", | ||||
| 			sb->s_last_orphan); | ||||
| 	if ((sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) || | ||||
| 	    sb->s_def_hash_version) | ||||
| 		fprintf(f, "Default directory hash:   %s\n", | ||||
| 			e2p_hash2string(sb->s_def_hash_version)); | ||||
| 	if (!e2p_is_null_uuid(sb->s_hash_seed)) | ||||
| 		fprintf(f, "Directory Hash Seed:      %s\n", | ||||
| 			e2p_uuid2str(sb->s_hash_seed)); | ||||
| 	if (sb->s_jnl_backup_type) { | ||||
| 		fprintf(f, "Journal backup:           "); | ||||
| 		if (sb->s_jnl_backup_type == 1) | ||||
| 			fprintf(f, "inode blocks\n"); | ||||
| 		else | ||||
| 			fprintf(f, "type %u\n", sb->s_jnl_backup_type); | ||||
| 	} | ||||
| } | ||||
| @@ -1,134 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * mountopts.c --- convert between default mount options and strings | ||||
|  * | ||||
|  * Copyright (C) 2002  Theodore Ts'o <tytso@mit.edu> | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| struct mntopt { | ||||
| 	unsigned int	mask; | ||||
| 	const char	*string; | ||||
| }; | ||||
|  | ||||
| static const struct mntopt mntopt_list[] = { | ||||
| 	{ EXT2_DEFM_DEBUG,	"debug" }, | ||||
| 	{ EXT2_DEFM_BSDGROUPS,	"bsdgroups" }, | ||||
| 	{ EXT2_DEFM_XATTR_USER,	"user_xattr" }, | ||||
| 	{ EXT2_DEFM_ACL,	"acl" }, | ||||
| 	{ EXT2_DEFM_UID16,	"uid16" }, | ||||
| 	{ EXT3_DEFM_JMODE_DATA, "journal_data" }, | ||||
| 	{ EXT3_DEFM_JMODE_ORDERED, "journal_data_ordered" }, | ||||
| 	{ EXT3_DEFM_JMODE_WBACK, "journal_data_writeback" }, | ||||
| 	{ 0, 0 }, | ||||
| }; | ||||
|  | ||||
| const char *e2p_mntopt2string(unsigned int mask) | ||||
| { | ||||
| 	const struct mntopt  *f; | ||||
| 	static char buf[20]; | ||||
| 	int	fnum; | ||||
|  | ||||
| 	for (f = mntopt_list; f->string; f++) { | ||||
| 		if (mask == f->mask) | ||||
| 			return f->string; | ||||
| 	} | ||||
| 	for (fnum = 0; mask >>= 1; fnum++); | ||||
| 	sprintf(buf, "MNTOPT_%d", fnum); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| int e2p_string2mntopt(char *string, unsigned int *mask) | ||||
| { | ||||
| 	const struct mntopt  *f; | ||||
| 	char		*eptr; | ||||
| 	int		num; | ||||
|  | ||||
| 	for (f = mntopt_list; f->string; f++) { | ||||
| 		if (!strcasecmp(string, f->string)) { | ||||
| 			*mask = f->mask; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	if (strncasecmp(string, "MNTOPT_", 8)) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (string[8] == 0) | ||||
| 		return 1; | ||||
| 	num = strtol(string+8, &eptr, 10); | ||||
| 	if (num > 32 || num < 0) | ||||
| 		return 1; | ||||
| 	if (*eptr) | ||||
| 		return 1; | ||||
| 	*mask = 1 << num; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static char *skip_over_blanks(char *cp) | ||||
| { | ||||
| 	while (*cp && isspace(*cp)) | ||||
| 		cp++; | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| static char *skip_over_word(char *cp) | ||||
| { | ||||
| 	while (*cp && !isspace(*cp) && *cp != ',') | ||||
| 		cp++; | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Edit a mntopt set array as requested by the user.  The ok | ||||
|  * parameter, if non-zero, allows the application to limit what | ||||
|  * mntopts the user is allowed to set or clear using this function. | ||||
|  */ | ||||
| int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok) | ||||
| { | ||||
| 	char	*cp, *buf, *next; | ||||
| 	int	neg; | ||||
| 	unsigned int	mask; | ||||
|  | ||||
| 	buf = xstrdup(str); | ||||
| 	cp = buf; | ||||
| 	while (cp && *cp) { | ||||
| 		neg = 0; | ||||
| 		cp = skip_over_blanks(cp); | ||||
| 		next = skip_over_word(cp); | ||||
| 		if (*next == 0) | ||||
| 			next = 0; | ||||
| 		else | ||||
| 			*next = 0; | ||||
| 		switch (*cp) { | ||||
| 		case '-': | ||||
| 		case '^': | ||||
| 			neg++; | ||||
| 		case '+': | ||||
| 			cp++; | ||||
| 			break; | ||||
| 		} | ||||
| 		if (e2p_string2mntopt(cp, &mask)) | ||||
| 			return 1; | ||||
| 		if (ok && !(ok & mask)) | ||||
| 			return 1; | ||||
| 		if (mask & EXT3_DEFM_JMODE) | ||||
| 			*mntopts &= ~EXT3_DEFM_JMODE; | ||||
| 		if (neg) | ||||
| 			*mntopts &= ~mask; | ||||
| 		else | ||||
| 			*mntopts |= mask; | ||||
| 		cp = next ? next+1 : 0; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * getostype.c          - Get the Filesystem OS type | ||||
|  * | ||||
|  * Copyright (C) 2004,2005  Theodore Ts'o <tytso@mit.edu> | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| #include "e2p.h" | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| static const char *const os_tab[] = | ||||
| 	{ "Linux", | ||||
| 	  "Hurd", | ||||
| 	  "Masix", | ||||
| 	  "FreeBSD", | ||||
| 	  "Lites", | ||||
| 	  0 }; | ||||
|  | ||||
| /* | ||||
|  * Convert an os_type to a string | ||||
|  */ | ||||
| char *e2p_os2string(int os_type) | ||||
| { | ||||
| 	const char *os; | ||||
| 	char *ret; | ||||
|  | ||||
| 	if (os_type <= EXT2_OS_LITES) | ||||
| 		os = os_tab[os_type]; | ||||
| 	else | ||||
| 		os = "(unknown os)"; | ||||
|  | ||||
| 	ret = xstrdup(os); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Convert an os_type to a string | ||||
|  */ | ||||
| int e2p_string2os(char *str) | ||||
| { | ||||
| 	const char *const *cpp; | ||||
| 	int i = 0; | ||||
|  | ||||
| 	for (cpp = os_tab; *cpp; cpp++, i++) { | ||||
| 		if (!strcasecmp(str, *cpp)) | ||||
| 			return i; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_PROGRAM | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	char	*s; | ||||
| 	int	i, os; | ||||
|  | ||||
| 	for (i=0; i <= EXT2_OS_LITES; i++) { | ||||
| 		s = e2p_os2string(i); | ||||
| 		os = e2p_string2os(s); | ||||
| 		printf("%d: %s (%d)\n", i, s, os); | ||||
| 		if (i != os) { | ||||
| 			fprintf(stderr, "Failure!\n"); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 	} | ||||
| 	exit(0); | ||||
| } | ||||
| #endif | ||||
| @@ -1,65 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * parse_num.c		- Parse the number of blocks | ||||
|  * | ||||
|  * Copyright (C) 2004,2005  Theodore Ts'o <tytso@mit.edu> | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| unsigned long parse_num_blocks(const char *arg, int log_block_size) | ||||
| { | ||||
| 	char *p; | ||||
| 	unsigned long long num; | ||||
|  | ||||
| 	num = strtoull(arg, &p, 0); | ||||
|  | ||||
| 	if (p[0] && p[1]) | ||||
| 		return 0; | ||||
|  | ||||
| 	switch (*p) {		/* Using fall-through logic */ | ||||
| 	case 'T': case 't': | ||||
| 		num <<= 10; | ||||
| 	case 'G': case 'g': | ||||
| 		num <<= 10; | ||||
| 	case 'M': case 'm': | ||||
| 		num <<= 10; | ||||
| 	case 'K': case 'k': | ||||
| 		num >>= log_block_size; | ||||
| 		break; | ||||
| 	case 's': | ||||
| 		num >>= 1; | ||||
| 		break; | ||||
| 	case '\0': | ||||
| 		break; | ||||
| 	default: | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return num; | ||||
| } | ||||
|  | ||||
| #ifdef DEBUG | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| main(int argc, char **argv) | ||||
| { | ||||
| 	unsigned long num; | ||||
| 	int log_block_size = 0; | ||||
|  | ||||
| 	if (argc != 2) { | ||||
| 		fprintf(stderr, "Usage: %s arg\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	num = parse_num_blocks(argv[1], log_block_size); | ||||
|  | ||||
| 	printf("Parsed number: %lu\n", num); | ||||
| 	exit(0); | ||||
| } | ||||
| #endif | ||||
| @@ -1,32 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * pe.c			- Print a second extended filesystem errors behavior | ||||
|  * | ||||
|  * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                                 Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                                 Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 94/01/09	- Creation | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| void print_fs_errors(FILE *f, unsigned short errors) | ||||
| { | ||||
| 	char *disp = NULL; | ||||
| 	switch (errors) { | ||||
| 	case EXT2_ERRORS_CONTINUE: disp = "Continue"; break; | ||||
| 	case EXT2_ERRORS_RO:       disp = "Remount read-only"; break; | ||||
| 	case EXT2_ERRORS_PANIC:    disp = "Panic"; break; | ||||
| 	default:                   disp = "Unknown (continue)"; | ||||
| 	} | ||||
| 	fprintf(f, disp); | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * pf.c			- Print file attributes on an ext2 file system | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                           Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                           Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 93/10/30	- Creation | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| struct flags_name { | ||||
| 	unsigned long	flag; | ||||
| 	const char	*short_name; | ||||
| 	const char	*long_name; | ||||
| }; | ||||
|  | ||||
| static const struct flags_name flags_array[] = { | ||||
| 	{ EXT2_SECRM_FL, "s", "Secure_Deletion" }, | ||||
| 	{ EXT2_UNRM_FL, "u" , "Undelete" }, | ||||
| 	{ EXT2_SYNC_FL, "S", "Synchronous_Updates" }, | ||||
| 	{ EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" }, | ||||
| 	{ EXT2_IMMUTABLE_FL, "i", "Immutable" }, | ||||
| 	{ EXT2_APPEND_FL, "a", "Append_Only" }, | ||||
| 	{ EXT2_NODUMP_FL, "d", "No_Dump" }, | ||||
| 	{ EXT2_NOATIME_FL, "A", "No_Atime" }, | ||||
| 	{ EXT2_COMPR_FL, "c", "Compression_Requested" }, | ||||
| #ifdef ENABLE_COMPRESSION | ||||
| 	{ EXT2_COMPRBLK_FL, "B", "Compressed_File" }, | ||||
| 	{ EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" }, | ||||
| 	{ EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" }, | ||||
| 	{ EXT2_ECOMPR_FL, "E", "Compression_Error" }, | ||||
| #endif | ||||
| 	{ EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" }, | ||||
| 	{ EXT2_INDEX_FL, "I", "Indexed_direcctory" }, | ||||
| 	{ EXT2_NOTAIL_FL, "t", "No_Tailmerging" }, | ||||
| 	{ EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" }, | ||||
| 	{ 0, NULL, NULL } | ||||
| }; | ||||
|  | ||||
| void print_flags (FILE *f, unsigned long flags, unsigned options) | ||||
| { | ||||
| 	int long_opt = (options & PFOPT_LONG); | ||||
| 	const struct flags_name *fp; | ||||
| 	int	first = 1; | ||||
|  | ||||
| 	for (fp = flags_array; fp->flag != 0; fp++) { | ||||
| 		if (flags & fp->flag) { | ||||
| 			if (long_opt) { | ||||
| 				if (first) | ||||
| 					first = 0; | ||||
| 				else | ||||
| 					fputs(", ", f); | ||||
| 				fputs(fp->long_name, f); | ||||
| 			} else | ||||
| 				fputs(fp->short_name, f); | ||||
| 		} else { | ||||
| 			if (!long_opt) | ||||
| 				fputs("-", f); | ||||
| 		} | ||||
| 	} | ||||
| 	if (long_opt && first) | ||||
| 		fputs("---", f); | ||||
| } | ||||
| @@ -1,27 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ps.c			- Print filesystem state | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr> | ||||
|  *                           Laboratoire MASI, Institut Blaise Pascal | ||||
|  *                           Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  * This file can be redistributed under the terms of the GNU Library General | ||||
|  * Public License | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * History: | ||||
|  * 93/12/22	- Creation | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| void print_fs_state(FILE *f, unsigned short state) | ||||
| { | ||||
| 	fprintf(f, (state & EXT2_VALID_FS ? " clean" : " not clean")); | ||||
| 	if (state & EXT2_ERROR_FS) | ||||
| 		fprintf(f, " with errors"); | ||||
| } | ||||
| @@ -1,78 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * uuid.c -- utility routines for manipulating UUID's. | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "../ext2fs/ext2_types.h" | ||||
|  | ||||
| #include "e2p.h" | ||||
|  | ||||
| struct uuid { | ||||
| 	__u32	time_low; | ||||
| 	__u16	time_mid; | ||||
| 	__u16	time_hi_and_version; | ||||
| 	__u16	clock_seq; | ||||
| 	__u8	node[6]; | ||||
| }; | ||||
|  | ||||
| /* Returns 1 if the uuid is the NULL uuid */ | ||||
| int e2p_is_null_uuid(void *uu) | ||||
| { | ||||
| 	__u8	*cp; | ||||
| 	int	i; | ||||
|  | ||||
| 	for (i=0, cp = uu; i < 16; i++) | ||||
| 		if (*cp) | ||||
| 			return 0; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void e2p_unpack_uuid(void *in, struct uuid *uu) | ||||
| { | ||||
| 	__u8	*ptr = in; | ||||
| 	__u32	tmp; | ||||
|  | ||||
| 	tmp = *ptr++; | ||||
| 	tmp = (tmp << 8) | *ptr++; | ||||
| 	tmp = (tmp << 8) | *ptr++; | ||||
| 	tmp = (tmp << 8) | *ptr++; | ||||
| 	uu->time_low = tmp; | ||||
|  | ||||
| 	tmp = *ptr++; | ||||
| 	tmp = (tmp << 8) | *ptr++; | ||||
| 	uu->time_mid = tmp; | ||||
|  | ||||
| 	tmp = *ptr++; | ||||
| 	tmp = (tmp << 8) | *ptr++; | ||||
| 	uu->time_hi_and_version = tmp; | ||||
|  | ||||
| 	tmp = *ptr++; | ||||
| 	tmp = (tmp << 8) | *ptr++; | ||||
| 	uu->clock_seq = tmp; | ||||
|  | ||||
| 	memcpy(uu->node, ptr, 6); | ||||
| } | ||||
|  | ||||
| void e2p_uuid_to_str(void *uu, char *out) | ||||
| { | ||||
| 	struct uuid uuid; | ||||
|  | ||||
| 	e2p_unpack_uuid(uu, &uuid); | ||||
| 	sprintf(out, | ||||
| 		"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", | ||||
| 		uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, | ||||
| 		uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, | ||||
| 		uuid.node[0], uuid.node[1], uuid.node[2], | ||||
| 		uuid.node[3], uuid.node[4], uuid.node[5]); | ||||
| } | ||||
|  | ||||
| const char *e2p_uuid2str(void *uu) | ||||
| { | ||||
| 	static char buf[80]; | ||||
| 	if (e2p_is_null_uuid(uu)) | ||||
| 		return "<none>"; | ||||
| 	e2p_uuid_to_str(uu, buf); | ||||
| 	return buf; | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| # Makefile for busybox | ||||
| # | ||||
| # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> | ||||
| # | ||||
| # Licensed under GPLv2, see file LICENSE in this source tree. | ||||
|  | ||||
| NEEDED-$(CONFIG_E2FSCK) = y | ||||
| NEEDED-$(CONFIG_FSCK) = y | ||||
| NEEDED-$(CONFIG_MKE2FS) = y | ||||
| NEEDED-$(CONFIG_TUNE2FS) = y | ||||
|  | ||||
| lib-y:= | ||||
|  | ||||
| INSERT | ||||
|  | ||||
| lib-$(NEEDED-y) += gen_bitmap.o bitops.o ismounted.o mkjournal.o unix_io.o \ | ||||
|                    rw_bitmaps.o initialize.o bitmaps.o block.o \ | ||||
|                    ind_block.o inode.o freefs.o alloc_stats.o closefs.o \ | ||||
|                    openfs.o io_manager.o finddev.o read_bb.o alloc.o badblocks.o \ | ||||
|                    getsize.o getsectsize.o alloc_tables.o read_bb_file.o mkdir.o \ | ||||
|                    bb_inode.o newdir.o alloc_sb.o lookup.o dirblock.o expanddir.o \ | ||||
|                    dir_iterate.o link.o res_gdt.o icount.o get_pathname.o dblist.o \ | ||||
|                    dirhash.o version.o flushb.o unlink.o check_desc.o valid_blk.o \ | ||||
|                    ext_attr.o bmap.o dblist_dir.o ext2fs_inline.o swapfs.o | ||||
|  | ||||
| CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h | ||||
| @@ -1,173 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * alloc.c --- allocate new inodes, blocks for ext2fs | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * Right now, just search forward from the parent directory's block | ||||
|  * group to find the next free inode. | ||||
|  * | ||||
|  * Should have a special policy for directories. | ||||
|  */ | ||||
| errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, | ||||
| 			   int mode EXT2FS_ATTR((unused)), | ||||
| 			   ext2fs_inode_bitmap map, ext2_ino_t *ret) | ||||
| { | ||||
| 	ext2_ino_t	dir_group = 0; | ||||
| 	ext2_ino_t	i; | ||||
| 	ext2_ino_t	start_inode; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (!map) | ||||
| 		map = fs->inode_map; | ||||
| 	if (!map) | ||||
| 		return EXT2_ET_NO_INODE_BITMAP; | ||||
|  | ||||
| 	if (dir > 0) | ||||
| 		dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super); | ||||
|  | ||||
| 	start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1; | ||||
| 	if (start_inode < EXT2_FIRST_INODE(fs->super)) | ||||
| 		start_inode = EXT2_FIRST_INODE(fs->super); | ||||
| 	i = start_inode; | ||||
|  | ||||
| 	do { | ||||
| 		if (!ext2fs_fast_test_inode_bitmap(map, i)) | ||||
| 			break; | ||||
| 		i++; | ||||
| 		if (i > fs->super->s_inodes_count) | ||||
| 			i = EXT2_FIRST_INODE(fs->super); | ||||
| 	} while (i != start_inode); | ||||
|  | ||||
| 	if (ext2fs_test_inode_bitmap(map, i)) | ||||
| 		return EXT2_ET_INODE_ALLOC_FAIL; | ||||
| 	*ret = i; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Stupid algorithm --- we now just search forward starting from the | ||||
|  * goal.  Should put in a smarter one someday.... | ||||
|  */ | ||||
| errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, | ||||
| 			   ext2fs_block_bitmap map, blk_t *ret) | ||||
| { | ||||
| 	blk_t	i; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (!map) | ||||
| 		map = fs->block_map; | ||||
| 	if (!map) | ||||
| 		return EXT2_ET_NO_BLOCK_BITMAP; | ||||
| 	if (!goal || (goal >= fs->super->s_blocks_count)) | ||||
| 		goal = fs->super->s_first_data_block; | ||||
| 	i = goal; | ||||
| 	do { | ||||
| 		if (!ext2fs_fast_test_block_bitmap(map, i)) { | ||||
| 			*ret = i; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		i++; | ||||
| 		if (i >= fs->super->s_blocks_count) | ||||
| 			i = fs->super->s_first_data_block; | ||||
| 	} while (i != goal); | ||||
| 	return EXT2_ET_BLOCK_ALLOC_FAIL; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function zeros out the allocated block, and updates all of the | ||||
|  * appropriate filesystem records. | ||||
|  */ | ||||
| errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, | ||||
| 			     char *block_buf, blk_t *ret) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	blk_t		block; | ||||
| 	char		*buf = NULL; | ||||
|  | ||||
| 	if (!block_buf) { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize, &buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		block_buf = buf; | ||||
| 	} | ||||
| 	memset(block_buf, 0, fs->blocksize); | ||||
|  | ||||
| 	if (!fs->block_map) { | ||||
| 		retval = ext2fs_read_block_bitmap(fs); | ||||
| 		if (retval) | ||||
| 			goto fail; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_new_block(fs, goal, 0, &block); | ||||
| 	if (retval) | ||||
| 		goto fail; | ||||
|  | ||||
| 	retval = io_channel_write_blk(fs->io, block, 1, block_buf); | ||||
| 	if (retval) | ||||
| 		goto fail; | ||||
|  | ||||
| 	ext2fs_block_alloc_stats(fs, block, +1); | ||||
| 	*ret = block; | ||||
| 	return 0; | ||||
|  | ||||
| fail: | ||||
| 	if (buf) | ||||
| 		ext2fs_free_mem(&buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, | ||||
| 				 int num, ext2fs_block_bitmap map, blk_t *ret) | ||||
| { | ||||
| 	blk_t	b = start; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (!map) | ||||
| 		map = fs->block_map; | ||||
| 	if (!map) | ||||
| 		return EXT2_ET_NO_BLOCK_BITMAP; | ||||
| 	if (!b) | ||||
| 		b = fs->super->s_first_data_block; | ||||
| 	if (!finish) | ||||
| 		finish = start; | ||||
| 	if (!num) | ||||
| 		num = 1; | ||||
| 	do { | ||||
| 		if (b+num-1 > fs->super->s_blocks_count) | ||||
| 			b = fs->super->s_first_data_block; | ||||
| 		if (ext2fs_fast_test_block_bitmap_range(map, b, num)) { | ||||
| 			*ret = b; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		b++; | ||||
| 	} while (b != finish); | ||||
| 	return EXT2_ET_BLOCK_ALLOC_FAIL; | ||||
| } | ||||
| @@ -1,58 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * alloc_sb.c --- Allocate the superblock and block group descriptors for a | ||||
|  * newly initialized filesystem.  Used by mke2fs when initializing a filesystem | ||||
|  * | ||||
|  * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| int ext2fs_reserve_super_and_bgd(ext2_filsys fs, | ||||
| 				 dgrp_t group, | ||||
| 				 ext2fs_block_bitmap bmap) | ||||
| { | ||||
| 	blk_t	super_blk, old_desc_blk, new_desc_blk; | ||||
| 	int	j, old_desc_blocks, num_blocks; | ||||
|  | ||||
| 	num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk, | ||||
| 					      &old_desc_blk, &new_desc_blk, 0); | ||||
|  | ||||
| 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) | ||||
| 		old_desc_blocks = fs->super->s_first_meta_bg; | ||||
| 	else | ||||
| 		old_desc_blocks = | ||||
| 			fs->desc_blocks + fs->super->s_reserved_gdt_blocks; | ||||
|  | ||||
| 	if (super_blk || (group == 0)) | ||||
| 		ext2fs_mark_block_bitmap(bmap, super_blk); | ||||
|  | ||||
| 	if (old_desc_blk) { | ||||
| 		for (j=0; j < old_desc_blocks; j++) | ||||
| 			ext2fs_mark_block_bitmap(bmap, old_desc_blk + j); | ||||
| 	} | ||||
| 	if (new_desc_blk) | ||||
| 		ext2fs_mark_block_bitmap(bmap, new_desc_blk); | ||||
|  | ||||
| 	return num_blocks; | ||||
| } | ||||
| @@ -1,53 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * alloc_stats.c --- Update allocation statistics for ext2fs | ||||
|  * | ||||
|  * Copyright (C) 2001 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			       int inuse, int isdir) | ||||
| { | ||||
| 	int	group = ext2fs_group_of_ino(fs, ino); | ||||
|  | ||||
| 	if (inuse > 0) | ||||
| 		ext2fs_mark_inode_bitmap(fs->inode_map, ino); | ||||
| 	else | ||||
| 		ext2fs_unmark_inode_bitmap(fs->inode_map, ino); | ||||
| 	fs->group_desc[group].bg_free_inodes_count -= inuse; | ||||
| 	if (isdir) | ||||
| 		fs->group_desc[group].bg_used_dirs_count += inuse; | ||||
| 	fs->super->s_free_inodes_count -= inuse; | ||||
| 	ext2fs_mark_super_dirty(fs); | ||||
| 	ext2fs_mark_ib_dirty(fs); | ||||
| } | ||||
|  | ||||
| void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse) | ||||
| { | ||||
| 	ext2fs_inode_alloc_stats2(fs, ino, inuse, 0); | ||||
| } | ||||
|  | ||||
| void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse) | ||||
| { | ||||
| 	int	group = ext2fs_group_of_blk(fs, blk); | ||||
|  | ||||
| 	if (inuse > 0) | ||||
| 		ext2fs_mark_block_bitmap(fs->block_map, blk); | ||||
| 	else | ||||
| 		ext2fs_unmark_block_bitmap(fs->block_map, blk); | ||||
| 	fs->group_desc[group].bg_free_blocks_count -= inuse; | ||||
| 	fs->super->s_free_blocks_count -= inuse; | ||||
| 	ext2fs_mark_super_dirty(fs); | ||||
| 	ext2fs_mark_bb_dirty(fs); | ||||
| } | ||||
| @@ -1,114 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * alloc_tables.c --- Allocate tables for a newly initialized | ||||
|  * filesystem.  Used by mke2fs when initializing a filesystem | ||||
|  * | ||||
|  * Copyright (C) 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, | ||||
| 				      ext2fs_block_bitmap bmap) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	blk_t		group_blk, start_blk, last_blk, new_blk, blk; | ||||
| 	int		j; | ||||
|  | ||||
| 	group_blk = fs->super->s_first_data_block + | ||||
| 		(group * fs->super->s_blocks_per_group); | ||||
|  | ||||
| 	last_blk = group_blk + fs->super->s_blocks_per_group; | ||||
| 	if (last_blk >= fs->super->s_blocks_count) | ||||
| 		last_blk = fs->super->s_blocks_count - 1; | ||||
|  | ||||
| 	if (!bmap) | ||||
| 		bmap = fs->block_map; | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate the block and inode bitmaps, if necessary | ||||
| 	 */ | ||||
| 	if (fs->stride) { | ||||
| 		start_blk = group_blk + fs->inode_blocks_per_group; | ||||
| 		start_blk += ((fs->stride * group) % | ||||
| 			      (last_blk - start_blk)); | ||||
| 		if (start_blk > last_blk) | ||||
| 			start_blk = group_blk; | ||||
| 	} else | ||||
| 		start_blk = group_blk; | ||||
|  | ||||
| 	if (!fs->group_desc[group].bg_block_bitmap) { | ||||
| 		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk, | ||||
| 						1, bmap, &new_blk); | ||||
| 		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) | ||||
| 			retval = ext2fs_get_free_blocks(fs, group_blk, | ||||
| 					last_blk, 1, bmap, &new_blk); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		ext2fs_mark_block_bitmap(bmap, new_blk); | ||||
| 		fs->group_desc[group].bg_block_bitmap = new_blk; | ||||
| 	} | ||||
|  | ||||
| 	if (!fs->group_desc[group].bg_inode_bitmap) { | ||||
| 		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk, | ||||
| 						1, bmap, &new_blk); | ||||
| 		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) | ||||
| 			retval = ext2fs_get_free_blocks(fs, group_blk, | ||||
| 					last_blk, 1, bmap, &new_blk); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		ext2fs_mark_block_bitmap(bmap, new_blk); | ||||
| 		fs->group_desc[group].bg_inode_bitmap = new_blk; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate the inode table | ||||
| 	 */ | ||||
| 	if (!fs->group_desc[group].bg_inode_table) { | ||||
| 		retval = ext2fs_get_free_blocks(fs, group_blk, last_blk, | ||||
| 						fs->inode_blocks_per_group, | ||||
| 						bmap, &new_blk); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		for (j=0, blk = new_blk; | ||||
| 		     j < fs->inode_blocks_per_group; | ||||
| 		     j++, blk++) | ||||
| 			ext2fs_mark_block_bitmap(bmap, blk); | ||||
| 		fs->group_desc[group].bg_inode_table = new_blk; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_allocate_tables(ext2_filsys fs) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	dgrp_t		i; | ||||
|  | ||||
| 	for (i = 0; i < fs->group_desc_count; i++) { | ||||
| 		retval = ext2fs_allocate_group_table(fs, i, fs->block_map); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,328 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * badblocks.c --- routines to manipulate the bad block structure | ||||
|  * | ||||
|  * Copyright (C) 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| /* | ||||
|  * Helper function for making a badblocks list | ||||
|  */ | ||||
| static errcode_t make_u32_list(int size, int num, __u32 *list, | ||||
| 			       ext2_u32_list *ret) | ||||
| { | ||||
| 	ext2_u32_list	bb; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	memset(bb, 0, sizeof(struct ext2_struct_u32_list)); | ||||
| 	bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST; | ||||
| 	bb->size = size ? size : 10; | ||||
| 	bb->num = num; | ||||
| 	retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list); | ||||
| 	if (!bb->list) { | ||||
| 		ext2fs_free_mem(&bb); | ||||
| 		return retval; | ||||
| 	} | ||||
| 	if (list) | ||||
| 		memcpy(bb->list, list, bb->size * sizeof(blk_t)); | ||||
| 	else | ||||
| 		memset(bb->list, 0, bb->size * sizeof(blk_t)); | ||||
| 	*ret = bb; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This procedure creates an empty u32 list. | ||||
|  */ | ||||
| errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size) | ||||
| { | ||||
| 	return make_u32_list(size, 0, 0, ret); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This procedure creates an empty badblocks list. | ||||
|  */ | ||||
| errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size) | ||||
| { | ||||
| 	return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This procedure copies a badblocks list | ||||
|  */ | ||||
| errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	retval = make_u32_list(src->size, src->num, src->list, dest); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	(*dest)->badblocks_flags = src->badblocks_flags; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, | ||||
| 				ext2_badblocks_list *dest) | ||||
| { | ||||
| 	return ext2fs_u32_copy((ext2_u32_list) src, | ||||
| 			       (ext2_u32_list *) dest); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This procedure frees a badblocks list. | ||||
|  * | ||||
|  * (note: moved to closefs.c) | ||||
|  */ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This procedure adds a block to a badblocks list. | ||||
|  */ | ||||
| errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	int		i, j; | ||||
| 	unsigned long	old_size; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); | ||||
|  | ||||
| 	if (bb->num >= bb->size) { | ||||
| 		old_size = bb->size * sizeof(__u32); | ||||
| 		bb->size += 100; | ||||
| 		retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32), | ||||
| 					   &bb->list); | ||||
| 		if (retval) { | ||||
| 			bb->size -= 100; | ||||
| 			return retval; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Add special case code for appending to the end of the list | ||||
| 	 */ | ||||
| 	i = bb->num-1; | ||||
| 	if ((bb->num != 0) && (bb->list[i] == blk)) | ||||
| 		return 0; | ||||
| 	if ((bb->num == 0) || (bb->list[i] < blk)) { | ||||
| 		bb->list[bb->num++] = blk; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	j = bb->num; | ||||
| 	for (i=0; i < bb->num; i++) { | ||||
| 		if (bb->list[i] == blk) | ||||
| 			return 0; | ||||
| 		if (bb->list[i] > blk) { | ||||
| 			j = i; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	for (i=bb->num; i > j; i--) | ||||
| 		bb->list[i] = bb->list[i-1]; | ||||
| 	bb->list[j] = blk; | ||||
| 	bb->num++; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk) | ||||
| { | ||||
| 	return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This procedure finds a particular block is on a badblocks | ||||
|  * list. | ||||
|  */ | ||||
| int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk) | ||||
| { | ||||
| 	int	low, high, mid; | ||||
|  | ||||
| 	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (bb->num == 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	low = 0; | ||||
| 	high = bb->num-1; | ||||
| 	if (blk == bb->list[low]) | ||||
| 		return low; | ||||
| 	if (blk == bb->list[high]) | ||||
| 		return high; | ||||
|  | ||||
| 	while (low < high) { | ||||
| 		mid = (low+high)/2; | ||||
| 		if (mid == low || mid == high) | ||||
| 			break; | ||||
| 		if (blk == bb->list[mid]) | ||||
| 			return mid; | ||||
| 		if (blk < bb->list[mid]) | ||||
| 			high = mid; | ||||
| 		else | ||||
| 			low = mid; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This procedure tests to see if a particular block is on a badblocks | ||||
|  * list. | ||||
|  */ | ||||
| int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk) | ||||
| { | ||||
| 	if (ext2fs_u32_list_find(bb, blk) < 0) | ||||
| 		return 0; | ||||
| 	else | ||||
| 		return 1; | ||||
| } | ||||
|  | ||||
| int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk) | ||||
| { | ||||
| 	return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Remove a block from the badblock list | ||||
|  */ | ||||
| int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk) | ||||
| { | ||||
| 	int	remloc, i; | ||||
|  | ||||
| 	if (bb->num == 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	remloc = ext2fs_u32_list_find(bb, blk); | ||||
| 	if (remloc < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	for (i = remloc; i < bb->num - 1; i++) | ||||
| 		bb->list[i] = bb->list[i+1]; | ||||
| 	bb->num--; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk) | ||||
| { | ||||
| 	ext2fs_u32_list_del(bb, blk); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, | ||||
| 					ext2_u32_iterate *ret) | ||||
| { | ||||
| 	ext2_u32_iterate iter; | ||||
| 	errcode_t		retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE; | ||||
| 	iter->bb = bb; | ||||
| 	iter->ptr = 0; | ||||
| 	*ret = iter; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, | ||||
| 					      ext2_badblocks_iterate *ret) | ||||
| { | ||||
| 	return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb, | ||||
| 					      (ext2_u32_iterate *) ret); | ||||
| } | ||||
|  | ||||
|  | ||||
| int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk) | ||||
| { | ||||
| 	ext2_u32_list	bb; | ||||
|  | ||||
| 	if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE) | ||||
| 		return 0; | ||||
|  | ||||
| 	bb = iter->bb; | ||||
|  | ||||
| 	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (iter->ptr < bb->num) { | ||||
| 		*blk = bb->list[iter->ptr++]; | ||||
| 		return 1; | ||||
| 	} | ||||
| 	*blk = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk) | ||||
| { | ||||
| 	return ext2fs_u32_list_iterate((ext2_u32_iterate) iter, | ||||
| 				       (__u32 *) blk); | ||||
| } | ||||
|  | ||||
|  | ||||
| void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter) | ||||
| { | ||||
| 	if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)) | ||||
| 		return; | ||||
|  | ||||
| 	iter->bb = 0; | ||||
| 	ext2fs_free_mem(&iter); | ||||
| } | ||||
|  | ||||
| void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter) | ||||
| { | ||||
| 	ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter); | ||||
| } | ||||
|  | ||||
|  | ||||
| int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2) | ||||
| { | ||||
| 	EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST); | ||||
| 	EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST); | ||||
|  | ||||
| 	if (bb1->num != bb2->num) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0) | ||||
| 		return 0; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2) | ||||
| { | ||||
| 	return ext2fs_u32_list_equal((ext2_u32_list) bb1, | ||||
| 				     (ext2_u32_list) bb2); | ||||
| } | ||||
|  | ||||
| int ext2fs_u32_list_count(ext2_u32_list bb) | ||||
| { | ||||
| 	return bb->num; | ||||
| } | ||||
| @@ -1,64 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bb_compat.c --- compatibility badblocks routines | ||||
|  * | ||||
|  * Copyright (C) 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| errcode_t badblocks_list_create(badblocks_list *ret, int size) | ||||
| { | ||||
| 	return ext2fs_badblocks_list_create(ret, size); | ||||
| } | ||||
|  | ||||
| void badblocks_list_free(badblocks_list bb) | ||||
| { | ||||
| 	ext2fs_badblocks_list_free(bb); | ||||
| } | ||||
|  | ||||
| errcode_t badblocks_list_add(badblocks_list bb, blk_t blk) | ||||
| { | ||||
| 	return ext2fs_badblocks_list_add(bb, blk); | ||||
| } | ||||
|  | ||||
| int badblocks_list_test(badblocks_list bb, blk_t blk) | ||||
| { | ||||
| 	return ext2fs_badblocks_list_test(bb, blk); | ||||
| } | ||||
|  | ||||
| errcode_t badblocks_list_iterate_begin(badblocks_list bb, | ||||
| 				       badblocks_iterate *ret) | ||||
| { | ||||
| 	return ext2fs_badblocks_list_iterate_begin(bb, ret); | ||||
| } | ||||
|  | ||||
| int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk) | ||||
| { | ||||
| 	return ext2fs_badblocks_list_iterate(iter, blk); | ||||
| } | ||||
|  | ||||
| void badblocks_list_iterate_end(badblocks_iterate iter) | ||||
| { | ||||
| 	ext2fs_badblocks_list_iterate_end(iter); | ||||
| } | ||||
| @@ -1,262 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bb_inode.c --- routines to update the bad block inode. | ||||
|  * | ||||
|  * WARNING: This routine modifies a lot of state in the filesystem; if | ||||
|  * this routine returns an error, the bad block inode may be in an | ||||
|  * inconsistent state. | ||||
|  * | ||||
|  * Copyright (C) 1994, 1995 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct set_badblock_record { | ||||
| 	ext2_badblocks_iterate	bb_iter; | ||||
| 	int		bad_block_count; | ||||
| 	blk_t		*ind_blocks; | ||||
| 	int		max_ind_blocks; | ||||
| 	int		ind_blocks_size; | ||||
| 	int		ind_blocks_ptr; | ||||
| 	char		*block_buf; | ||||
| 	errcode_t	err; | ||||
| }; | ||||
|  | ||||
| static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, | ||||
| 			      e2_blkcnt_t blockcnt, | ||||
| 			      blk_t ref_block, int ref_offset, | ||||
| 			      void *priv_data); | ||||
| static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, | ||||
| 				e2_blkcnt_t blockcnt, | ||||
| 				blk_t ref_block, int ref_offset, | ||||
| 				void *priv_data); | ||||
|  | ||||
| /* | ||||
|  * Given a bad blocks bitmap, update the bad blocks inode to reflect | ||||
|  * the map. | ||||
|  */ | ||||
| errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list) | ||||
| { | ||||
| 	errcode_t			retval; | ||||
| 	struct set_badblock_record	rec; | ||||
| 	struct ext2_inode		inode; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (!fs->block_map) | ||||
| 		return EXT2_ET_NO_BLOCK_BITMAP; | ||||
|  | ||||
| 	rec.bad_block_count = 0; | ||||
| 	rec.ind_blocks_size = rec.ind_blocks_ptr = 0; | ||||
| 	rec.max_ind_blocks = 10; | ||||
| 	retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t), | ||||
| 				&rec.ind_blocks); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t)); | ||||
| 	retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	memset(rec.block_buf, 0, fs->blocksize); | ||||
| 	rec.err = 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * First clear the old bad blocks (while saving the indirect blocks) | ||||
| 	 */ | ||||
| 	retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, | ||||
| 				       BLOCK_FLAG_DEPTH_TRAVERSE, 0, | ||||
| 				       clear_bad_block_proc, &rec); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	if (rec.err) { | ||||
| 		retval = rec.err; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Now set the bad blocks! | ||||
| 	 * | ||||
| 	 * First, mark the bad blocks as used.  This prevents a bad | ||||
| 	 * block from being used as an indirecto block for the bad | ||||
| 	 * block inode (!). | ||||
| 	 */ | ||||
| 	if (bb_list) { | ||||
| 		retval = ext2fs_badblocks_list_iterate_begin(bb_list, | ||||
| 							     &rec.bb_iter); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 		retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, | ||||
| 					       BLOCK_FLAG_APPEND, 0, | ||||
| 					       set_bad_block_proc, &rec); | ||||
| 		ext2fs_badblocks_list_iterate_end(rec.bb_iter); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 		if (rec.err) { | ||||
| 			retval = rec.err; | ||||
| 			goto cleanup; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Update the bad block inode's mod time and block count | ||||
| 	 * field. | ||||
| 	 */ | ||||
| 	retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	inode.i_atime = inode.i_mtime = time(NULL); | ||||
| 	if (!inode.i_ctime) | ||||
| 		inode.i_ctime = time(NULL); | ||||
| 	inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512); | ||||
| 	inode.i_size = rec.bad_block_count * fs->blocksize; | ||||
|  | ||||
| 	retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| cleanup: | ||||
| 	ext2fs_free_mem(&rec.ind_blocks); | ||||
| 	ext2fs_free_mem(&rec.block_buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Helper function for update_bb_inode() | ||||
|  * | ||||
|  * Clear the bad blocks in the bad block inode, while saving the | ||||
|  * indirect blocks. | ||||
|  */ | ||||
| #ifdef __TURBOC__ | ||||
| # pragma argsused | ||||
| #endif | ||||
| static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, | ||||
| 				e2_blkcnt_t blockcnt, | ||||
| 				blk_t ref_block EXT2FS_ATTR((unused)), | ||||
| 				int ref_offset EXT2FS_ATTR((unused)), | ||||
| 				void *priv_data) | ||||
| { | ||||
| 	struct set_badblock_record *rec = (struct set_badblock_record *) | ||||
| 		priv_data; | ||||
| 	errcode_t	retval; | ||||
| 	unsigned long	old_size; | ||||
|  | ||||
| 	if (!*block_nr) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * If the block number is outrageous, clear it and ignore it. | ||||
| 	 */ | ||||
| 	if (*block_nr >= fs->super->s_blocks_count || | ||||
| 	    *block_nr < fs->super->s_first_data_block) { | ||||
| 		*block_nr = 0; | ||||
| 		return BLOCK_CHANGED; | ||||
| 	} | ||||
|  | ||||
| 	if (blockcnt < 0) { | ||||
| 		if (rec->ind_blocks_size >= rec->max_ind_blocks) { | ||||
| 			old_size = rec->max_ind_blocks * sizeof(blk_t); | ||||
| 			rec->max_ind_blocks += 10; | ||||
| 			retval = ext2fs_resize_mem(old_size, | ||||
| 				   rec->max_ind_blocks * sizeof(blk_t), | ||||
| 				   &rec->ind_blocks); | ||||
| 			if (retval) { | ||||
| 				rec->max_ind_blocks -= 10; | ||||
| 				rec->err = retval; | ||||
| 				return BLOCK_ABORT; | ||||
| 			} | ||||
| 		} | ||||
| 		rec->ind_blocks[rec->ind_blocks_size++] = *block_nr; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Mark the block as unused, and update accounting information | ||||
| 	 */ | ||||
| 	ext2fs_block_alloc_stats(fs, *block_nr, -1); | ||||
|  | ||||
| 	*block_nr = 0; | ||||
| 	return BLOCK_CHANGED; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Helper function for update_bb_inode() | ||||
|  * | ||||
|  * Set the block list in the bad block inode, using the supplied bitmap. | ||||
|  */ | ||||
| #ifdef __TURBOC__ | ||||
|  #pragma argsused | ||||
| #endif | ||||
| static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, | ||||
| 			      e2_blkcnt_t blockcnt, | ||||
| 			      blk_t ref_block EXT2FS_ATTR((unused)), | ||||
| 			      int ref_offset EXT2FS_ATTR((unused)), | ||||
| 			      void *priv_data) | ||||
| { | ||||
| 	struct set_badblock_record *rec = (struct set_badblock_record *) | ||||
| 		priv_data; | ||||
| 	errcode_t	retval; | ||||
| 	blk_t		blk; | ||||
|  | ||||
| 	if (blockcnt >= 0) { | ||||
| 		/* | ||||
| 		 * Get the next bad block. | ||||
| 		 */ | ||||
| 		if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk)) | ||||
| 			return BLOCK_ABORT; | ||||
| 		rec->bad_block_count++; | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * An indirect block; fetch a block from the | ||||
| 		 * previously used indirect block list.  The block | ||||
| 		 * most be not marked as used; if so, get another one. | ||||
| 		 * If we run out of reserved indirect blocks, allocate | ||||
| 		 * a new one. | ||||
| 		 */ | ||||
| 	retry: | ||||
| 		if (rec->ind_blocks_ptr < rec->ind_blocks_size) { | ||||
| 			blk = rec->ind_blocks[rec->ind_blocks_ptr++]; | ||||
| 			if (ext2fs_test_block_bitmap(fs->block_map, blk)) | ||||
| 				goto retry; | ||||
| 		} else { | ||||
| 			retval = ext2fs_new_block(fs, 0, 0, &blk); | ||||
| 			if (retval) { | ||||
| 				rec->err = retval; | ||||
| 				return BLOCK_ABORT; | ||||
| 			} | ||||
| 		} | ||||
| 		retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf); | ||||
| 		if (retval) { | ||||
| 			rec->err = retval; | ||||
| 			return BLOCK_ABORT; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Update block counts | ||||
| 	 */ | ||||
| 	ext2fs_block_alloc_stats(fs, blk, +1); | ||||
|  | ||||
| 	*block_nr = blk; | ||||
| 	return BLOCK_CHANGED; | ||||
| } | ||||
| @@ -1,211 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bitmaps.c --- routines to read, write, and manipulate the inode and | ||||
|  * block bitmaps. | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end, | ||||
| 			     const char *descr, char *init_map, | ||||
| 			     ext2fs_generic_bitmap *ret) | ||||
| { | ||||
| 	ext2fs_generic_bitmap	bitmap; | ||||
| 	errcode_t		retval; | ||||
| 	size_t			size; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), | ||||
| 				&bitmap); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP; | ||||
| 	bitmap->fs = NULL; | ||||
| 	bitmap->start = start; | ||||
| 	bitmap->end = end; | ||||
| 	bitmap->real_end = real_end; | ||||
| 	bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; | ||||
| 	if (descr) { | ||||
| 		retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); | ||||
| 		if (retval) { | ||||
| 			ext2fs_free_mem(&bitmap); | ||||
| 			return retval; | ||||
| 		} | ||||
| 		strcpy(bitmap->description, descr); | ||||
| 	} else | ||||
| 		bitmap->description = 0; | ||||
|  | ||||
| 	size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); | ||||
| 	retval = ext2fs_get_mem(size, &bitmap->bitmap); | ||||
| 	if (retval) { | ||||
| 		ext2fs_free_mem(&bitmap->description); | ||||
| 		ext2fs_free_mem(&bitmap); | ||||
| 		return retval; | ||||
| 	} | ||||
|  | ||||
| 	if (init_map) | ||||
| 		memcpy(bitmap->bitmap, init_map, size); | ||||
| 	else | ||||
| 		memset(bitmap->bitmap, 0, size); | ||||
| 	*ret = bitmap; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_allocate_generic_bitmap(__u32 start, | ||||
| 					 __u32 end, | ||||
| 					 __u32 real_end, | ||||
| 					 const char *descr, | ||||
| 					 ext2fs_generic_bitmap *ret) | ||||
| { | ||||
| 	return make_bitmap(start, end, real_end, descr, 0, ret); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, | ||||
| 			     ext2fs_generic_bitmap *dest) | ||||
| { | ||||
| 	errcode_t		retval; | ||||
| 	ext2fs_generic_bitmap	new_map; | ||||
|  | ||||
| 	retval = make_bitmap(src->start, src->end, src->real_end, | ||||
| 			     src->description, src->bitmap, &new_map); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	new_map->magic = src->magic; | ||||
| 	new_map->fs = src->fs; | ||||
| 	new_map->base_error_code = src->base_error_code; | ||||
| 	*dest = new_map; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map) | ||||
| { | ||||
| 	__u32	i, j; | ||||
|  | ||||
| 	for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++) | ||||
| 		ext2fs_set_bit(j, map->bitmap); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, | ||||
| 				       const char *descr, | ||||
| 				       ext2fs_inode_bitmap *ret) | ||||
| { | ||||
| 	ext2fs_inode_bitmap bitmap; | ||||
| 	errcode_t	retval; | ||||
| 	__u32		start, end, real_end; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	fs->write_bitmaps = ext2fs_write_bitmaps; | ||||
|  | ||||
| 	start = 1; | ||||
| 	end = fs->super->s_inodes_count; | ||||
| 	real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count); | ||||
|  | ||||
| 	retval = ext2fs_allocate_generic_bitmap(start, end, real_end, | ||||
| 						descr, &bitmap); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP; | ||||
| 	bitmap->fs = fs; | ||||
| 	bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; | ||||
|  | ||||
| 	*ret = bitmap; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, | ||||
| 				       const char *descr, | ||||
| 				       ext2fs_block_bitmap *ret) | ||||
| { | ||||
| 	ext2fs_block_bitmap bitmap; | ||||
| 	errcode_t	retval; | ||||
| 	__u32		start, end, real_end; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	fs->write_bitmaps = ext2fs_write_bitmaps; | ||||
|  | ||||
| 	start = fs->super->s_first_data_block; | ||||
| 	end = fs->super->s_blocks_count-1; | ||||
| 	real_end = (EXT2_BLOCKS_PER_GROUP(fs->super) | ||||
| 		    * fs->group_desc_count)-1 + start; | ||||
|  | ||||
| 	retval = ext2fs_allocate_generic_bitmap(start, end, real_end, | ||||
| 						descr, &bitmap); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP; | ||||
| 	bitmap->fs = fs; | ||||
| 	bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; | ||||
|  | ||||
| 	*ret = bitmap; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, | ||||
| 					ext2_ino_t end, ext2_ino_t *oend) | ||||
| { | ||||
| 	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP); | ||||
|  | ||||
| 	if (end > bitmap->real_end) | ||||
| 		return EXT2_ET_FUDGE_INODE_BITMAP_END; | ||||
| 	if (oend) | ||||
| 		*oend = bitmap->end; | ||||
| 	bitmap->end = end; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, | ||||
| 					blk_t end, blk_t *oend) | ||||
| { | ||||
| 	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP); | ||||
|  | ||||
| 	if (end > bitmap->real_end) | ||||
| 		return EXT2_ET_FUDGE_BLOCK_BITMAP_END; | ||||
| 	if (oend) | ||||
| 		*oend = bitmap->end; | ||||
| 	bitmap->end = end; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap) | ||||
| { | ||||
| 	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP)) | ||||
| 		return; | ||||
|  | ||||
| 	memset(bitmap->bitmap, 0, | ||||
| 	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); | ||||
| } | ||||
|  | ||||
| void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap) | ||||
| { | ||||
| 	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP)) | ||||
| 		return; | ||||
|  | ||||
| 	memset(bitmap->bitmap, 0, | ||||
| 	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); | ||||
| } | ||||
| @@ -1,90 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bitops.c --- Bitmap frobbing code.  See bitops.h for the inlined | ||||
|  *	routines. | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| #ifndef _EXT2_HAVE_ASM_BITOPS_ | ||||
|  | ||||
| /* | ||||
|  * For the benefit of those who are trying to port Linux to another | ||||
|  * architecture, here are some C-language equivalents.  You should | ||||
|  * recode these in the native assmebly language, if at all possible. | ||||
|  * | ||||
|  * C language equivalents written by Theodore Ts'o, 9/26/92. | ||||
|  * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian | ||||
|  * systems, as well as non-32 bit systems. | ||||
|  */ | ||||
|  | ||||
| int ext2fs_set_bit(unsigned int nr,void * addr) | ||||
| { | ||||
| 	int		mask, retval; | ||||
| 	unsigned char	*ADDR = (unsigned char *) addr; | ||||
|  | ||||
| 	ADDR += nr >> 3; | ||||
| 	mask = 1 << (nr & 0x07); | ||||
| 	retval = mask & *ADDR; | ||||
| 	*ADDR |= mask; | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| int ext2fs_clear_bit(unsigned int nr, void * addr) | ||||
| { | ||||
| 	int		mask, retval; | ||||
| 	unsigned char	*ADDR = (unsigned char *) addr; | ||||
|  | ||||
| 	ADDR += nr >> 3; | ||||
| 	mask = 1 << (nr & 0x07); | ||||
| 	retval = mask & *ADDR; | ||||
| 	*ADDR &= ~mask; | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| int ext2fs_test_bit(unsigned int nr, const void * addr) | ||||
| { | ||||
| 	int			mask; | ||||
| 	const unsigned char	*ADDR = (const unsigned char *) addr; | ||||
|  | ||||
| 	ADDR += nr >> 3; | ||||
| 	mask = 1 << (nr & 0x07); | ||||
| 	return (mask & *ADDR); | ||||
| } | ||||
|  | ||||
| #endif  /* !_EXT2_HAVE_ASM_BITOPS_ */ | ||||
|  | ||||
| void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, | ||||
| 			const char *description) | ||||
| { | ||||
| #ifndef OMIT_COM_ERR | ||||
| 	if (description) | ||||
| 		bb_error_msg("#%lu for %s", arg, description); | ||||
| 	else | ||||
| 		bb_error_msg("#%lu", arg); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, | ||||
| 			    int code, unsigned long arg) | ||||
| { | ||||
| #ifndef OMIT_COM_ERR | ||||
| 	if (bitmap->description) | ||||
| 		bb_error_msg("#%lu for %s", arg, bitmap->description); | ||||
| 	else | ||||
| 		bb_error_msg("#%lu", arg); | ||||
| #endif | ||||
| } | ||||
| @@ -1,105 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bitops.h --- Bitmap frobbing code.  The byte swapping routines are | ||||
|  *	also included here. | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  * | ||||
|  * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992, | ||||
|  * Linus Torvalds. | ||||
|  */ | ||||
| #include <string.h> | ||||
|  | ||||
| extern int ext2fs_set_bit(unsigned int nr,void * addr); | ||||
| extern int ext2fs_clear_bit(unsigned int nr, void * addr); | ||||
| extern int ext2fs_test_bit(unsigned int nr, const void * addr); | ||||
| extern __u16 ext2fs_swab16(__u16 val); | ||||
| extern __u32 ext2fs_swab32(__u32 val); | ||||
|  | ||||
| #ifdef WORDS_BIGENDIAN | ||||
| #define ext2fs_cpu_to_le32(x) ext2fs_swab32((x)) | ||||
| #define ext2fs_le32_to_cpu(x) ext2fs_swab32((x)) | ||||
| #define ext2fs_cpu_to_le16(x) ext2fs_swab16((x)) | ||||
| #define ext2fs_le16_to_cpu(x) ext2fs_swab16((x)) | ||||
| #define ext2fs_cpu_to_be32(x) ((__u32)(x)) | ||||
| #define ext2fs_be32_to_cpu(x) ((__u32)(x)) | ||||
| #define ext2fs_cpu_to_be16(x) ((__u16)(x)) | ||||
| #define ext2fs_be16_to_cpu(x) ((__u16)(x)) | ||||
| #else | ||||
| #define ext2fs_cpu_to_le32(x) ((__u32)(x)) | ||||
| #define ext2fs_le32_to_cpu(x) ((__u32)(x)) | ||||
| #define ext2fs_cpu_to_le16(x) ((__u16)(x)) | ||||
| #define ext2fs_le16_to_cpu(x) ((__u16)(x)) | ||||
| #define ext2fs_cpu_to_be32(x) ext2fs_swab32((x)) | ||||
| #define ext2fs_be32_to_cpu(x) ext2fs_swab32((x)) | ||||
| #define ext2fs_cpu_to_be16(x) ext2fs_swab16((x)) | ||||
| #define ext2fs_be16_to_cpu(x) ext2fs_swab16((x)) | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * EXT2FS bitmap manipulation routines. | ||||
|  */ | ||||
|  | ||||
| /* Support for sending warning messages from the inline subroutines */ | ||||
| extern const char *ext2fs_block_string; | ||||
| extern const char *ext2fs_inode_string; | ||||
| extern const char *ext2fs_mark_string; | ||||
| extern const char *ext2fs_unmark_string; | ||||
| extern const char *ext2fs_test_string; | ||||
| extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, | ||||
| 			       const char *description); | ||||
| extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, | ||||
| 				int code, unsigned long arg); | ||||
|  | ||||
| extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); | ||||
| extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 				       blk_t block); | ||||
| extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); | ||||
|  | ||||
| extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); | ||||
| extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 				       ext2_ino_t inode); | ||||
| extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); | ||||
|  | ||||
| extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					  blk_t block); | ||||
| extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					    blk_t block); | ||||
| extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					 blk_t block); | ||||
|  | ||||
| extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					  ext2_ino_t inode); | ||||
| extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					    ext2_ino_t inode); | ||||
| extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					 ext2_ino_t inode); | ||||
| extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap); | ||||
| extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap); | ||||
| extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap); | ||||
| extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap); | ||||
|  | ||||
| extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					   blk_t block, int num); | ||||
| extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					     blk_t block, int num); | ||||
| extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					  blk_t block, int num); | ||||
| extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 						blk_t block, int num); | ||||
| extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 						  blk_t block, int num); | ||||
| extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					       blk_t block, int num); | ||||
| extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map); | ||||
|  | ||||
| /* These two routines moved to gen_bitmap.c */ | ||||
| extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||||
| 					 __u32 bitno); | ||||
| extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||||
| 					   blk_t bitno); | ||||
| @@ -1,437 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * block.c --- iterate over all blocks in an inode | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct block_context { | ||||
| 	ext2_filsys	fs; | ||||
| 	int (*func)(ext2_filsys	fs, | ||||
| 		    blk_t	*blocknr, | ||||
| 		    e2_blkcnt_t	bcount, | ||||
| 		    blk_t	ref_blk, | ||||
| 		    int		ref_offset, | ||||
| 		    void	*priv_data); | ||||
| 	e2_blkcnt_t	bcount; | ||||
| 	int		bsize; | ||||
| 	int		flags; | ||||
| 	errcode_t	errcode; | ||||
| 	char	*ind_buf; | ||||
| 	char	*dind_buf; | ||||
| 	char	*tind_buf; | ||||
| 	void	*priv_data; | ||||
| }; | ||||
|  | ||||
| static int block_iterate_ind(blk_t *ind_block, blk_t ref_block, | ||||
| 			     int ref_offset, struct block_context *ctx) | ||||
| { | ||||
| 	int	ret = 0, changed = 0; | ||||
| 	int	i, flags, limit, offset; | ||||
| 	blk_t	*block_nr; | ||||
|  | ||||
| 	limit = ctx->fs->blocksize >> 2; | ||||
| 	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | ||||
| 	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) | ||||
| 		ret = (*ctx->func)(ctx->fs, ind_block, | ||||
| 				   BLOCK_COUNT_IND, ref_block, | ||||
| 				   ref_offset, ctx->priv_data); | ||||
| 	if (!*ind_block || (ret & BLOCK_ABORT)) { | ||||
| 		ctx->bcount += limit; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	if (*ind_block >= ctx->fs->super->s_blocks_count || | ||||
| 	    *ind_block < ctx->fs->super->s_first_data_block) { | ||||
| 		ctx->errcode = EXT2_ET_BAD_IND_BLOCK; | ||||
| 		ret |= BLOCK_ERROR; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block, | ||||
| 					     ctx->ind_buf); | ||||
| 	if (ctx->errcode) { | ||||
| 		ret |= BLOCK_ERROR; | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	block_nr = (blk_t *) ctx->ind_buf; | ||||
| 	offset = 0; | ||||
| 	if (ctx->flags & BLOCK_FLAG_APPEND) { | ||||
| 		for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { | ||||
| 			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount, | ||||
| 					     *ind_block, offset, | ||||
| 					     ctx->priv_data); | ||||
| 			changed	|= flags; | ||||
| 			if (flags & BLOCK_ABORT) { | ||||
| 				ret |= BLOCK_ABORT; | ||||
| 				break; | ||||
| 			} | ||||
| 			offset += sizeof(blk_t); | ||||
| 		} | ||||
| 	} else { | ||||
| 		for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { | ||||
| 			if (*block_nr == 0) | ||||
| 				continue; | ||||
| 			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount, | ||||
| 					     *ind_block, offset, | ||||
| 					     ctx->priv_data); | ||||
| 			changed	|= flags; | ||||
| 			if (flags & BLOCK_ABORT) { | ||||
| 				ret |= BLOCK_ABORT; | ||||
| 				break; | ||||
| 			} | ||||
| 			offset += sizeof(blk_t); | ||||
| 		} | ||||
| 	} | ||||
| 	if (changed & BLOCK_CHANGED) { | ||||
| 		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block, | ||||
| 						      ctx->ind_buf); | ||||
| 		if (ctx->errcode) | ||||
| 			ret |= BLOCK_ERROR | BLOCK_ABORT; | ||||
| 	} | ||||
| 	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | ||||
| 	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && | ||||
| 	    !(ret & BLOCK_ABORT)) | ||||
| 		ret |= (*ctx->func)(ctx->fs, ind_block, | ||||
| 				    BLOCK_COUNT_IND, ref_block, | ||||
| 				    ref_offset, ctx->priv_data); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int block_iterate_dind(blk_t *dind_block, blk_t ref_block, | ||||
| 			      int ref_offset, struct block_context *ctx) | ||||
| { | ||||
| 	int	ret = 0, changed = 0; | ||||
| 	int	i, flags, limit, offset; | ||||
| 	blk_t	*block_nr; | ||||
|  | ||||
| 	limit = ctx->fs->blocksize >> 2; | ||||
| 	if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | | ||||
| 			    BLOCK_FLAG_DATA_ONLY))) | ||||
| 		ret = (*ctx->func)(ctx->fs, dind_block, | ||||
| 				   BLOCK_COUNT_DIND, ref_block, | ||||
| 				   ref_offset, ctx->priv_data); | ||||
| 	if (!*dind_block || (ret & BLOCK_ABORT)) { | ||||
| 		ctx->bcount += limit*limit; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	if (*dind_block >= ctx->fs->super->s_blocks_count || | ||||
| 	    *dind_block < ctx->fs->super->s_first_data_block) { | ||||
| 		ctx->errcode = EXT2_ET_BAD_DIND_BLOCK; | ||||
| 		ret |= BLOCK_ERROR; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block, | ||||
| 					     ctx->dind_buf); | ||||
| 	if (ctx->errcode) { | ||||
| 		ret |= BLOCK_ERROR; | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	block_nr = (blk_t *) ctx->dind_buf; | ||||
| 	offset = 0; | ||||
| 	if (ctx->flags & BLOCK_FLAG_APPEND) { | ||||
| 		for (i = 0; i < limit; i++, block_nr++) { | ||||
| 			flags = block_iterate_ind(block_nr, | ||||
| 						  *dind_block, offset, | ||||
| 						  ctx); | ||||
| 			changed |= flags; | ||||
| 			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { | ||||
| 				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | ||||
| 				break; | ||||
| 			} | ||||
| 			offset += sizeof(blk_t); | ||||
| 		} | ||||
| 	} else { | ||||
| 		for (i = 0; i < limit; i++, block_nr++) { | ||||
| 			if (*block_nr == 0) { | ||||
| 				ctx->bcount += limit; | ||||
| 				continue; | ||||
| 			} | ||||
| 			flags = block_iterate_ind(block_nr, | ||||
| 						  *dind_block, offset, | ||||
| 						  ctx); | ||||
| 			changed |= flags; | ||||
| 			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { | ||||
| 				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | ||||
| 				break; | ||||
| 			} | ||||
| 			offset += sizeof(blk_t); | ||||
| 		} | ||||
| 	} | ||||
| 	if (changed & BLOCK_CHANGED) { | ||||
| 		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block, | ||||
| 						      ctx->dind_buf); | ||||
| 		if (ctx->errcode) | ||||
| 			ret |= BLOCK_ERROR | BLOCK_ABORT; | ||||
| 	} | ||||
| 	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | ||||
| 	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && | ||||
| 	    !(ret & BLOCK_ABORT)) | ||||
| 		ret |= (*ctx->func)(ctx->fs, dind_block, | ||||
| 				    BLOCK_COUNT_DIND, ref_block, | ||||
| 				    ref_offset, ctx->priv_data); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, | ||||
| 			      int ref_offset, struct block_context *ctx) | ||||
| { | ||||
| 	int	ret = 0, changed = 0; | ||||
| 	int	i, flags, limit, offset; | ||||
| 	blk_t	*block_nr; | ||||
|  | ||||
| 	limit = ctx->fs->blocksize >> 2; | ||||
| 	if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | | ||||
| 			    BLOCK_FLAG_DATA_ONLY))) | ||||
| 		ret = (*ctx->func)(ctx->fs, tind_block, | ||||
| 				   BLOCK_COUNT_TIND, ref_block, | ||||
| 				   ref_offset, ctx->priv_data); | ||||
| 	if (!*tind_block || (ret & BLOCK_ABORT)) { | ||||
| 		ctx->bcount += limit*limit*limit; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	if (*tind_block >= ctx->fs->super->s_blocks_count || | ||||
| 	    *tind_block < ctx->fs->super->s_first_data_block) { | ||||
| 		ctx->errcode = EXT2_ET_BAD_TIND_BLOCK; | ||||
| 		ret |= BLOCK_ERROR; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block, | ||||
| 					     ctx->tind_buf); | ||||
| 	if (ctx->errcode) { | ||||
| 		ret |= BLOCK_ERROR; | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	block_nr = (blk_t *) ctx->tind_buf; | ||||
| 	offset = 0; | ||||
| 	if (ctx->flags & BLOCK_FLAG_APPEND) { | ||||
| 		for (i = 0; i < limit; i++, block_nr++) { | ||||
| 			flags = block_iterate_dind(block_nr, | ||||
| 						   *tind_block, | ||||
| 						   offset, ctx); | ||||
| 			changed |= flags; | ||||
| 			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { | ||||
| 				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | ||||
| 				break; | ||||
| 			} | ||||
| 			offset += sizeof(blk_t); | ||||
| 		} | ||||
| 	} else { | ||||
| 		for (i = 0; i < limit; i++, block_nr++) { | ||||
| 			if (*block_nr == 0) { | ||||
| 				ctx->bcount += limit*limit; | ||||
| 				continue; | ||||
| 			} | ||||
| 			flags = block_iterate_dind(block_nr, | ||||
| 						   *tind_block, | ||||
| 						   offset, ctx); | ||||
| 			changed |= flags; | ||||
| 			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { | ||||
| 				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | ||||
| 				break; | ||||
| 			} | ||||
| 			offset += sizeof(blk_t); | ||||
| 		} | ||||
| 	} | ||||
| 	if (changed & BLOCK_CHANGED) { | ||||
| 		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block, | ||||
| 						      ctx->tind_buf); | ||||
| 		if (ctx->errcode) | ||||
| 			ret |= BLOCK_ERROR | BLOCK_ABORT; | ||||
| 	} | ||||
| 	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | ||||
| 	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && | ||||
| 	    !(ret & BLOCK_ABORT)) | ||||
| 		ret |= (*ctx->func)(ctx->fs, tind_block, | ||||
| 				    BLOCK_COUNT_TIND, ref_block, | ||||
| 				    ref_offset, ctx->priv_data); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_block_iterate2(ext2_filsys fs, | ||||
| 				ext2_ino_t ino, | ||||
| 				int	flags, | ||||
| 				char *block_buf, | ||||
| 				int (*func)(ext2_filsys fs, | ||||
| 					    blk_t	*blocknr, | ||||
| 					    e2_blkcnt_t	blockcnt, | ||||
| 					    blk_t	ref_blk, | ||||
| 					    int		ref_offset, | ||||
| 					    void	*priv_data), | ||||
| 				void *priv_data) | ||||
| { | ||||
| 	int	i; | ||||
| 	int	got_inode = 0; | ||||
| 	int	ret = 0; | ||||
| 	blk_t	blocks[EXT2_N_BLOCKS];	/* directory data blocks */ | ||||
| 	struct ext2_inode inode; | ||||
| 	errcode_t	retval; | ||||
| 	struct block_context ctx; | ||||
| 	int	limit; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	/* | ||||
| 	 * Check to see if we need to limit large files | ||||
| 	 */ | ||||
| 	if (flags & BLOCK_FLAG_NO_LARGE) { | ||||
| 		ctx.errcode = ext2fs_read_inode(fs, ino, &inode); | ||||
| 		if (ctx.errcode) | ||||
| 			return ctx.errcode; | ||||
| 		got_inode = 1; | ||||
| 		if (!LINUX_S_ISDIR(inode.i_mode) && | ||||
| 		    (inode.i_size_high != 0)) | ||||
| 			return EXT2_ET_FILE_TOO_BIG; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_blocks(fs, ino, blocks); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	limit = fs->blocksize >> 2; | ||||
|  | ||||
| 	ctx.fs = fs; | ||||
| 	ctx.func = func; | ||||
| 	ctx.priv_data = priv_data; | ||||
| 	ctx.flags = flags; | ||||
| 	ctx.bcount = 0; | ||||
| 	if (block_buf) { | ||||
| 		ctx.ind_buf = block_buf; | ||||
| 	} else { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	ctx.dind_buf = ctx.ind_buf + fs->blocksize; | ||||
| 	ctx.tind_buf = ctx.dind_buf + fs->blocksize; | ||||
|  | ||||
| 	/* | ||||
| 	 * Iterate over the HURD translator block (if present) | ||||
| 	 */ | ||||
| 	if ((fs->super->s_creator_os == EXT2_OS_HURD) && | ||||
| 	    !(flags & BLOCK_FLAG_DATA_ONLY)) { | ||||
| 		ctx.errcode = ext2fs_read_inode(fs, ino, &inode); | ||||
| 		if (ctx.errcode) | ||||
| 			goto abort_exit; | ||||
| 		got_inode = 1; | ||||
| 		if (inode.osd1.hurd1.h_i_translator) { | ||||
| 			ret |= (*ctx.func)(fs, | ||||
| 					   &inode.osd1.hurd1.h_i_translator, | ||||
| 					   BLOCK_COUNT_TRANSLATOR, | ||||
| 					   0, 0, priv_data); | ||||
| 			if (ret & BLOCK_ABORT) | ||||
| 				goto abort_exit; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Iterate over normal data blocks | ||||
| 	 */ | ||||
| 	for (i = 0; i < EXT2_NDIR_BLOCKS; i++, ctx.bcount++) { | ||||
| 		if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) { | ||||
| 			ret |= (*ctx.func)(fs, &blocks[i], | ||||
| 					    ctx.bcount, 0, i, priv_data); | ||||
| 			if (ret & BLOCK_ABORT) | ||||
| 				goto abort_exit; | ||||
| 		} | ||||
| 	} | ||||
| 	if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { | ||||
| 		ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK, | ||||
| 					 0, EXT2_IND_BLOCK, &ctx); | ||||
| 		if (ret & BLOCK_ABORT) | ||||
| 			goto abort_exit; | ||||
| 	} else | ||||
| 		ctx.bcount += limit; | ||||
| 	if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { | ||||
| 		ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK, | ||||
| 					  0, EXT2_DIND_BLOCK, &ctx); | ||||
| 		if (ret & BLOCK_ABORT) | ||||
| 			goto abort_exit; | ||||
| 	} else | ||||
| 		ctx.bcount += limit * limit; | ||||
| 	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { | ||||
| 		ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK, | ||||
| 					  0, EXT2_TIND_BLOCK, &ctx); | ||||
| 		if (ret & BLOCK_ABORT) | ||||
| 			goto abort_exit; | ||||
| 	} | ||||
|  | ||||
| abort_exit: | ||||
| 	if (ret & BLOCK_CHANGED) { | ||||
| 		if (!got_inode) { | ||||
| 			retval = ext2fs_read_inode(fs, ino, &inode); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		for (i=0; i < EXT2_N_BLOCKS; i++) | ||||
| 			inode.i_block[i] = blocks[i]; | ||||
| 		retval = ext2fs_write_inode(fs, ino, &inode); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	if (!block_buf) | ||||
| 		ext2fs_free_mem(&ctx.ind_buf); | ||||
|  | ||||
| 	return (ret & BLOCK_ERROR) ? ctx.errcode : 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Emulate the old ext2fs_block_iterate function! | ||||
|  */ | ||||
|  | ||||
| struct xlate { | ||||
| 	int (*func)(ext2_filsys	fs, | ||||
| 		    blk_t	*blocknr, | ||||
| 		    int		bcount, | ||||
| 		    void	*priv_data); | ||||
| 	void *real_private; | ||||
| }; | ||||
|  | ||||
| #ifdef __TURBOC__ | ||||
| # pragma argsused | ||||
| #endif | ||||
| static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, | ||||
| 		      blk_t ref_block EXT2FS_ATTR((unused)), | ||||
| 		      int ref_offset EXT2FS_ATTR((unused)), | ||||
| 		      void *priv_data) | ||||
| { | ||||
| 	struct xlate *xl = (struct xlate *) priv_data; | ||||
|  | ||||
| 	return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_block_iterate(ext2_filsys fs, | ||||
| 			       ext2_ino_t ino, | ||||
| 			       int	flags, | ||||
| 			       char *block_buf, | ||||
| 			       int (*func)(ext2_filsys fs, | ||||
| 					   blk_t	*blocknr, | ||||
| 					   int	blockcnt, | ||||
| 					   void	*priv_data), | ||||
| 			       void *priv_data) | ||||
| { | ||||
| 	struct xlate xl; | ||||
|  | ||||
| 	xl.real_private = priv_data; | ||||
| 	xl.func = func; | ||||
|  | ||||
| 	return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags, | ||||
| 				     block_buf, xlate_func, &xl); | ||||
| } | ||||
| @@ -1,261 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bmap.c --- logical to physical block mapping | ||||
|  * | ||||
|  * Copyright (C) 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			     struct ext2_inode *inode, | ||||
| 			     char *block_buf, int bmap_flags, | ||||
| 			     blk_t block, blk_t *phys_blk); | ||||
|  | ||||
| #define inode_bmap(inode, nr) ((inode)->i_block[(nr)]) | ||||
|  | ||||
| static errcode_t block_ind_bmap(ext2_filsys fs, int flags, | ||||
| 					      blk_t ind, char *block_buf, | ||||
| 					      int *blocks_alloc, | ||||
| 					      blk_t nr, blk_t *ret_blk) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	blk_t		b; | ||||
|  | ||||
| 	if (!ind) { | ||||
| 		if (flags & BMAP_SET) | ||||
| 			return EXT2_ET_SET_BMAP_NO_IND; | ||||
| 		*ret_blk = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	retval = io_channel_read_blk(fs->io, ind, 1, block_buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	if (flags & BMAP_SET) { | ||||
| 		b = *ret_blk; | ||||
| #if BB_BIG_ENDIAN | ||||
| 		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) | ||||
| 			b = ext2fs_swab32(b); | ||||
| #endif | ||||
| 		((blk_t *) block_buf)[nr] = b; | ||||
| 		return io_channel_write_blk(fs->io, ind, 1, block_buf); | ||||
| 	} | ||||
|  | ||||
| 	b = ((blk_t *) block_buf)[nr]; | ||||
|  | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | ||||
| 		b = ext2fs_swab32(b); | ||||
| #endif | ||||
|  | ||||
| 	if (!b && (flags & BMAP_ALLOC)) { | ||||
| 		b = nr ? ((blk_t *) block_buf)[nr-1] : 0; | ||||
| 		retval = ext2fs_alloc_block(fs, b, | ||||
| 					    block_buf + fs->blocksize, &b); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
|  | ||||
| #if BB_BIG_ENDIAN | ||||
| 		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) | ||||
| 			((blk_t *) block_buf)[nr] = ext2fs_swab32(b); | ||||
| 		else | ||||
| #endif | ||||
| 			((blk_t *) block_buf)[nr] = b; | ||||
|  | ||||
| 		retval = io_channel_write_blk(fs->io, ind, 1, block_buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
|  | ||||
| 		(*blocks_alloc)++; | ||||
| 	} | ||||
|  | ||||
| 	*ret_blk = b; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t block_dind_bmap(ext2_filsys fs, int flags, | ||||
| 					       blk_t dind, char *block_buf, | ||||
| 					       int *blocks_alloc, | ||||
| 					       blk_t nr, blk_t *ret_blk) | ||||
| { | ||||
| 	blk_t		b; | ||||
| 	errcode_t	retval; | ||||
| 	blk_t		addr_per_block; | ||||
|  | ||||
| 	addr_per_block = (blk_t) fs->blocksize >> 2; | ||||
|  | ||||
| 	retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf, | ||||
| 				blocks_alloc, nr / addr_per_block, &b); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, | ||||
| 				nr % addr_per_block, ret_blk); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static errcode_t block_tind_bmap(ext2_filsys fs, int flags, | ||||
| 					       blk_t tind, char *block_buf, | ||||
| 					       int *blocks_alloc, | ||||
| 					       blk_t nr, blk_t *ret_blk) | ||||
| { | ||||
| 	blk_t		b; | ||||
| 	errcode_t	retval; | ||||
| 	blk_t		addr_per_block; | ||||
|  | ||||
| 	addr_per_block = (blk_t) fs->blocksize >> 2; | ||||
|  | ||||
| 	retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf, | ||||
| 				 blocks_alloc, nr / addr_per_block, &b); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, | ||||
| 				nr % addr_per_block, ret_blk); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, | ||||
| 		      char *block_buf, int bmap_flags, blk_t block, | ||||
| 		      blk_t *phys_blk) | ||||
| { | ||||
| 	struct ext2_inode inode_buf; | ||||
| 	blk_t addr_per_block; | ||||
| 	blk_t	b; | ||||
| 	char	*buf = NULL; | ||||
| 	errcode_t	retval = 0; | ||||
| 	int		blocks_alloc = 0, inode_dirty = 0; | ||||
|  | ||||
| 	if (!(bmap_flags & BMAP_SET)) | ||||
| 		*phys_blk = 0; | ||||
|  | ||||
| 	/* Read inode structure if necessary */ | ||||
| 	if (!inode) { | ||||
| 		retval = ext2fs_read_inode(fs, ino, &inode_buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		inode = &inode_buf; | ||||
| 	} | ||||
| 	addr_per_block = (blk_t) fs->blocksize >> 2; | ||||
|  | ||||
| 	if (!block_buf) { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize * 2, &buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		block_buf = buf; | ||||
| 	} | ||||
|  | ||||
| 	if (block < EXT2_NDIR_BLOCKS) { | ||||
| 		if (bmap_flags & BMAP_SET) { | ||||
| 			b = *phys_blk; | ||||
| #if BB_BIG_ENDIAN | ||||
| 			if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 			    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | ||||
| 				b = ext2fs_swab32(b); | ||||
| #endif | ||||
| 			inode_bmap(inode, block) = b; | ||||
| 			inode_dirty++; | ||||
| 			goto done; | ||||
| 		} | ||||
|  | ||||
| 		*phys_blk = inode_bmap(inode, block); | ||||
| 		b = block ? inode_bmap(inode, block-1) : 0; | ||||
|  | ||||
| 		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { | ||||
| 			retval = ext2fs_alloc_block(fs, b, block_buf, &b); | ||||
| 			if (retval) | ||||
| 				goto done; | ||||
| 			inode_bmap(inode, block) = b; | ||||
| 			blocks_alloc++; | ||||
| 			*phys_blk = b; | ||||
| 		} | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	/* Indirect block */ | ||||
| 	block -= EXT2_NDIR_BLOCKS; | ||||
| 	if (block < addr_per_block) { | ||||
| 		b = inode_bmap(inode, EXT2_IND_BLOCK); | ||||
| 		if (!b) { | ||||
| 			if (!(bmap_flags & BMAP_ALLOC)) { | ||||
| 				if (bmap_flags & BMAP_SET) | ||||
| 					retval = EXT2_ET_SET_BMAP_NO_IND; | ||||
| 				goto done; | ||||
| 			} | ||||
|  | ||||
| 			b = inode_bmap(inode, EXT2_IND_BLOCK-1); | ||||
| 			retval = ext2fs_alloc_block(fs, b, block_buf, &b); | ||||
| 			if (retval) | ||||
| 				goto done; | ||||
| 			inode_bmap(inode, EXT2_IND_BLOCK) = b; | ||||
| 			blocks_alloc++; | ||||
| 		} | ||||
| 		retval = block_ind_bmap(fs, bmap_flags, b, block_buf, | ||||
| 					&blocks_alloc, block, phys_blk); | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	/* Doubly indirect block  */ | ||||
| 	block -= addr_per_block; | ||||
| 	if (block < addr_per_block * addr_per_block) { | ||||
| 		b = inode_bmap(inode, EXT2_DIND_BLOCK); | ||||
| 		if (!b) { | ||||
| 			if (!(bmap_flags & BMAP_ALLOC)) { | ||||
| 				if (bmap_flags & BMAP_SET) | ||||
| 					retval = EXT2_ET_SET_BMAP_NO_IND; | ||||
| 				goto done; | ||||
| 			} | ||||
|  | ||||
| 			b = inode_bmap(inode, EXT2_IND_BLOCK); | ||||
| 			retval = ext2fs_alloc_block(fs, b, block_buf, &b); | ||||
| 			if (retval) | ||||
| 				goto done; | ||||
| 			inode_bmap(inode, EXT2_DIND_BLOCK) = b; | ||||
| 			blocks_alloc++; | ||||
| 		} | ||||
| 		retval = block_dind_bmap(fs, bmap_flags, b, block_buf, | ||||
| 					 &blocks_alloc, block, phys_blk); | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	/* Triply indirect block */ | ||||
| 	block -= addr_per_block * addr_per_block; | ||||
| 	b = inode_bmap(inode, EXT2_TIND_BLOCK); | ||||
| 	if (!b) { | ||||
| 		if (!(bmap_flags & BMAP_ALLOC)) { | ||||
| 			if (bmap_flags & BMAP_SET) | ||||
| 				retval = EXT2_ET_SET_BMAP_NO_IND; | ||||
| 			goto done; | ||||
| 		} | ||||
|  | ||||
| 		b = inode_bmap(inode, EXT2_DIND_BLOCK); | ||||
| 		retval = ext2fs_alloc_block(fs, b, block_buf, &b); | ||||
| 		if (retval) | ||||
| 			goto done; | ||||
| 		inode_bmap(inode, EXT2_TIND_BLOCK) = b; | ||||
| 		blocks_alloc++; | ||||
| 	} | ||||
| 	retval = block_tind_bmap(fs, bmap_flags, b, block_buf, | ||||
| 				 &blocks_alloc, block, phys_blk); | ||||
| done: | ||||
| 	ext2fs_free_mem(&buf); | ||||
| 	if ((retval == 0) && (blocks_alloc || inode_dirty)) { | ||||
| 		inode->i_blocks += (blocks_alloc * fs->blocksize) / 512; | ||||
| 		retval = ext2fs_write_inode(fs, ino, inode); | ||||
| 	} | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,155 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * bmove.c --- Move blocks around to make way for a particular | ||||
|  *	filesystem structure. | ||||
|  * | ||||
|  * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed | ||||
|  * under the terms of the GNU Public License. | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| struct process_block_struct { | ||||
| 	ext2_ino_t		ino; | ||||
| 	struct ext2_inode *	inode; | ||||
| 	ext2fs_block_bitmap	reserve; | ||||
| 	ext2fs_block_bitmap	alloc_map; | ||||
| 	errcode_t		error; | ||||
| 	char			*buf; | ||||
| 	int			add_dir; | ||||
| 	int			flags; | ||||
| }; | ||||
|  | ||||
| static int process_block(ext2_filsys fs, blk_t	*block_nr, | ||||
| 			 e2_blkcnt_t blockcnt, blk_t ref_block, | ||||
| 			 int ref_offset, void *priv_data) | ||||
| { | ||||
| 	struct process_block_struct *pb; | ||||
| 	errcode_t	retval; | ||||
| 	int		ret; | ||||
| 	blk_t		block, orig; | ||||
|  | ||||
| 	pb = (struct process_block_struct *) priv_data; | ||||
| 	block = orig = *block_nr; | ||||
| 	ret = 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * Let's see if this is one which we need to relocate | ||||
| 	 */ | ||||
| 	if (ext2fs_test_block_bitmap(pb->reserve, block)) { | ||||
| 		do { | ||||
| 			if (++block >= fs->super->s_blocks_count) | ||||
| 				block = fs->super->s_first_data_block; | ||||
| 			if (block == orig) { | ||||
| 				pb->error = EXT2_ET_BLOCK_ALLOC_FAIL; | ||||
| 				return BLOCK_ABORT; | ||||
| 			} | ||||
| 		} while (ext2fs_test_block_bitmap(pb->reserve, block) || | ||||
| 			 ext2fs_test_block_bitmap(pb->alloc_map, block)); | ||||
|  | ||||
| 		retval = io_channel_read_blk(fs->io, orig, 1, pb->buf); | ||||
| 		if (retval) { | ||||
| 			pb->error = retval; | ||||
| 			return BLOCK_ABORT; | ||||
| 		} | ||||
| 		retval = io_channel_write_blk(fs->io, block, 1, pb->buf); | ||||
| 		if (retval) { | ||||
| 			pb->error = retval; | ||||
| 			return BLOCK_ABORT; | ||||
| 		} | ||||
| 		*block_nr = block; | ||||
| 		ext2fs_mark_block_bitmap(pb->alloc_map, block); | ||||
| 		ret = BLOCK_CHANGED; | ||||
| 		if (pb->flags & EXT2_BMOVE_DEBUG) | ||||
| 			printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino, | ||||
| 			       blockcnt, orig, block); | ||||
| 	} | ||||
| 	if (pb->add_dir) { | ||||
| 		retval = ext2fs_add_dir_block(fs->dblist, pb->ino, | ||||
| 					      block, (int) blockcnt); | ||||
| 		if (retval) { | ||||
| 			pb->error = retval; | ||||
| 			ret |= BLOCK_ABORT; | ||||
| 		} | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_move_blocks(ext2_filsys fs, | ||||
| 			     ext2fs_block_bitmap reserve, | ||||
| 			     ext2fs_block_bitmap alloc_map, | ||||
| 			     int flags) | ||||
| { | ||||
| 	ext2_ino_t	ino; | ||||
| 	struct ext2_inode inode; | ||||
| 	errcode_t	retval; | ||||
| 	struct process_block_struct pb; | ||||
| 	ext2_inode_scan	scan; | ||||
| 	char		*block_buf; | ||||
|  | ||||
| 	retval = ext2fs_open_inode_scan(fs, 0, &scan); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	pb.reserve = reserve; | ||||
| 	pb.error = 0; | ||||
| 	pb.alloc_map = alloc_map ? alloc_map : fs->block_map; | ||||
| 	pb.flags = flags; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	pb.buf = block_buf + fs->blocksize * 3; | ||||
|  | ||||
| 	/* | ||||
| 	 * If GET_DBLIST is set in the flags field, then we should | ||||
| 	 * gather directory block information while we're doing the | ||||
| 	 * block move. | ||||
| 	 */ | ||||
| 	if (flags & EXT2_BMOVE_GET_DBLIST) { | ||||
| 		ext2fs_free_dblist(fs->dblist); | ||||
| 		fs->dblist = NULL; | ||||
| 		retval = ext2fs_init_dblist(fs, 0); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_next_inode(scan, &ino, &inode); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	while (ino) { | ||||
| 		if ((inode.i_links_count == 0) || | ||||
| 		    !ext2fs_inode_has_valid_blocks(&inode)) | ||||
| 			goto next; | ||||
|  | ||||
| 		pb.ino = ino; | ||||
| 		pb.inode = &inode; | ||||
|  | ||||
| 		pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) && | ||||
| 			      flags & EXT2_BMOVE_GET_DBLIST); | ||||
|  | ||||
| 		retval = ext2fs_block_iterate2(fs, ino, 0, block_buf, | ||||
| 					      process_block, &pb); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		if (pb.error) | ||||
| 			return pb.error; | ||||
|  | ||||
| 	next: | ||||
| 		retval = ext2fs_get_next_inode(scan, &ino, &inode); | ||||
| 		if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) | ||||
| 			goto next; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,86 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * brel.h | ||||
|  * | ||||
|  * Copyright (C) 1996, 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| struct ext2_block_relocate_entry { | ||||
| 	blk_t	new; | ||||
| 	__s16	offset; | ||||
| 	__u16	flags; | ||||
| 	union { | ||||
| 		blk_t		block_ref; | ||||
| 		ext2_ino_t	inode_ref; | ||||
| 	} owner; | ||||
| }; | ||||
|  | ||||
| #define RELOCATE_TYPE_REF  0x0007 | ||||
| #define RELOCATE_BLOCK_REF 0x0001 | ||||
| #define RELOCATE_INODE_REF 0x0002 | ||||
|  | ||||
| typedef struct ext2_block_relocation_table *ext2_brel; | ||||
|  | ||||
| struct ext2_block_relocation_table { | ||||
| 	__u32	magic; | ||||
| 	char	*name; | ||||
| 	blk_t	current; | ||||
| 	void	*priv_data; | ||||
|  | ||||
| 	/* | ||||
| 	 * Add a block relocation entry. | ||||
| 	 */ | ||||
| 	errcode_t (*put)(ext2_brel brel, blk_t old, | ||||
| 			      struct ext2_block_relocate_entry *ent); | ||||
|  | ||||
| 	/* | ||||
| 	 * Get a block relocation entry. | ||||
| 	 */ | ||||
| 	errcode_t (*get)(ext2_brel brel, blk_t old, | ||||
| 			      struct ext2_block_relocate_entry *ent); | ||||
|  | ||||
| 	/* | ||||
| 	 * Initialize for iterating over the block relocation entries. | ||||
| 	 */ | ||||
| 	errcode_t (*start_iter)(ext2_brel brel); | ||||
|  | ||||
| 	/* | ||||
| 	 * The iterator function for the inode relocation entries. | ||||
| 	 * Returns an inode number of 0 when out of entries. | ||||
| 	 */ | ||||
| 	errcode_t (*next)(ext2_brel brel, blk_t *old, | ||||
| 			  struct ext2_block_relocate_entry *ent); | ||||
|  | ||||
| 	/* | ||||
| 	 * Move the inode relocation table from one block number to | ||||
| 	 * another. | ||||
| 	 */ | ||||
| 	errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new); | ||||
|  | ||||
| 	/* | ||||
| 	 * Remove a block relocation entry. | ||||
| 	 */ | ||||
| 	errcode_t (*delete)(ext2_brel brel, blk_t old); | ||||
|  | ||||
|  | ||||
| 	/* | ||||
| 	 * Free the block relocation table. | ||||
| 	 */ | ||||
| 	errcode_t (*free)(ext2_brel brel); | ||||
| }; | ||||
|  | ||||
| errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block, | ||||
| 				    ext2_brel *brel); | ||||
|  | ||||
| #define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent)) | ||||
| #define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent)) | ||||
| #define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel))) | ||||
| #define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent)) | ||||
| #define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new)) | ||||
| #define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old)) | ||||
| #define ext2fs_brel_free(brel) ((brel)->free((brel))) | ||||
| @@ -1,196 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * brel_ma.c | ||||
|  * | ||||
|  * Copyright (C) 1996, 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * TODO: rewrite to not use a direct array!!!  (Fortunately this | ||||
|  * module isn't really used yet.) | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
| #include "brel.h" | ||||
|  | ||||
| static errcode_t bma_put(ext2_brel brel, blk_t old, | ||||
| 			struct ext2_block_relocate_entry *ent); | ||||
| static errcode_t bma_get(ext2_brel brel, blk_t old, | ||||
| 			struct ext2_block_relocate_entry *ent); | ||||
| static errcode_t bma_start_iter(ext2_brel brel); | ||||
| static errcode_t bma_next(ext2_brel brel, blk_t *old, | ||||
| 			 struct ext2_block_relocate_entry *ent); | ||||
| static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new); | ||||
| static errcode_t bma_delete(ext2_brel brel, blk_t old); | ||||
| static errcode_t bma_free(ext2_brel brel); | ||||
|  | ||||
| struct brel_ma { | ||||
| 	__u32 magic; | ||||
| 	blk_t max_block; | ||||
| 	struct ext2_block_relocate_entry *entries; | ||||
| }; | ||||
|  | ||||
| errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block, | ||||
| 				      ext2_brel *new_brel) | ||||
| { | ||||
| 	ext2_brel		brel = 0; | ||||
| 	errcode_t	retval; | ||||
| 	struct brel_ma	*ma = 0; | ||||
| 	size_t		size; | ||||
|  | ||||
| 	*new_brel = 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate memory structures | ||||
| 	 */ | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table), | ||||
| 				&brel); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(brel, 0, sizeof(struct ext2_block_relocation_table)); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(strlen(name)+1, &brel->name); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	strcpy(brel->name, name); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(ma, 0, sizeof(struct brel_ma)); | ||||
| 	brel->priv_data = ma; | ||||
|  | ||||
| 	size = (size_t) (sizeof(struct ext2_block_relocate_entry) * | ||||
| 			 (max_block+1)); | ||||
| 	retval = ext2fs_get_mem(size, &ma->entries); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(ma->entries, 0, size); | ||||
| 	ma->max_block = max_block; | ||||
|  | ||||
| 	/* | ||||
| 	 * Fill in the brel data structure | ||||
| 	 */ | ||||
| 	brel->put = bma_put; | ||||
| 	brel->get = bma_get; | ||||
| 	brel->start_iter = bma_start_iter; | ||||
| 	brel->next = bma_next; | ||||
| 	brel->move = bma_move; | ||||
| 	brel->delete = bma_delete; | ||||
| 	brel->free = bma_free; | ||||
|  | ||||
| 	*new_brel = brel; | ||||
| 	return 0; | ||||
|  | ||||
| errout: | ||||
| 	bma_free(brel); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_put(ext2_brel brel, blk_t old, | ||||
| 			struct ext2_block_relocate_entry *ent) | ||||
| { | ||||
| 	struct brel_ma	*ma; | ||||
|  | ||||
| 	ma = brel->priv_data; | ||||
| 	if (old > ma->max_block) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	ma->entries[(unsigned)old] = *ent; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_get(ext2_brel brel, blk_t old, | ||||
| 			struct ext2_block_relocate_entry *ent) | ||||
| { | ||||
| 	struct brel_ma	*ma; | ||||
|  | ||||
| 	ma = brel->priv_data; | ||||
| 	if (old > ma->max_block) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned)old].new == 0) | ||||
| 		return ENOENT; | ||||
| 	*ent = ma->entries[old]; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_start_iter(ext2_brel brel) | ||||
| { | ||||
| 	brel->current = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_next(ext2_brel brel, blk_t *old, | ||||
| 			  struct ext2_block_relocate_entry *ent) | ||||
| { | ||||
| 	struct brel_ma	*ma; | ||||
|  | ||||
| 	ma = brel->priv_data; | ||||
| 	while (++brel->current < ma->max_block) { | ||||
| 		if (ma->entries[(unsigned)brel->current].new == 0) | ||||
| 			continue; | ||||
| 		*old = brel->current; | ||||
| 		*ent = ma->entries[(unsigned)brel->current]; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*old = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new) | ||||
| { | ||||
| 	struct brel_ma	*ma; | ||||
|  | ||||
| 	ma = brel->priv_data; | ||||
| 	if ((old > ma->max_block) || (new > ma->max_block)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned)old].new == 0) | ||||
| 		return ENOENT; | ||||
| 	ma->entries[(unsigned)new] = ma->entries[old]; | ||||
| 	ma->entries[(unsigned)old].new = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_delete(ext2_brel brel, blk_t old) | ||||
| { | ||||
| 	struct brel_ma	*ma; | ||||
|  | ||||
| 	ma = brel->priv_data; | ||||
| 	if (old > ma->max_block) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned)old].new == 0) | ||||
| 		return ENOENT; | ||||
| 	ma->entries[(unsigned)old].new = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t bma_free(ext2_brel brel) | ||||
| { | ||||
| 	struct brel_ma	*ma; | ||||
|  | ||||
| 	if (!brel) | ||||
| 		return 0; | ||||
|  | ||||
| 	ma = brel->priv_data; | ||||
|  | ||||
| 	if (ma) { | ||||
| 		ext2fs_free_mem(&ma->entries); | ||||
| 		ext2fs_free_mem(&ma); | ||||
| 	} | ||||
| 	ext2fs_free_mem(&brel->name); | ||||
| 	ext2fs_free_mem(&brel); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * check_desc.c --- Check the group descriptors of an ext2 filesystem | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * This routine sanity checks the group descriptors | ||||
|  */ | ||||
| errcode_t ext2fs_check_desc(ext2_filsys fs) | ||||
| { | ||||
| 	dgrp_t i; | ||||
| 	blk_t block = fs->super->s_first_data_block; | ||||
| 	blk_t next; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	for (i = 0; i < fs->group_desc_count; i++) { | ||||
| 		next = block + fs->super->s_blocks_per_group; | ||||
| 		/* | ||||
| 		 * Check to make sure block bitmap for group is | ||||
| 		 * located within the group. | ||||
| 		 */ | ||||
| 		if (fs->group_desc[i].bg_block_bitmap < block || | ||||
| 		    fs->group_desc[i].bg_block_bitmap >= next) | ||||
| 			return EXT2_ET_GDESC_BAD_BLOCK_MAP; | ||||
| 		/* | ||||
| 		 * Check to make sure inode bitmap for group is | ||||
| 		 * located within the group | ||||
| 		 */ | ||||
| 		if (fs->group_desc[i].bg_inode_bitmap < block || | ||||
| 		    fs->group_desc[i].bg_inode_bitmap >= next) | ||||
| 			return EXT2_ET_GDESC_BAD_INODE_MAP; | ||||
| 		/* | ||||
| 		 * Check to make sure inode table for group is located | ||||
| 		 * within the group | ||||
| 		 */ | ||||
| 		if (fs->group_desc[i].bg_inode_table < block || | ||||
| 		    ((fs->group_desc[i].bg_inode_table + | ||||
| 		      fs->inode_blocks_per_group) >= next)) | ||||
| 			return EXT2_ET_GDESC_BAD_INODE_TABLE; | ||||
|  | ||||
| 		block = next; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,380 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * closefs.c --- close an ext2 filesystem | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| static int test_root(int a, int b) | ||||
| { | ||||
| 	if (a == 0) | ||||
| 		return 1; | ||||
| 	while (1) { | ||||
| 		if (a == 1) | ||||
| 			return 1; | ||||
| 		if (a % b) | ||||
| 			return 0; | ||||
| 		a = a / b; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int ext2fs_bg_has_super(ext2_filsys fs, int group_block) | ||||
| { | ||||
| 	if (!(fs->super->s_feature_ro_compat & | ||||
| 	      EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (test_root(group_block, 3) || (test_root(group_block, 5)) || | ||||
| 	    test_root(group_block, 7)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int ext2fs_super_and_bgd_loc(ext2_filsys fs, | ||||
| 			     dgrp_t group, | ||||
| 			     blk_t *ret_super_blk, | ||||
| 			     blk_t *ret_old_desc_blk, | ||||
| 			     blk_t *ret_new_desc_blk, | ||||
| 			     int *ret_meta_bg) | ||||
| { | ||||
| 	blk_t	group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0; | ||||
| 	unsigned int meta_bg, meta_bg_size; | ||||
| 	int	numblocks, has_super; | ||||
| 	int	old_desc_blocks; | ||||
|  | ||||
| 	group_block = fs->super->s_first_data_block + | ||||
| 		(group * fs->super->s_blocks_per_group); | ||||
|  | ||||
| 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) | ||||
| 		old_desc_blocks = fs->super->s_first_meta_bg; | ||||
| 	else | ||||
| 		old_desc_blocks = | ||||
| 			fs->desc_blocks + fs->super->s_reserved_gdt_blocks; | ||||
|  | ||||
| 	if (group == fs->group_desc_count-1) { | ||||
| 		numblocks = (fs->super->s_blocks_count - | ||||
| 			     fs->super->s_first_data_block) % | ||||
| 			fs->super->s_blocks_per_group; | ||||
| 		if (!numblocks) | ||||
| 			numblocks = fs->super->s_blocks_per_group; | ||||
| 	} else | ||||
| 		numblocks = fs->super->s_blocks_per_group; | ||||
|  | ||||
| 	has_super = ext2fs_bg_has_super(fs, group); | ||||
|  | ||||
| 	if (has_super) { | ||||
| 		super_blk = group_block; | ||||
| 		numblocks--; | ||||
| 	} | ||||
| 	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc)); | ||||
| 	meta_bg = group / meta_bg_size; | ||||
|  | ||||
| 	if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) || | ||||
| 	    (meta_bg < fs->super->s_first_meta_bg)) { | ||||
| 		if (has_super) { | ||||
| 			old_desc_blk = group_block + 1; | ||||
| 			numblocks -= old_desc_blocks; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (((group % meta_bg_size) == 0) || | ||||
| 		    ((group % meta_bg_size) == 1) || | ||||
| 		    ((group % meta_bg_size) == (meta_bg_size-1))) { | ||||
| 			if (has_super) | ||||
| 				has_super = 1; | ||||
| 			new_desc_blk = group_block + has_super; | ||||
| 			numblocks--; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	numblocks -= 2 + fs->inode_blocks_per_group; | ||||
|  | ||||
| 	if (ret_super_blk) | ||||
| 		*ret_super_blk = super_blk; | ||||
| 	if (ret_old_desc_blk) | ||||
| 		*ret_old_desc_blk = old_desc_blk; | ||||
| 	if (ret_new_desc_blk) | ||||
| 		*ret_new_desc_blk = new_desc_blk; | ||||
| 	if (ret_meta_bg) | ||||
| 		*ret_meta_bg = meta_bg; | ||||
| 	return numblocks; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This function forces out the primary superblock.  We need to only | ||||
|  * write out those fields which we have changed, since if the | ||||
|  * filesystem is mounted, it may have changed some of the other | ||||
|  * fields. | ||||
|  * | ||||
|  * It takes as input a superblock which has already been byte swapped | ||||
|  * (if necessary). | ||||
|  * | ||||
|  */ | ||||
| static errcode_t write_primary_superblock(ext2_filsys fs, | ||||
| 					  struct ext2_super_block *super) | ||||
| { | ||||
| 	__u16		*old_super, *new_super; | ||||
| 	int		check_idx, write_idx, size; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (!fs->io->manager->write_byte || !fs->orig_super) { | ||||
| 		io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); | ||||
| 		retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE, | ||||
| 					      super); | ||||
| 		io_channel_set_blksize(fs->io, fs->blocksize); | ||||
| 		return retval; | ||||
| 	} | ||||
|  | ||||
| 	old_super = (__u16 *) fs->orig_super; | ||||
| 	new_super = (__u16 *) super; | ||||
|  | ||||
| 	for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { | ||||
| 		if (old_super[check_idx] == new_super[check_idx]) | ||||
| 			continue; | ||||
| 		write_idx = check_idx; | ||||
| 		for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) | ||||
| 			if (old_super[check_idx] == new_super[check_idx]) | ||||
| 				break; | ||||
| 		size = 2 * (check_idx - write_idx); | ||||
| 		retval = io_channel_write_byte(fs->io, | ||||
| 			       SUPERBLOCK_OFFSET + (2 * write_idx), size, | ||||
| 					       new_super + write_idx); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	memcpy(fs->orig_super, super, SUPERBLOCK_SIZE); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Updates the revision to EXT2_DYNAMIC_REV | ||||
|  */ | ||||
| void ext2fs_update_dynamic_rev(ext2_filsys fs) | ||||
| { | ||||
| 	struct ext2_super_block *sb = fs->super; | ||||
|  | ||||
| 	if (sb->s_rev_level > EXT2_GOOD_OLD_REV) | ||||
| 		return; | ||||
|  | ||||
| 	sb->s_rev_level = EXT2_DYNAMIC_REV; | ||||
| 	sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; | ||||
| 	sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; | ||||
| 	/* s_uuid is handled by e2fsck already */ | ||||
| 	/* other fields should be left alone */ | ||||
| } | ||||
|  | ||||
| static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group, | ||||
| 				    blk_t group_block, | ||||
| 				    struct ext2_super_block *super_shadow) | ||||
| { | ||||
| 	dgrp_t	sgrp = group; | ||||
|  | ||||
| 	if (sgrp > ((1 << 16) - 1)) | ||||
| 		sgrp = (1 << 16) - 1; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) | ||||
| 		super_shadow->s_block_group_nr = ext2fs_swab16(sgrp); | ||||
| 	else | ||||
| #endif | ||||
| 		fs->super->s_block_group_nr = sgrp; | ||||
|  | ||||
| 	return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE, | ||||
| 				    super_shadow); | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_flush(ext2_filsys fs) | ||||
| { | ||||
| 	dgrp_t		i; | ||||
| 	blk_t		group_block; | ||||
| 	errcode_t	retval; | ||||
| 	unsigned long	fs_state; | ||||
| 	struct ext2_super_block *super_shadow = NULL; | ||||
| 	struct ext2_group_desc *group_shadow = NULL; | ||||
| 	char	*group_ptr; | ||||
| 	int	old_desc_blocks; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	dgrp_t		j; | ||||
| 	struct ext2_group_desc *s, *t; | ||||
| #endif | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	fs_state = fs->super->s_state; | ||||
|  | ||||
| 	fs->super->s_wtime = time(NULL); | ||||
| 	fs->super->s_block_group_nr = 0; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) { | ||||
| 		retval = EXT2_ET_NO_MEMORY; | ||||
| 		retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 		retval = ext2fs_get_mem((size_t)(fs->blocksize * | ||||
| 						 fs->desc_blocks), | ||||
| 					&group_shadow); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 		memset(group_shadow, 0, (size_t) fs->blocksize * | ||||
| 		       fs->desc_blocks); | ||||
|  | ||||
| 		/* swap the group descriptors */ | ||||
| 		for (j=0, s=fs->group_desc, t=group_shadow; | ||||
| 		     j < fs->group_desc_count; j++, t++, s++) { | ||||
| 			*t = *s; | ||||
| 			ext2fs_swap_group_desc(t); | ||||
| 		} | ||||
| 	} else { | ||||
| 		super_shadow = fs->super; | ||||
| 		group_shadow = fs->group_desc; | ||||
| 	} | ||||
| #else | ||||
| 	super_shadow = fs->super; | ||||
| 	group_shadow = fs->group_desc; | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	 * If this is an external journal device, don't write out the | ||||
| 	 * block group descriptors or any of the backup superblocks | ||||
| 	 */ | ||||
| 	if (fs->super->s_feature_incompat & | ||||
| 	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) | ||||
| 		goto write_primary_superblock_only; | ||||
|  | ||||
| 	/* | ||||
| 	 * Set the state of the FS to be non-valid.  (The state has | ||||
| 	 * already been backed up earlier, and will be restored after | ||||
| 	 * we write out the backup superblocks.) | ||||
| 	 */ | ||||
| 	fs->super->s_state &= ~EXT2_VALID_FS; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) { | ||||
| 		*super_shadow = *fs->super; | ||||
| 		ext2fs_swap_super(super_shadow); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	 * Write out the master group descriptors, and the backup | ||||
| 	 * superblocks and group descriptors. | ||||
| 	 */ | ||||
| 	group_block = fs->super->s_first_data_block; | ||||
| 	group_ptr = (char *) group_shadow; | ||||
| 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) | ||||
| 		old_desc_blocks = fs->super->s_first_meta_bg; | ||||
| 	else | ||||
| 		old_desc_blocks = fs->desc_blocks; | ||||
|  | ||||
| 	for (i = 0; i < fs->group_desc_count; i++) { | ||||
| 		blk_t	super_blk, old_desc_blk, new_desc_blk; | ||||
| 		int	meta_bg; | ||||
|  | ||||
| 		ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk, | ||||
| 					 &new_desc_blk, &meta_bg); | ||||
|  | ||||
| 		if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) { | ||||
| 			retval = write_backup_super(fs, i, super_blk, | ||||
| 						    super_shadow); | ||||
| 			if (retval) | ||||
| 				goto errout; | ||||
| 		} | ||||
| 		if (fs->flags & EXT2_FLAG_SUPER_ONLY) | ||||
| 			continue; | ||||
| 		if ((old_desc_blk) && | ||||
| 		    (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) { | ||||
| 			retval = io_channel_write_blk(fs->io, | ||||
| 			      old_desc_blk, old_desc_blocks, group_ptr); | ||||
| 			if (retval) | ||||
| 				goto errout; | ||||
| 		} | ||||
| 		if (new_desc_blk) { | ||||
| 			retval = io_channel_write_blk(fs->io, new_desc_blk, | ||||
| 				1, group_ptr + (meta_bg*fs->blocksize)); | ||||
| 			if (retval) | ||||
| 				goto errout; | ||||
| 		} | ||||
| 	} | ||||
| 	fs->super->s_block_group_nr = 0; | ||||
| 	fs->super->s_state = fs_state; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) { | ||||
| 		*super_shadow = *fs->super; | ||||
| 		ext2fs_swap_super(super_shadow); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	 * If the write_bitmaps() function is present, call it to | ||||
| 	 * flush the bitmaps.  This is done this way so that a simple | ||||
| 	 * program that doesn't mess with the bitmaps doesn't need to | ||||
| 	 * drag in the bitmaps.c code. | ||||
| 	 */ | ||||
| 	if (fs->write_bitmaps) { | ||||
| 		retval = fs->write_bitmaps(fs); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 	} | ||||
|  | ||||
| write_primary_superblock_only: | ||||
| 	/* | ||||
| 	 * Write out master superblock.  This has to be done | ||||
| 	 * separately, since it is located at a fixed location | ||||
| 	 * (SUPERBLOCK_OFFSET).  We flush all other pending changes | ||||
| 	 * out to disk first, just to avoid a race condition with an | ||||
| 	 * insy-tinsy window.... | ||||
| 	 */ | ||||
| 	retval = io_channel_flush(fs->io); | ||||
| 	retval = write_primary_superblock(fs, super_shadow); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
|  | ||||
| 	fs->flags &= ~EXT2_FLAG_DIRTY; | ||||
|  | ||||
| 	retval = io_channel_flush(fs->io); | ||||
| errout: | ||||
| 	fs->super->s_state = fs_state; | ||||
| 	if (fs->flags & EXT2_FLAG_SWAP_BYTES) { | ||||
| 		if (super_shadow) | ||||
| 			ext2fs_free_mem(&super_shadow); | ||||
| 		if (group_shadow) | ||||
| 			ext2fs_free_mem(&group_shadow); | ||||
| 	} | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_close(ext2_filsys fs) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (fs->flags & EXT2_FLAG_DIRTY) { | ||||
| 		retval = ext2fs_flush(fs); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	if (fs->write_bitmaps) { | ||||
| 		retval = fs->write_bitmaps(fs); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	ext2fs_free(fs); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * cmp_bitmaps.c --- routines to compare inode and block bitmaps. | ||||
|  * | ||||
|  * Copyright (C) 1995 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, | ||||
| 				      ext2fs_block_bitmap bm2) | ||||
| { | ||||
| 	blk_t	i; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP); | ||||
| 	EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP); | ||||
|  | ||||
| 	if ((bm1->start != bm2->start) || | ||||
| 	    (bm1->end != bm2->end) || | ||||
| 	    (memcmp(bm1->bitmap, bm2->bitmap, | ||||
| 		    (size_t) (bm1->end - bm1->start)/8))) | ||||
| 		return EXT2_ET_NEQ_BLOCK_BITMAP; | ||||
|  | ||||
| 	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) | ||||
| 		if (ext2fs_fast_test_block_bitmap(bm1, i) != | ||||
| 		    ext2fs_fast_test_block_bitmap(bm2, i)) | ||||
| 			return EXT2_ET_NEQ_BLOCK_BITMAP; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, | ||||
| 				      ext2fs_inode_bitmap bm2) | ||||
| { | ||||
| 	ext2_ino_t	i; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP); | ||||
| 	EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP); | ||||
|  | ||||
| 	if ((bm1->start != bm2->start) || | ||||
| 	    (bm1->end != bm2->end) || | ||||
| 	    (memcmp(bm1->bitmap, bm2->bitmap, | ||||
| 		    (size_t) (bm1->end - bm1->start)/8))) | ||||
| 		return EXT2_ET_NEQ_INODE_BITMAP; | ||||
|  | ||||
| 	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) | ||||
| 		if (ext2fs_fast_test_inode_bitmap(bm1, i) != | ||||
| 		    ext2fs_fast_test_inode_bitmap(bm2, i)) | ||||
| 			return EXT2_ET_NEQ_INODE_BITMAP; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,260 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dblist.c -- directory block list functions | ||||
|  * | ||||
|  * Copyright 1997 by Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| static int dir_block_cmp(const void *a, const void *b); | ||||
|  | ||||
| /* | ||||
|  * Returns the number of directories in the filesystem as reported by | ||||
|  * the group descriptors.  Of course, the group descriptors could be | ||||
|  * wrong! | ||||
|  */ | ||||
| errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs) | ||||
| { | ||||
| 	dgrp_t	i; | ||||
| 	ext2_ino_t	num_dirs, max_dirs; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	num_dirs = 0; | ||||
| 	max_dirs = fs->super->s_inodes_per_group; | ||||
| 	for (i = 0; i < fs->group_desc_count; i++) { | ||||
| 		if (fs->group_desc[i].bg_used_dirs_count > max_dirs) | ||||
| 			num_dirs += max_dirs / 8; | ||||
| 		else | ||||
| 			num_dirs += fs->group_desc[i].bg_used_dirs_count; | ||||
| 	} | ||||
| 	if (num_dirs > fs->super->s_inodes_count) | ||||
| 		num_dirs = fs->super->s_inodes_count; | ||||
|  | ||||
| 	*ret_num_dirs = num_dirs; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * helper function for making a new directory block list (for | ||||
|  * initialize and copy). | ||||
|  */ | ||||
| static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count, | ||||
| 			     struct ext2_db_entry *list, | ||||
| 			     ext2_dblist *ret_dblist) | ||||
| { | ||||
| 	ext2_dblist	dblist; | ||||
| 	errcode_t	retval; | ||||
| 	size_t		len; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if ((ret_dblist == 0) && fs->dblist && | ||||
| 	    (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST)) | ||||
| 		return 0; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	memset(dblist, 0, sizeof(struct ext2_struct_dblist)); | ||||
|  | ||||
| 	dblist->magic = EXT2_ET_MAGIC_DBLIST; | ||||
| 	dblist->fs = fs; | ||||
| 	if (size) | ||||
| 		dblist->size = size; | ||||
| 	else { | ||||
| 		retval = ext2fs_get_num_dirs(fs, &dblist->size); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 		dblist->size = (dblist->size * 2) + 12; | ||||
| 	} | ||||
| 	len = (size_t) sizeof(struct ext2_db_entry) * dblist->size; | ||||
| 	dblist->count = count; | ||||
| 	retval = ext2fs_get_mem(len, &dblist->list); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	if (list) | ||||
| 		memcpy(dblist->list, list, len); | ||||
| 	else | ||||
| 		memset(dblist->list, 0, len); | ||||
| 	if (ret_dblist) | ||||
| 		*ret_dblist = dblist; | ||||
| 	else | ||||
| 		fs->dblist = dblist; | ||||
| 	return 0; | ||||
| cleanup: | ||||
| 	ext2fs_free_mem(&dblist); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Initialize a directory block list | ||||
|  */ | ||||
| errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist) | ||||
| { | ||||
| 	ext2_dblist	dblist; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	retval = make_dblist(fs, 0, 0, 0, &dblist); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	dblist->sorted = 1; | ||||
| 	if (ret_dblist) | ||||
| 		*ret_dblist = dblist; | ||||
| 	else | ||||
| 		fs->dblist = dblist; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Copy a directory block list | ||||
|  */ | ||||
| errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest) | ||||
| { | ||||
| 	ext2_dblist	dblist; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	retval = make_dblist(src->fs, src->size, src->count, src->list, | ||||
| 			     &dblist); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	dblist->sorted = src->sorted; | ||||
| 	*dest = dblist; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Close a directory block list | ||||
|  * | ||||
|  * (moved to closefs.c) | ||||
|  */ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Add a directory block to the directory block list | ||||
|  */ | ||||
| errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, | ||||
| 			       int blockcnt) | ||||
| { | ||||
| 	struct ext2_db_entry	*new_entry; | ||||
| 	errcode_t		retval; | ||||
| 	unsigned long		old_size; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); | ||||
|  | ||||
| 	if (dblist->count >= dblist->size) { | ||||
| 		old_size = dblist->size * sizeof(struct ext2_db_entry); | ||||
| 		dblist->size += 100; | ||||
| 		retval = ext2fs_resize_mem(old_size, (size_t) dblist->size * | ||||
| 					   sizeof(struct ext2_db_entry), | ||||
| 					   &dblist->list); | ||||
| 		if (retval) { | ||||
| 			dblist->size -= 100; | ||||
| 			return retval; | ||||
| 		} | ||||
| 	} | ||||
| 	new_entry = dblist->list + ( (int) dblist->count++); | ||||
| 	new_entry->blk = blk; | ||||
| 	new_entry->ino = ino; | ||||
| 	new_entry->blockcnt = blockcnt; | ||||
|  | ||||
| 	dblist->sorted = 0; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Change the directory block to the directory block list | ||||
|  */ | ||||
| errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, | ||||
| 			       int blockcnt) | ||||
| { | ||||
| 	dgrp_t			i; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); | ||||
|  | ||||
| 	for (i=0; i < dblist->count; i++) { | ||||
| 		if ((dblist->list[i].ino != ino) || | ||||
| 		    (dblist->list[i].blockcnt != blockcnt)) | ||||
| 			continue; | ||||
| 		dblist->list[i].blk = blk; | ||||
| 		dblist->sorted = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return EXT2_ET_DB_NOT_FOUND; | ||||
| } | ||||
|  | ||||
| void ext2fs_dblist_sort(ext2_dblist dblist, | ||||
| 			int (*sortfunc)(const void *, | ||||
| 						    const void *)) | ||||
| { | ||||
| 	if (!sortfunc) | ||||
| 		sortfunc = dir_block_cmp; | ||||
| 	qsort(dblist->list, (size_t) dblist->count, | ||||
| 	      sizeof(struct ext2_db_entry), sortfunc); | ||||
| 	dblist->sorted = 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function iterates over the directory block list | ||||
|  */ | ||||
| errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, | ||||
| 				int (*func)(ext2_filsys fs, | ||||
| 					    struct ext2_db_entry *db_info, | ||||
| 					    void	*priv_data), | ||||
| 				void *priv_data) | ||||
| { | ||||
| 	ext2_ino_t	i; | ||||
| 	int		ret; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); | ||||
|  | ||||
| 	if (!dblist->sorted) | ||||
| 		ext2fs_dblist_sort(dblist, 0); | ||||
| 	for (i=0; i < dblist->count; i++) { | ||||
| 		ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data); | ||||
| 		if (ret & DBLIST_ABORT) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int dir_block_cmp(const void *a, const void *b) | ||||
| { | ||||
| 	const struct ext2_db_entry *db_a = | ||||
| 		(const struct ext2_db_entry *) a; | ||||
| 	const struct ext2_db_entry *db_b = | ||||
| 		(const struct ext2_db_entry *) b; | ||||
|  | ||||
| 	if (db_a->blk != db_b->blk) | ||||
| 		return (int) (db_a->blk - db_b->blk); | ||||
|  | ||||
| 	if (db_a->ino != db_b->ino) | ||||
| 		return (int) (db_a->ino - db_b->ino); | ||||
|  | ||||
| 	return (int) (db_a->blockcnt - db_b->blockcnt); | ||||
| } | ||||
|  | ||||
| int ext2fs_dblist_count(ext2_dblist dblist) | ||||
| { | ||||
| 	return (int) dblist->count; | ||||
| } | ||||
| @@ -1,76 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dblist_dir.c --- iterate by directory entry | ||||
|  * | ||||
|  * Copyright 1997 by Theodore Ts'o | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info, | ||||
| 		       void *priv_data); | ||||
|  | ||||
| errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist, | ||||
| 				    int	flags, | ||||
| 				    char	*block_buf, | ||||
| 				    int (*func)(ext2_ino_t dir, | ||||
| 						int	entry, | ||||
| 						struct ext2_dir_entry *dirent, | ||||
| 						int	offset, | ||||
| 						int	blocksize, | ||||
| 						char	*buf, | ||||
| 						void	*priv_data), | ||||
| 				    void *priv_data) | ||||
| { | ||||
| 	errcode_t		retval; | ||||
| 	struct dir_context	ctx; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); | ||||
|  | ||||
| 	ctx.dir = 0; | ||||
| 	ctx.flags = flags; | ||||
| 	if (block_buf) | ||||
| 		ctx.buf = block_buf; | ||||
| 	else { | ||||
| 		retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	ctx.func = func; | ||||
| 	ctx.priv_data = priv_data; | ||||
| 	ctx.errcode = 0; | ||||
|  | ||||
| 	retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx); | ||||
|  | ||||
| 	if (!block_buf) | ||||
| 		ext2fs_free_mem(&ctx.buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	return ctx.errcode; | ||||
| } | ||||
|  | ||||
| static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info, | ||||
| 		       void *priv_data) | ||||
| { | ||||
| 	struct dir_context	*ctx; | ||||
|  | ||||
| 	ctx = (struct dir_context *) priv_data; | ||||
| 	ctx->dir = db_info->ino; | ||||
|  | ||||
| 	return ext2fs_process_dir_block(fs, &db_info->blk, | ||||
| 					db_info->blockcnt, 0, 0, priv_data); | ||||
| } | ||||
| @@ -1,219 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dir_iterate.c --- ext2fs directory iteration operations | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| /* | ||||
|  * This function checks to see whether or not a potential deleted | ||||
|  * directory entry looks valid.  What we do is check the deleted entry | ||||
|  * and each successive entry to make sure that they all look valid and | ||||
|  * that the last deleted entry ends at the beginning of the next | ||||
|  * undeleted entry.  Returns 1 if the deleted entry looks valid, zero | ||||
|  * if not valid. | ||||
|  */ | ||||
| static int ext2fs_validate_entry(char *buf, int offset, int final_offset) | ||||
| { | ||||
| 	struct ext2_dir_entry *dirent; | ||||
|  | ||||
| 	while (offset < final_offset) { | ||||
| 		dirent = (struct ext2_dir_entry *)(buf + offset); | ||||
| 		offset += dirent->rec_len; | ||||
| 		if ((dirent->rec_len < 8) || | ||||
| 		    ((dirent->rec_len % 4) != 0) || | ||||
| 		    (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	return (offset == final_offset); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_dir_iterate2(ext2_filsys fs, | ||||
| 			      ext2_ino_t dir, | ||||
| 			      int flags, | ||||
| 			      char *block_buf, | ||||
| 			      int (*func)(ext2_ino_t	dir, | ||||
| 					  int		entry, | ||||
| 					  struct ext2_dir_entry *dirent, | ||||
| 					  int	offset, | ||||
| 					  int	blocksize, | ||||
| 					  char	*buf, | ||||
| 					  void	*priv_data), | ||||
| 			      void *priv_data) | ||||
| { | ||||
| 	struct		dir_context	ctx; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	retval = ext2fs_check_directory(fs, dir); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	ctx.dir = dir; | ||||
| 	ctx.flags = flags; | ||||
| 	if (block_buf) | ||||
| 		ctx.buf = block_buf; | ||||
| 	else { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize, &ctx.buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	ctx.func = func; | ||||
| 	ctx.priv_data = priv_data; | ||||
| 	ctx.errcode = 0; | ||||
| 	retval = ext2fs_block_iterate2(fs, dir, 0, 0, | ||||
| 				       ext2fs_process_dir_block, &ctx); | ||||
| 	if (!block_buf) | ||||
| 		ext2fs_free_mem(&ctx.buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	return ctx.errcode; | ||||
| } | ||||
|  | ||||
| struct xlate { | ||||
| 	int (*func)(struct ext2_dir_entry *dirent, | ||||
| 		    int		offset, | ||||
| 		    int		blocksize, | ||||
| 		    char	*buf, | ||||
| 		    void	*priv_data); | ||||
| 	void *real_private; | ||||
| }; | ||||
|  | ||||
| static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)), | ||||
| 		      int entry EXT2FS_ATTR((unused)), | ||||
| 		      struct ext2_dir_entry *dirent, int offset, | ||||
| 		      int blocksize, char *buf, void *priv_data) | ||||
| { | ||||
| 	struct xlate *xl = (struct xlate *) priv_data; | ||||
|  | ||||
| 	return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private); | ||||
| } | ||||
|  | ||||
| extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, | ||||
| 			      ext2_ino_t dir, | ||||
| 			      int flags, | ||||
| 			      char *block_buf, | ||||
| 			      int (*func)(struct ext2_dir_entry *dirent, | ||||
| 					  int	offset, | ||||
| 					  int	blocksize, | ||||
| 					  char	*buf, | ||||
| 					  void	*priv_data), | ||||
| 			      void *priv_data) | ||||
| { | ||||
| 	struct xlate xl; | ||||
|  | ||||
| 	xl.real_private = priv_data; | ||||
| 	xl.func = func; | ||||
|  | ||||
| 	return ext2fs_dir_iterate2(fs, dir, flags, block_buf, | ||||
| 				   xlate_func, &xl); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Helper function which is private to this module.  Used by | ||||
|  * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate() | ||||
|  */ | ||||
| int ext2fs_process_dir_block(ext2_filsys fs, | ||||
| 			     blk_t	*blocknr, | ||||
| 			     e2_blkcnt_t blockcnt, | ||||
| 			     blk_t	ref_block EXT2FS_ATTR((unused)), | ||||
| 			     int	ref_offset EXT2FS_ATTR((unused)), | ||||
| 			     void	*priv_data) | ||||
| { | ||||
| 	struct dir_context *ctx = (struct dir_context *) priv_data; | ||||
| 	unsigned int	offset = 0; | ||||
| 	unsigned int	next_real_entry = 0; | ||||
| 	int		ret = 0; | ||||
| 	int		changed = 0; | ||||
| 	int		do_abort = 0; | ||||
| 	int		entry, size; | ||||
| 	struct ext2_dir_entry *dirent; | ||||
|  | ||||
| 	if (blockcnt < 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE; | ||||
|  | ||||
| 	ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf); | ||||
| 	if (ctx->errcode) | ||||
| 		return BLOCK_ABORT; | ||||
|  | ||||
| 	while (offset < fs->blocksize) { | ||||
| 		dirent = (struct ext2_dir_entry *) (ctx->buf + offset); | ||||
| 		if (((offset + dirent->rec_len) > fs->blocksize) || | ||||
| 		    (dirent->rec_len < 8) || | ||||
| 		    ((dirent->rec_len % 4) != 0) || | ||||
| 		    (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { | ||||
| 			ctx->errcode = EXT2_ET_DIR_CORRUPTED; | ||||
| 			return BLOCK_ABORT; | ||||
| 		} | ||||
| 		if (!dirent->inode && | ||||
| 		    !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) | ||||
| 			goto next; | ||||
|  | ||||
| 		ret = (ctx->func)(ctx->dir, | ||||
| 				  (next_real_entry > offset) ? | ||||
| 				  DIRENT_DELETED_FILE : entry, | ||||
| 				  dirent, offset, | ||||
| 				  fs->blocksize, ctx->buf, | ||||
| 				  ctx->priv_data); | ||||
| 		if (entry < DIRENT_OTHER_FILE) | ||||
| 			entry++; | ||||
|  | ||||
| 		if (ret & DIRENT_CHANGED) | ||||
| 			changed++; | ||||
| 		if (ret & DIRENT_ABORT) { | ||||
| 			do_abort++; | ||||
| 			break; | ||||
| 		} | ||||
| next: | ||||
| 		if (next_real_entry == offset) | ||||
| 			next_real_entry += dirent->rec_len; | ||||
|  | ||||
| 		if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) { | ||||
| 			size = ((dirent->name_len & 0xFF) + 11) & ~3; | ||||
|  | ||||
| 			if (dirent->rec_len != size)  { | ||||
| 				unsigned int final_offset; | ||||
|  | ||||
| 				final_offset = offset + dirent->rec_len; | ||||
| 				offset += size; | ||||
| 				while (offset < final_offset && | ||||
| 				       !ext2fs_validate_entry(ctx->buf, | ||||
| 							      offset, | ||||
| 							      final_offset)) | ||||
| 					offset += 4; | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| 		offset += dirent->rec_len; | ||||
| 	} | ||||
|  | ||||
| 	if (changed) { | ||||
| 		ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf); | ||||
| 		if (ctx->errcode) | ||||
| 			return BLOCK_ABORT; | ||||
| 	} | ||||
| 	if (do_abort) | ||||
| 		return BLOCK_ABORT; | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,132 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dirblock.c --- directory block routines. | ||||
|  * | ||||
|  * Copyright (C) 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, | ||||
| 				 void *buf, int flags EXT2FS_ATTR((unused))) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	char		*p, *end; | ||||
| 	struct ext2_dir_entry *dirent; | ||||
| 	unsigned int	name_len, rec_len; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	unsigned int do_swap; | ||||
| #endif | ||||
|  | ||||
| 	retval = io_channel_read_blk(fs->io, block, 1, buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES| | ||||
| 				EXT2_FLAG_SWAP_BYTES_READ)) != 0; | ||||
| #endif | ||||
| 	p = (char *) buf; | ||||
| 	end = (char *) buf + fs->blocksize; | ||||
| 	while (p < end-8) { | ||||
| 		dirent = (struct ext2_dir_entry *) p; | ||||
| #if BB_BIG_ENDIAN | ||||
| 		if (do_swap) { | ||||
| 			dirent->inode = ext2fs_swab32(dirent->inode); | ||||
| 			dirent->rec_len = ext2fs_swab16(dirent->rec_len); | ||||
| 			dirent->name_len = ext2fs_swab16(dirent->name_len); | ||||
| 		} | ||||
| #endif | ||||
| 		name_len = dirent->name_len; | ||||
| #ifdef WORDS_BIGENDIAN | ||||
| 		if (flags & EXT2_DIRBLOCK_V2_STRUCT) | ||||
| 			dirent->name_len = ext2fs_swab16(dirent->name_len); | ||||
| #endif | ||||
| 		rec_len = dirent->rec_len; | ||||
| 		if ((rec_len < 8) || (rec_len % 4)) { | ||||
| 			rec_len = 8; | ||||
| 			retval = EXT2_ET_DIR_CORRUPTED; | ||||
| 		} | ||||
| 		if (((name_len & 0xFF) + 8) > dirent->rec_len) | ||||
| 			retval = EXT2_ET_DIR_CORRUPTED; | ||||
| 		p += rec_len; | ||||
| 	} | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, | ||||
| 				 void *buf) | ||||
| { | ||||
| 	return ext2fs_read_dir_block2(fs, block, buf, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, | ||||
| 				  void *inbuf, int flags EXT2FS_ATTR((unused))) | ||||
| { | ||||
| #if BB_BIG_ENDIAN | ||||
| 	int		do_swap = 0; | ||||
| 	errcode_t	retval; | ||||
| 	char		*p, *end; | ||||
| 	char		*buf = NULL; | ||||
| 	struct ext2_dir_entry *dirent; | ||||
|  | ||||
| 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) | ||||
| 		do_swap = 1; | ||||
|  | ||||
| #ifndef WORDS_BIGENDIAN | ||||
| 	if (!do_swap) | ||||
| 		return io_channel_write_blk(fs->io, block, 1, (char *) inbuf); | ||||
| #endif | ||||
|  | ||||
| 	retval = ext2fs_get_mem(fs->blocksize, &buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	memcpy(buf, inbuf, fs->blocksize); | ||||
| 	p = buf; | ||||
| 	end = buf + fs->blocksize; | ||||
| 	while (p < end) { | ||||
| 		dirent = (struct ext2_dir_entry *) p; | ||||
| 		if ((dirent->rec_len < 8) || | ||||
| 		    (dirent->rec_len % 4)) { | ||||
| 			ext2fs_free_mem(&buf); | ||||
| 			return EXT2_ET_DIR_CORRUPTED; | ||||
| 		} | ||||
| 		p += dirent->rec_len; | ||||
| 		if (do_swap) { | ||||
| 			dirent->inode = ext2fs_swab32(dirent->inode); | ||||
| 			dirent->rec_len = ext2fs_swab16(dirent->rec_len); | ||||
| 			dirent->name_len = ext2fs_swab16(dirent->name_len); | ||||
| 		} | ||||
| #ifdef WORDS_BIGENDIAN | ||||
| 		if (flags & EXT2_DIRBLOCK_V2_STRUCT) | ||||
| 			dirent->name_len = ext2fs_swab16(dirent->name_len); | ||||
| #endif | ||||
| 	} | ||||
| 	retval = io_channel_write_blk(fs->io, block, 1, buf); | ||||
| 	ext2fs_free_mem(&buf); | ||||
| 	return retval; | ||||
| #else | ||||
| 	return io_channel_write_blk(fs->io, block, 1, (char *) inbuf); | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, | ||||
| 				 void *inbuf) | ||||
| { | ||||
| 	return ext2fs_write_dir_block2(fs, block, inbuf, 0); | ||||
| } | ||||
| @@ -1,234 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dirhash.c -- Calculate the hash of a directory entry | ||||
|  * | ||||
|  * Copyright (c) 2001  Daniel Phillips | ||||
|  * | ||||
|  * Copyright (c) 2002 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * Keyed 32-bit hash function using TEA in a Davis-Meyer function | ||||
|  *   H0 = Key | ||||
|  *   Hi = E Mi(Hi-1) + Hi-1 | ||||
|  * | ||||
|  * (see Applied Cryptography, 2nd edition, p448). | ||||
|  * | ||||
|  * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998 | ||||
|  * | ||||
|  * This code is made available under the terms of the GPL | ||||
|  */ | ||||
| #define DELTA 0x9E3779B9 | ||||
|  | ||||
| static void TEA_transform(__u32 buf[4], __u32 const in[]) | ||||
| { | ||||
| 	__u32	sum = 0; | ||||
| 	__u32	b0 = buf[0], b1 = buf[1]; | ||||
| 	__u32	a = in[0], b = in[1], c = in[2], d = in[3]; | ||||
| 	int	n = 16; | ||||
|  | ||||
| 	do { | ||||
| 		sum += DELTA; | ||||
| 		b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); | ||||
| 		b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); | ||||
| 	} while (--n); | ||||
|  | ||||
| 	buf[0] += b0; | ||||
| 	buf[1] += b1; | ||||
| } | ||||
|  | ||||
| /* F, G and H are basic MD4 functions: selection, majority, parity */ | ||||
| #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) | ||||
| #define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) | ||||
| #define H(x, y, z) ((x) ^ (y) ^ (z)) | ||||
|  | ||||
| /* | ||||
|  * The generic round function.  The application is so specific that | ||||
|  * we don't bother protecting all the arguments with parens, as is generally | ||||
|  * good macro practice, in favor of extra legibility. | ||||
|  * Rotation is separate from addition to prevent recomputation | ||||
|  */ | ||||
| #define ROUND(f, a, b, c, d, x, s)	\ | ||||
| 	(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s))) | ||||
| #define K1 0 | ||||
| #define K2 013240474631UL | ||||
| #define K3 015666365641UL | ||||
|  | ||||
| /* | ||||
|  * Basic cut-down MD4 transform.  Returns only 32 bits of result. | ||||
|  */ | ||||
| static void halfMD4Transform (__u32 buf[4], __u32 const in[]) | ||||
| { | ||||
| 	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3]; | ||||
|  | ||||
| 	/* Round 1 */ | ||||
| 	ROUND(F, a, b, c, d, in[0] + K1,  3); | ||||
| 	ROUND(F, d, a, b, c, in[1] + K1,  7); | ||||
| 	ROUND(F, c, d, a, b, in[2] + K1, 11); | ||||
| 	ROUND(F, b, c, d, a, in[3] + K1, 19); | ||||
| 	ROUND(F, a, b, c, d, in[4] + K1,  3); | ||||
| 	ROUND(F, d, a, b, c, in[5] + K1,  7); | ||||
| 	ROUND(F, c, d, a, b, in[6] + K1, 11); | ||||
| 	ROUND(F, b, c, d, a, in[7] + K1, 19); | ||||
|  | ||||
| 	/* Round 2 */ | ||||
| 	ROUND(G, a, b, c, d, in[1] + K2,  3); | ||||
| 	ROUND(G, d, a, b, c, in[3] + K2,  5); | ||||
| 	ROUND(G, c, d, a, b, in[5] + K2,  9); | ||||
| 	ROUND(G, b, c, d, a, in[7] + K2, 13); | ||||
| 	ROUND(G, a, b, c, d, in[0] + K2,  3); | ||||
| 	ROUND(G, d, a, b, c, in[2] + K2,  5); | ||||
| 	ROUND(G, c, d, a, b, in[4] + K2,  9); | ||||
| 	ROUND(G, b, c, d, a, in[6] + K2, 13); | ||||
|  | ||||
| 	/* Round 3 */ | ||||
| 	ROUND(H, a, b, c, d, in[3] + K3,  3); | ||||
| 	ROUND(H, d, a, b, c, in[7] + K3,  9); | ||||
| 	ROUND(H, c, d, a, b, in[2] + K3, 11); | ||||
| 	ROUND(H, b, c, d, a, in[6] + K3, 15); | ||||
| 	ROUND(H, a, b, c, d, in[1] + K3,  3); | ||||
| 	ROUND(H, d, a, b, c, in[5] + K3,  9); | ||||
| 	ROUND(H, c, d, a, b, in[0] + K3, 11); | ||||
| 	ROUND(H, b, c, d, a, in[4] + K3, 15); | ||||
|  | ||||
| 	buf[0] += a; | ||||
| 	buf[1] += b; | ||||
| 	buf[2] += c; | ||||
| 	buf[3] += d; | ||||
| } | ||||
|  | ||||
| #undef ROUND | ||||
| #undef F | ||||
| #undef G | ||||
| #undef H | ||||
| #undef K1 | ||||
| #undef K2 | ||||
| #undef K3 | ||||
|  | ||||
| /* The old legacy hash */ | ||||
| static ext2_dirhash_t dx_hack_hash (const char *name, int len) | ||||
| { | ||||
| 	__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; | ||||
| 	while (len--) { | ||||
| 		__u32 hash = hash1 + (hash0 ^ (*name++ * 7152373)); | ||||
|  | ||||
| 		if (hash & 0x80000000) hash -= 0x7fffffff; | ||||
| 		hash1 = hash0; | ||||
| 		hash0 = hash; | ||||
| 	} | ||||
| 	return (hash0 << 1); | ||||
| } | ||||
|  | ||||
| static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) | ||||
| { | ||||
| 	__u32	pad, val; | ||||
| 	int	i; | ||||
|  | ||||
| 	pad = (__u32)len | ((__u32)len << 8); | ||||
| 	pad |= pad << 16; | ||||
|  | ||||
| 	val = pad; | ||||
| 	if (len > num*4) | ||||
| 		len = num * 4; | ||||
| 	for (i=0; i < len; i++) { | ||||
| 		if ((i % 4) == 0) | ||||
| 			val = pad; | ||||
| 		val = msg[i] + (val << 8); | ||||
| 		if ((i % 4) == 3) { | ||||
| 			*buf++ = val; | ||||
| 			val = pad; | ||||
| 			num--; | ||||
| 		} | ||||
| 	} | ||||
| 	if (--num >= 0) | ||||
| 		*buf++ = val; | ||||
| 	while (--num >= 0) | ||||
| 		*buf++ = pad; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the hash of a filename.  If len is 0 and name is NULL, then | ||||
|  * this function can be used to test whether or not a hash version is | ||||
|  * supported. | ||||
|  * | ||||
|  * The seed is an 4 longword (32 bits) "secret" which can be used to | ||||
|  * uniquify a hash.  If the seed is all zero's, then some default seed | ||||
|  * may be used. | ||||
|  * | ||||
|  * A particular hash version specifies whether or not the seed is | ||||
|  * represented, and whether or not the returned hash is 32 bits or 64 | ||||
|  * bits.  32 bit hashes will return 0 for the minor hash. | ||||
|  */ | ||||
| errcode_t ext2fs_dirhash(int version, const char *name, int len, | ||||
| 			 const __u32 *seed, | ||||
| 			 ext2_dirhash_t *ret_hash, | ||||
| 			 ext2_dirhash_t *ret_minor_hash) | ||||
| { | ||||
| 	__u32	hash; | ||||
| 	__u32	minor_hash = 0; | ||||
| 	const char	*p; | ||||
| 	int		i; | ||||
| 	__u32		in[8], buf[4]; | ||||
|  | ||||
| 	/* Initialize the default seed for the hash checksum functions */ | ||||
| 	buf[0] = 0x67452301; | ||||
| 	buf[1] = 0xefcdab89; | ||||
| 	buf[2] = 0x98badcfe; | ||||
| 	buf[3] = 0x10325476; | ||||
|  | ||||
| 	/* Check to see if the seed is all zero's */ | ||||
| 	if (seed) { | ||||
| 		for (i=0; i < 4; i++) { | ||||
| 			if (seed[i]) | ||||
| 				break; | ||||
| 		} | ||||
| 		if (i < 4) | ||||
| 			memcpy(buf, seed, sizeof(buf)); | ||||
| 	} | ||||
|  | ||||
| 	switch (version) { | ||||
| 	case EXT2_HASH_LEGACY: | ||||
| 		hash = dx_hack_hash(name, len); | ||||
| 		break; | ||||
| 	case EXT2_HASH_HALF_MD4: | ||||
| 		p = name; | ||||
| 		while (len > 0) { | ||||
| 			str2hashbuf(p, len, in, 8); | ||||
| 			halfMD4Transform(buf, in); | ||||
| 			len -= 32; | ||||
| 			p += 32; | ||||
| 		} | ||||
| 		minor_hash = buf[2]; | ||||
| 		hash = buf[1]; | ||||
| 		break; | ||||
| 	case EXT2_HASH_TEA: | ||||
| 		p = name; | ||||
| 		while (len > 0) { | ||||
| 			str2hashbuf(p, len, in, 4); | ||||
| 			TEA_transform(buf, in); | ||||
| 			len -= 16; | ||||
| 			p += 16; | ||||
| 		} | ||||
| 		hash = buf[0]; | ||||
| 		minor_hash = buf[1]; | ||||
| 		break; | ||||
| 	default: | ||||
| 		*ret_hash = 0; | ||||
| 		return EXT2_ET_DIRHASH_UNSUPP; | ||||
| 	} | ||||
| 	*ret_hash = hash & ~1; | ||||
| 	if (ret_minor_hash) | ||||
| 		*ret_minor_hash = minor_hash; | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,95 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * dupfs.c --- duplicate a ext2 filesystem handle | ||||
|  * | ||||
|  * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest) | ||||
| { | ||||
| 	ext2_filsys	fs; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	*fs = *src; | ||||
| 	fs->device_name = 0; | ||||
| 	fs->super = 0; | ||||
| 	fs->orig_super = 0; | ||||
| 	fs->group_desc = 0; | ||||
| 	fs->inode_map = 0; | ||||
| 	fs->block_map = 0; | ||||
| 	fs->badblocks = 0; | ||||
| 	fs->dblist = 0; | ||||
|  | ||||
| 	io_channel_bumpcount(fs->io); | ||||
| 	if (fs->icache) | ||||
| 		fs->icache->refcount++; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	strcpy(fs->device_name, src->device_name); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memcpy(fs->super, src->super, SUPERBLOCK_SIZE); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE); | ||||
|  | ||||
| 	retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize, | ||||
| 				&fs->group_desc); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memcpy(fs->group_desc, src->group_desc, | ||||
| 	       (size_t) fs->desc_blocks * fs->blocksize); | ||||
|  | ||||
| 	if (src->inode_map) { | ||||
| 		retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 	} | ||||
| 	if (src->block_map) { | ||||
| 		retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 	} | ||||
| 	if (src->badblocks) { | ||||
| 		retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 	} | ||||
| 	if (src->dblist) { | ||||
| 		retval = ext2fs_copy_dblist(src->dblist, &fs->dblist); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 	} | ||||
| 	*dest = fs; | ||||
| 	return 0; | ||||
| errout: | ||||
| 	ext2fs_free(fs); | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,39 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * e2image.h --- header file describing the ext2 image format | ||||
|  * | ||||
|  * Copyright (C) 2000 Theodore Ts'o. | ||||
|  * | ||||
|  * Note: this uses the POSIX IO interfaces, unlike most of the other | ||||
|  * functions in this library.  So sue me. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
|  | ||||
| struct ext2_image_hdr { | ||||
| 	__u32	magic_number;	/* This must be EXT2_ET_MAGIC_E2IMAGE */ | ||||
| 	char	magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */ | ||||
| 	char	fs_hostname[64];/* Hostname of machine of image */ | ||||
| 	char	fs_netaddr[32];	/* Network address */ | ||||
| 	__u32	fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */ | ||||
| 	__u32	fs_device;	/* Device number of image */ | ||||
| 	char	fs_device_name[64]; /* Device name */ | ||||
| 	char	fs_uuid[16];	/* UUID of filesystem */ | ||||
| 	__u32	fs_blocksize;	/* Block size of the filesystem */ | ||||
| 	__u32	fs_reserved[8]; | ||||
|  | ||||
| 	__u32	image_device;	/* Device number of image file */ | ||||
| 	__u32	image_inode;	/* Inode number of image file */ | ||||
| 	__u32	image_time;	/* Time of image creation */ | ||||
| 	__u32	image_reserved[8]; | ||||
|  | ||||
| 	__u32	offset_super;	/* Byte offset of the sb and descriptors */ | ||||
| 	__u32	offset_inode;	/* Byte offset of the inode table  */ | ||||
| 	__u32	offset_inodemap; /* Byte offset of the inode bitmaps */ | ||||
| 	__u32	offset_blockmap; /* Byte offset of the inode bitmaps */ | ||||
| 	__u32	offset_reserved[8]; | ||||
| }; | ||||
| @@ -1,127 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * expand.c --- expand an ext2fs directory | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999  Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct expand_dir_struct { | ||||
| 	int		done; | ||||
| 	int		newblocks; | ||||
| 	errcode_t	err; | ||||
| }; | ||||
|  | ||||
| static int expand_dir_proc(ext2_filsys	fs, | ||||
| 			   blk_t	*blocknr, | ||||
| 			   e2_blkcnt_t	blockcnt, | ||||
| 			   blk_t	ref_block EXT2FS_ATTR((unused)), | ||||
| 			   int		ref_offset EXT2FS_ATTR((unused)), | ||||
| 			   void		*priv_data) | ||||
| { | ||||
| 	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; | ||||
| 	blk_t	new_blk; | ||||
| 	static blk_t	last_blk = 0; | ||||
| 	char		*block; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (*blocknr) { | ||||
| 		last_blk = *blocknr; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); | ||||
| 	if (retval) { | ||||
| 		es->err = retval; | ||||
| 		return BLOCK_ABORT; | ||||
| 	} | ||||
| 	if (blockcnt > 0) { | ||||
| 		retval = ext2fs_new_dir_block(fs, 0, 0, &block); | ||||
| 		if (retval) { | ||||
| 			es->err = retval; | ||||
| 			return BLOCK_ABORT; | ||||
| 		} | ||||
| 		es->done = 1; | ||||
| 		retval = ext2fs_write_dir_block(fs, new_blk, block); | ||||
| 	} else { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize, &block); | ||||
| 		if (retval) { | ||||
| 			es->err = retval; | ||||
| 			return BLOCK_ABORT; | ||||
| 		} | ||||
| 		memset(block, 0, fs->blocksize); | ||||
| 		retval = io_channel_write_blk(fs->io, new_blk, 1, block); | ||||
| 	} | ||||
| 	if (retval) { | ||||
| 		es->err = retval; | ||||
| 		return BLOCK_ABORT; | ||||
| 	} | ||||
| 	ext2fs_free_mem(&block); | ||||
| 	*blocknr = new_blk; | ||||
| 	ext2fs_block_alloc_stats(fs, new_blk, +1); | ||||
| 	es->newblocks++; | ||||
|  | ||||
| 	if (es->done) | ||||
| 		return (BLOCK_CHANGED | BLOCK_ABORT); | ||||
| 	else | ||||
| 		return BLOCK_CHANGED; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	struct expand_dir_struct es; | ||||
| 	struct ext2_inode	inode; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (!(fs->flags & EXT2_FLAG_RW)) | ||||
| 		return EXT2_ET_RO_FILSYS; | ||||
|  | ||||
| 	if (!fs->block_map) | ||||
| 		return EXT2_ET_NO_BLOCK_BITMAP; | ||||
|  | ||||
| 	retval = ext2fs_check_directory(fs, dir); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	es.done = 0; | ||||
| 	es.err = 0; | ||||
| 	es.newblocks = 0; | ||||
|  | ||||
| 	retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, | ||||
| 				       0, expand_dir_proc, &es); | ||||
|  | ||||
| 	if (es.err) | ||||
| 		return es.err; | ||||
| 	if (!es.done) | ||||
| 		return EXT2_ET_EXPAND_DIR_ERR; | ||||
|  | ||||
| 	/* | ||||
| 	 * Update the size and block count fields in the inode. | ||||
| 	 */ | ||||
| 	retval = ext2fs_read_inode(fs, dir, &inode); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	inode.i_size += fs->blocksize; | ||||
| 	inode.i_blocks += (fs->blocksize / 512) * es.newblocks; | ||||
|  | ||||
| 	retval = ext2fs_write_inode(fs, dir, &inode); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,116 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ext2_err.h: | ||||
|  * This file is automatically generated; please do not edit it. | ||||
|  */ | ||||
|  | ||||
| #define EXT2_ET_BASE                             (2133571328L) | ||||
| #define EXT2_ET_MAGIC_EXT2FS_FILSYS              (2133571329L) | ||||
| #define EXT2_ET_MAGIC_BADBLOCKS_LIST             (2133571330L) | ||||
| #define EXT2_ET_MAGIC_BADBLOCKS_ITERATE          (2133571331L) | ||||
| #define EXT2_ET_MAGIC_INODE_SCAN                 (2133571332L) | ||||
| #define EXT2_ET_MAGIC_IO_CHANNEL                 (2133571333L) | ||||
| #define EXT2_ET_MAGIC_UNIX_IO_CHANNEL            (2133571334L) | ||||
| #define EXT2_ET_MAGIC_IO_MANAGER                 (2133571335L) | ||||
| #define EXT2_ET_MAGIC_BLOCK_BITMAP               (2133571336L) | ||||
| #define EXT2_ET_MAGIC_INODE_BITMAP               (2133571337L) | ||||
| #define EXT2_ET_MAGIC_GENERIC_BITMAP             (2133571338L) | ||||
| #define EXT2_ET_MAGIC_TEST_IO_CHANNEL            (2133571339L) | ||||
| #define EXT2_ET_MAGIC_DBLIST                     (2133571340L) | ||||
| #define EXT2_ET_MAGIC_ICOUNT                     (2133571341L) | ||||
| #define EXT2_ET_MAGIC_PQ_IO_CHANNEL              (2133571342L) | ||||
| #define EXT2_ET_MAGIC_EXT2_FILE                  (2133571343L) | ||||
| #define EXT2_ET_MAGIC_E2IMAGE                    (2133571344L) | ||||
| #define EXT2_ET_MAGIC_INODE_IO_CHANNEL           (2133571345L) | ||||
| #define EXT2_ET_MAGIC_RESERVED_9                 (2133571346L) | ||||
| #define EXT2_ET_BAD_MAGIC                        (2133571347L) | ||||
| #define EXT2_ET_REV_TOO_HIGH                     (2133571348L) | ||||
| #define EXT2_ET_RO_FILSYS                        (2133571349L) | ||||
| #define EXT2_ET_GDESC_READ                       (2133571350L) | ||||
| #define EXT2_ET_GDESC_WRITE                      (2133571351L) | ||||
| #define EXT2_ET_GDESC_BAD_BLOCK_MAP              (2133571352L) | ||||
| #define EXT2_ET_GDESC_BAD_INODE_MAP              (2133571353L) | ||||
| #define EXT2_ET_GDESC_BAD_INODE_TABLE            (2133571354L) | ||||
| #define EXT2_ET_INODE_BITMAP_WRITE               (2133571355L) | ||||
| #define EXT2_ET_INODE_BITMAP_READ                (2133571356L) | ||||
| #define EXT2_ET_BLOCK_BITMAP_WRITE               (2133571357L) | ||||
| #define EXT2_ET_BLOCK_BITMAP_READ                (2133571358L) | ||||
| #define EXT2_ET_INODE_TABLE_WRITE                (2133571359L) | ||||
| #define EXT2_ET_INODE_TABLE_READ                 (2133571360L) | ||||
| #define EXT2_ET_NEXT_INODE_READ                  (2133571361L) | ||||
| #define EXT2_ET_UNEXPECTED_BLOCK_SIZE            (2133571362L) | ||||
| #define EXT2_ET_DIR_CORRUPTED                    (2133571363L) | ||||
| #define EXT2_ET_SHORT_READ                       (2133571364L) | ||||
| #define EXT2_ET_SHORT_WRITE                      (2133571365L) | ||||
| #define EXT2_ET_DIR_NO_SPACE                     (2133571366L) | ||||
| #define EXT2_ET_NO_INODE_BITMAP                  (2133571367L) | ||||
| #define EXT2_ET_NO_BLOCK_BITMAP                  (2133571368L) | ||||
| #define EXT2_ET_BAD_INODE_NUM                    (2133571369L) | ||||
| #define EXT2_ET_BAD_BLOCK_NUM                    (2133571370L) | ||||
| #define EXT2_ET_EXPAND_DIR_ERR                   (2133571371L) | ||||
| #define EXT2_ET_TOOSMALL                         (2133571372L) | ||||
| #define EXT2_ET_BAD_BLOCK_MARK                   (2133571373L) | ||||
| #define EXT2_ET_BAD_BLOCK_UNMARK                 (2133571374L) | ||||
| #define EXT2_ET_BAD_BLOCK_TEST                   (2133571375L) | ||||
| #define EXT2_ET_BAD_INODE_MARK                   (2133571376L) | ||||
| #define EXT2_ET_BAD_INODE_UNMARK                 (2133571377L) | ||||
| #define EXT2_ET_BAD_INODE_TEST                   (2133571378L) | ||||
| #define EXT2_ET_FUDGE_BLOCK_BITMAP_END           (2133571379L) | ||||
| #define EXT2_ET_FUDGE_INODE_BITMAP_END           (2133571380L) | ||||
| #define EXT2_ET_BAD_IND_BLOCK                    (2133571381L) | ||||
| #define EXT2_ET_BAD_DIND_BLOCK                   (2133571382L) | ||||
| #define EXT2_ET_BAD_TIND_BLOCK                   (2133571383L) | ||||
| #define EXT2_ET_NEQ_BLOCK_BITMAP                 (2133571384L) | ||||
| #define EXT2_ET_NEQ_INODE_BITMAP                 (2133571385L) | ||||
| #define EXT2_ET_BAD_DEVICE_NAME                  (2133571386L) | ||||
| #define EXT2_ET_MISSING_INODE_TABLE              (2133571387L) | ||||
| #define EXT2_ET_CORRUPT_SUPERBLOCK               (2133571388L) | ||||
| #define EXT2_ET_BAD_GENERIC_MARK                 (2133571389L) | ||||
| #define EXT2_ET_BAD_GENERIC_UNMARK               (2133571390L) | ||||
| #define EXT2_ET_BAD_GENERIC_TEST                 (2133571391L) | ||||
| #define EXT2_ET_SYMLINK_LOOP                     (2133571392L) | ||||
| #define EXT2_ET_CALLBACK_NOTHANDLED              (2133571393L) | ||||
| #define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE         (2133571394L) | ||||
| #define EXT2_ET_UNSUPP_FEATURE                   (2133571395L) | ||||
| #define EXT2_ET_RO_UNSUPP_FEATURE                (2133571396L) | ||||
| #define EXT2_ET_LLSEEK_FAILED                    (2133571397L) | ||||
| #define EXT2_ET_NO_MEMORY                        (2133571398L) | ||||
| #define EXT2_ET_INVALID_ARGUMENT                 (2133571399L) | ||||
| #define EXT2_ET_BLOCK_ALLOC_FAIL                 (2133571400L) | ||||
| #define EXT2_ET_INODE_ALLOC_FAIL                 (2133571401L) | ||||
| #define EXT2_ET_NO_DIRECTORY                     (2133571402L) | ||||
| #define EXT2_ET_TOO_MANY_REFS                    (2133571403L) | ||||
| #define EXT2_ET_FILE_NOT_FOUND                   (2133571404L) | ||||
| #define EXT2_ET_FILE_RO                          (2133571405L) | ||||
| #define EXT2_ET_DB_NOT_FOUND                     (2133571406L) | ||||
| #define EXT2_ET_DIR_EXISTS                       (2133571407L) | ||||
| #define EXT2_ET_UNIMPLEMENTED                    (2133571408L) | ||||
| #define EXT2_ET_CANCEL_REQUESTED                 (2133571409L) | ||||
| #define EXT2_ET_FILE_TOO_BIG                     (2133571410L) | ||||
| #define EXT2_ET_JOURNAL_NOT_BLOCK                (2133571411L) | ||||
| #define EXT2_ET_NO_JOURNAL_SB                    (2133571412L) | ||||
| #define EXT2_ET_JOURNAL_TOO_SMALL                (2133571413L) | ||||
| #define EXT2_ET_JOURNAL_UNSUPP_VERSION           (2133571414L) | ||||
| #define EXT2_ET_LOAD_EXT_JOURNAL                 (2133571415L) | ||||
| #define EXT2_ET_NO_JOURNAL                       (2133571416L) | ||||
| #define EXT2_ET_DIRHASH_UNSUPP                   (2133571417L) | ||||
| #define EXT2_ET_BAD_EA_BLOCK_NUM                 (2133571418L) | ||||
| #define EXT2_ET_TOO_MANY_INODES                  (2133571419L) | ||||
| #define EXT2_ET_NOT_IMAGE_FILE                   (2133571420L) | ||||
| #define EXT2_ET_RES_GDT_BLOCKS                   (2133571421L) | ||||
| #define EXT2_ET_RESIZE_INODE_CORRUPT             (2133571422L) | ||||
| #define EXT2_ET_SET_BMAP_NO_IND                  (2133571423L) | ||||
|  | ||||
| #if 0 | ||||
| extern const struct error_table et_ext2_error_table; | ||||
| extern void initialize_ext2_error_table(void); | ||||
|  | ||||
| /* For compatibility with Heimdal */ | ||||
| extern void initialize_ext2_error_table_r(struct et_list **list); | ||||
|  | ||||
| #define ERROR_TABLE_BASE_ext2 (2133571328L) | ||||
|  | ||||
| /* for compatibility with older versions... */ | ||||
| #define init_ext2_err_tbl initialize_ext2_error_table | ||||
| #define ext2_err_base ERROR_TABLE_BASE_ext2 | ||||
| #endif | ||||
| @@ -1,52 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|   File: linux/ext2_ext_attr.h | ||||
|  | ||||
|   On-disk format of extended attributes for the ext2 filesystem. | ||||
|  | ||||
|   (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org> | ||||
| */ | ||||
|  | ||||
| /* Magic value in attribute blocks */ | ||||
| #define EXT2_EXT_ATTR_MAGIC_v1		0xEA010000 | ||||
| #define EXT2_EXT_ATTR_MAGIC		0xEA020000 | ||||
|  | ||||
| /* Maximum number of references to one attribute block */ | ||||
| #define EXT2_EXT_ATTR_REFCOUNT_MAX	1024 | ||||
|  | ||||
| struct ext2_ext_attr_header { | ||||
| 	__u32	h_magic;	/* magic number for identification */ | ||||
| 	__u32	h_refcount;	/* reference count */ | ||||
| 	__u32	h_blocks;	/* number of disk blocks used */ | ||||
| 	__u32	h_hash;		/* hash value of all attributes */ | ||||
| 	__u32	h_reserved[4];	/* zero right now */ | ||||
| }; | ||||
|  | ||||
| struct ext2_ext_attr_entry { | ||||
| 	__u8	e_name_len;	/* length of name */ | ||||
| 	__u8	e_name_index;	/* attribute name index */ | ||||
| 	__u16	e_value_offs;	/* offset in disk block of value */ | ||||
| 	__u32	e_value_block;	/* disk block attribute is stored on (n/i) */ | ||||
| 	__u32	e_value_size;	/* size of attribute value */ | ||||
| 	__u32	e_hash;		/* hash value of name and value */ | ||||
| }; | ||||
|  | ||||
| #define EXT2_EXT_ATTR_PAD_BITS		2 | ||||
| #define EXT2_EXT_ATTR_PAD		(1<<EXT2_EXT_ATTR_PAD_BITS) | ||||
| #define EXT2_EXT_ATTR_ROUND		(EXT2_EXT_ATTR_PAD-1) | ||||
| #define EXT2_EXT_ATTR_LEN(name_len) \ | ||||
| 	(((name_len) + EXT2_EXT_ATTR_ROUND + \ | ||||
| 	sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND) | ||||
| #define EXT2_EXT_ATTR_NEXT(entry) \ | ||||
| 	( (struct ext2_ext_attr_entry *)( \ | ||||
| 	  (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) ) | ||||
| #define EXT2_EXT_ATTR_SIZE(size) \ | ||||
| 	(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) | ||||
| #define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL) | ||||
| #define EXT2_EXT_ATTR_NAME(entry) \ | ||||
| 	(((char *) (entry)) + sizeof(struct ext2_ext_attr_entry)) | ||||
| #define EXT2_XATTR_LEN(name_len) \ | ||||
| 	(((name_len) + EXT2_EXT_ATTR_ROUND + \ | ||||
| 	sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND) | ||||
| #define EXT2_XATTR_SIZE(size) \ | ||||
| 	(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) | ||||
| @@ -1,569 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  *  linux/include/linux/ext2_fs.h | ||||
|  * | ||||
|  * Copyright (C) 1992, 1993, 1994, 1995 | ||||
|  * Remy Card (card@masi.ibp.fr) | ||||
|  * Laboratoire MASI - Institut Blaise Pascal | ||||
|  * Universite Pierre et Marie Curie (Paris VI) | ||||
|  * | ||||
|  *  from | ||||
|  * | ||||
|  *  linux/include/linux/minix_fs.h | ||||
|  * | ||||
|  *  Copyright (C) 1991, 1992  Linus Torvalds | ||||
|  */ | ||||
| #ifndef LINUX_EXT2_FS_H | ||||
| #define LINUX_EXT2_FS_H 1 | ||||
|  | ||||
| #include "ext2_types.h"		/* Changed from linux/types.h */ | ||||
|  | ||||
| /* | ||||
|  * Special inode numbers | ||||
|  */ | ||||
| #define EXT2_BAD_INO		 1	/* Bad blocks inode */ | ||||
| #define EXT2_ROOT_INO		 2	/* Root inode */ | ||||
| #define EXT2_ACL_IDX_INO	 3	/* ACL inode */ | ||||
| #define EXT2_ACL_DATA_INO	 4	/* ACL inode */ | ||||
| #define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */ | ||||
| #define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */ | ||||
| #define EXT2_RESIZE_INO		 7	/* Reserved group descriptors inode */ | ||||
| #define EXT2_JOURNAL_INO	 8	/* Journal inode */ | ||||
|  | ||||
| /* First non-reserved inode for old ext2 filesystems */ | ||||
| #define EXT2_GOOD_OLD_FIRST_INO	11 | ||||
|  | ||||
| /* | ||||
|  * The second extended file system magic number | ||||
|  */ | ||||
| #define EXT2_SUPER_MAGIC	0xEF53 | ||||
|  | ||||
| /* Assume that user mode programs are passing in an ext2fs superblock, not | ||||
|  * a kernel struct super_block.  This will allow us to call the feature-test | ||||
|  * macros from user land. */ | ||||
| #define EXT2_SB(sb)	(sb) | ||||
|  | ||||
| /* | ||||
|  * Maximal count of links to a file | ||||
|  */ | ||||
| #define EXT2_LINK_MAX		32000 | ||||
|  | ||||
| /* | ||||
|  * Macro-instructions used to manage several block sizes | ||||
|  */ | ||||
| #define EXT2_MIN_BLOCK_LOG_SIZE		10	/* 1024 */ | ||||
| #define EXT2_MAX_BLOCK_LOG_SIZE		16	/* 65536 */ | ||||
| #define EXT2_MIN_BLOCK_SIZE	(1 << EXT2_MIN_BLOCK_LOG_SIZE) | ||||
| #define EXT2_MAX_BLOCK_SIZE	(1 << EXT2_MAX_BLOCK_LOG_SIZE) | ||||
| #define EXT2_BLOCK_SIZE(s)	(EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) | ||||
| #define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10) | ||||
| #define EXT2_INODE_SIZE(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ | ||||
| 				 EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size) | ||||
| #define EXT2_FIRST_INO(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ | ||||
| 				 EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino) | ||||
| #define EXT2_ADDR_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / sizeof(__u32)) | ||||
|  | ||||
| /* | ||||
|  * Macro-instructions used to manage fragments | ||||
|  */ | ||||
| #define EXT2_MIN_FRAG_SIZE		EXT2_MIN_BLOCK_SIZE | ||||
| #define EXT2_MAX_FRAG_SIZE		EXT2_MAX_BLOCK_SIZE | ||||
| #define EXT2_MIN_FRAG_LOG_SIZE		EXT2_MIN_BLOCK_LOG_SIZE | ||||
| # define EXT2_FRAG_SIZE(s)		(EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) | ||||
| # define EXT2_FRAGS_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) | ||||
|  | ||||
| /* | ||||
|  * ACL structures | ||||
|  */ | ||||
| struct ext2_acl_header	/* Header of Access Control Lists */ | ||||
| { | ||||
| 	__u32	aclh_size; | ||||
| 	__u32	aclh_file_count; | ||||
| 	__u32	aclh_acle_count; | ||||
| 	__u32	aclh_first_acle; | ||||
| }; | ||||
|  | ||||
| struct ext2_acl_entry	/* Access Control List Entry */ | ||||
| { | ||||
| 	__u32	acle_size; | ||||
| 	__u16	acle_perms;	/* Access permissions */ | ||||
| 	__u16	acle_type;	/* Type of entry */ | ||||
| 	__u16	acle_tag;	/* User or group identity */ | ||||
| 	__u16	acle_pad1; | ||||
| 	__u32	acle_next;	/* Pointer on next entry for the */ | ||||
| 					/* same inode or on next free entry */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Structure of a blocks group descriptor | ||||
|  */ | ||||
| struct ext2_group_desc | ||||
| { | ||||
| 	__u32	bg_block_bitmap;		/* Blocks bitmap block */ | ||||
| 	__u32	bg_inode_bitmap;		/* Inodes bitmap block */ | ||||
| 	__u32	bg_inode_table;		/* Inodes table block */ | ||||
| 	__u16	bg_free_blocks_count;	/* Free blocks count */ | ||||
| 	__u16	bg_free_inodes_count;	/* Free inodes count */ | ||||
| 	__u16	bg_used_dirs_count;	/* Directories count */ | ||||
| 	__u16	bg_pad; | ||||
| 	__u32	bg_reserved[3]; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Data structures used by the directory indexing feature | ||||
|  * | ||||
|  * Note: all of the multibyte integer fields are little endian. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Note: dx_root_info is laid out so that if it should somehow get | ||||
|  * overlaid by a dirent the two low bits of the hash version will be | ||||
|  * zero.  Therefore, the hash version mod 4 should never be 0. | ||||
|  * Sincerely, the paranoia department. | ||||
|  */ | ||||
| struct ext2_dx_root_info { | ||||
| 	__u32 reserved_zero; | ||||
| 	__u8 hash_version; /* 0 now, 1 at release */ | ||||
| 	__u8 info_length; /* 8 */ | ||||
| 	__u8 indirect_levels; | ||||
| 	__u8 unused_flags; | ||||
| }; | ||||
|  | ||||
| #define EXT2_HASH_LEGACY	0 | ||||
| #define EXT2_HASH_HALF_MD4	1 | ||||
| #define EXT2_HASH_TEA		2 | ||||
|  | ||||
| #define EXT2_HASH_FLAG_INCOMPAT	0x1 | ||||
|  | ||||
| struct ext2_dx_entry { | ||||
| 	__u32 hash; | ||||
| 	__u32 block; | ||||
| }; | ||||
|  | ||||
| struct ext2_dx_countlimit { | ||||
| 	__u16 limit; | ||||
| 	__u16 count; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Macro-instructions used to manage group descriptors | ||||
|  */ | ||||
| #define EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->s_blocks_per_group) | ||||
| #define EXT2_INODES_PER_GROUP(s)	(EXT2_SB(s)->s_inodes_per_group) | ||||
| #define EXT2_INODES_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s)) | ||||
| /* limits imposed by 16-bit value gd_free_{blocks,inode}_count */ | ||||
| #define EXT2_MAX_BLOCKS_PER_GROUP(s)	((1 << 16) - 8) | ||||
| #define EXT2_MAX_INODES_PER_GROUP(s)	((1 << 16) - EXT2_INODES_PER_BLOCK(s)) | ||||
| #define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) | ||||
|  | ||||
| /* | ||||
|  * Constants relative to the data blocks | ||||
|  */ | ||||
| #define EXT2_NDIR_BLOCKS		12 | ||||
| #define EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS | ||||
| #define EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1) | ||||
| #define EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1) | ||||
| #define EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1) | ||||
|  | ||||
| /* | ||||
|  * Inode flags | ||||
|  */ | ||||
| #define EXT2_SECRM_FL			0x00000001 /* Secure deletion */ | ||||
| #define EXT2_UNRM_FL			0x00000002 /* Undelete */ | ||||
| #define EXT2_COMPR_FL			0x00000004 /* Compress file */ | ||||
| #define EXT2_SYNC_FL			0x00000008 /* Synchronous updates */ | ||||
| #define EXT2_IMMUTABLE_FL		0x00000010 /* Immutable file */ | ||||
| #define EXT2_APPEND_FL			0x00000020 /* writes to file may only append */ | ||||
| #define EXT2_NODUMP_FL			0x00000040 /* do not dump file */ | ||||
| #define EXT2_NOATIME_FL			0x00000080 /* do not update atime */ | ||||
| /* Reserved for compression usage... */ | ||||
| #define EXT2_DIRTY_FL			0x00000100 | ||||
| #define EXT2_COMPRBLK_FL		0x00000200 /* One or more compressed clusters */ | ||||
| #define EXT2_NOCOMPR_FL			0x00000400 /* Access raw compressed data */ | ||||
| #define EXT2_ECOMPR_FL			0x00000800 /* Compression error */ | ||||
| /* End compression flags --- maybe not all used */ | ||||
| #define EXT2_BTREE_FL			0x00001000 /* btree format dir */ | ||||
| #define EXT2_INDEX_FL			0x00001000 /* hash-indexed directory */ | ||||
| #define EXT2_IMAGIC_FL			0x00002000 | ||||
| #define EXT3_JOURNAL_DATA_FL		0x00004000 /* file data should be journaled */ | ||||
| #define EXT2_NOTAIL_FL			0x00008000 /* file tail should not be merged */ | ||||
| #define EXT2_DIRSYNC_FL			0x00010000 /* Synchronous directory modifications */ | ||||
| #define EXT2_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/ | ||||
| #define EXT3_EXTENTS_FL			0x00080000 /* Inode uses extents */ | ||||
| #define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */ | ||||
|  | ||||
| #define EXT2_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */ | ||||
| #define EXT2_FL_USER_MODIFIABLE		0x000080FF /* User modifiable flags */ | ||||
|  | ||||
| /* | ||||
|  * ioctl commands | ||||
|  */ | ||||
| #define EXT2_IOC_GETFLAGS		_IOR('f', 1, long) | ||||
| #define EXT2_IOC_SETFLAGS		_IOW('f', 2, long) | ||||
| #define EXT2_IOC_GETVERSION		_IOR('v', 1, long) | ||||
| #define EXT2_IOC_SETVERSION		_IOW('v', 2, long) | ||||
|  | ||||
| /* | ||||
|  * Structure of an inode on the disk | ||||
|  */ | ||||
| struct ext2_inode { | ||||
| 	__u16	i_mode;		/* File mode */ | ||||
| 	__u16	i_uid;		/* Low 16 bits of Owner Uid */ | ||||
| 	__u32	i_size;		/* Size in bytes */ | ||||
| 	__u32	i_atime;	/* Access time */ | ||||
| 	__u32	i_ctime;	/* Creation time */ | ||||
| 	__u32	i_mtime;	/* Modification time */ | ||||
| 	__u32	i_dtime;	/* Deletion Time */ | ||||
| 	__u16	i_gid;		/* Low 16 bits of Group Id */ | ||||
| 	__u16	i_links_count;	/* Links count */ | ||||
| 	__u32	i_blocks;	/* Blocks count */ | ||||
| 	__u32	i_flags;	/* File flags */ | ||||
| 	union { | ||||
| 		struct { | ||||
| 			__u32  l_i_reserved1; | ||||
| 		} linux1; | ||||
| 		struct { | ||||
| 			__u32  h_i_translator; | ||||
| 		} hurd1; | ||||
| 		struct { | ||||
| 			__u32  m_i_reserved1; | ||||
| 		} masix1; | ||||
| 	} osd1;				/* OS dependent 1 */ | ||||
| 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ | ||||
| 	__u32	i_generation;	/* File version (for NFS) */ | ||||
| 	__u32	i_file_acl;	/* File ACL */ | ||||
| 	__u32	i_dir_acl;	/* Directory ACL */ | ||||
| 	__u32	i_faddr;	/* Fragment address */ | ||||
| 	union { | ||||
| 		struct { | ||||
| 			__u8	l_i_frag;	/* Fragment number */ | ||||
| 			__u8	l_i_fsize;	/* Fragment size */ | ||||
| 			__u16	i_pad1; | ||||
| 			__u16	l_i_uid_high;	/* these 2 fields    */ | ||||
| 			__u16	l_i_gid_high;	/* were reserved2[0] */ | ||||
| 			__u32	l_i_reserved2; | ||||
| 		} linux2; | ||||
| 		struct { | ||||
| 			__u8	h_i_frag;	/* Fragment number */ | ||||
| 			__u8	h_i_fsize;	/* Fragment size */ | ||||
| 			__u16	h_i_mode_high; | ||||
| 			__u16	h_i_uid_high; | ||||
| 			__u16	h_i_gid_high; | ||||
| 			__u32	h_i_author; | ||||
| 		} hurd2; | ||||
| 		struct { | ||||
| 			__u8	m_i_frag;	/* Fragment number */ | ||||
| 			__u8	m_i_fsize;	/* Fragment size */ | ||||
| 			__u16	m_pad1; | ||||
| 			__u32	m_i_reserved2[2]; | ||||
| 		} masix2; | ||||
| 	} osd2;				/* OS dependent 2 */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Permanent part of an large inode on the disk | ||||
|  */ | ||||
| struct ext2_inode_large { | ||||
| 	__u16	i_mode;		/* File mode */ | ||||
| 	__u16	i_uid;		/* Low 16 bits of Owner Uid */ | ||||
| 	__u32	i_size;		/* Size in bytes */ | ||||
| 	__u32	i_atime;	/* Access time */ | ||||
| 	__u32	i_ctime;	/* Creation time */ | ||||
| 	__u32	i_mtime;	/* Modification time */ | ||||
| 	__u32	i_dtime;	/* Deletion Time */ | ||||
| 	__u16	i_gid;		/* Low 16 bits of Group Id */ | ||||
| 	__u16	i_links_count;	/* Links count */ | ||||
| 	__u32	i_blocks;	/* Blocks count */ | ||||
| 	__u32	i_flags;	/* File flags */ | ||||
| 	union { | ||||
| 		struct { | ||||
| 			__u32  l_i_reserved1; | ||||
| 		} linux1; | ||||
| 		struct { | ||||
| 			__u32  h_i_translator; | ||||
| 		} hurd1; | ||||
| 		struct { | ||||
| 			__u32  m_i_reserved1; | ||||
| 		} masix1; | ||||
| 	} osd1;				/* OS dependent 1 */ | ||||
| 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ | ||||
| 	__u32	i_generation;	/* File version (for NFS) */ | ||||
| 	__u32	i_file_acl;	/* File ACL */ | ||||
| 	__u32	i_dir_acl;	/* Directory ACL */ | ||||
| 	__u32	i_faddr;	/* Fragment address */ | ||||
| 	union { | ||||
| 		struct { | ||||
| 			__u8	l_i_frag;	/* Fragment number */ | ||||
| 			__u8	l_i_fsize;	/* Fragment size */ | ||||
| 			__u16	i_pad1; | ||||
| 			__u16	l_i_uid_high;	/* these 2 fields    */ | ||||
| 			__u16	l_i_gid_high;	/* were reserved2[0] */ | ||||
| 			__u32	l_i_reserved2; | ||||
| 		} linux2; | ||||
| 		struct { | ||||
| 			__u8	h_i_frag;	/* Fragment number */ | ||||
| 			__u8	h_i_fsize;	/* Fragment size */ | ||||
| 			__u16	h_i_mode_high; | ||||
| 			__u16	h_i_uid_high; | ||||
| 			__u16	h_i_gid_high; | ||||
| 			__u32	h_i_author; | ||||
| 		} hurd2; | ||||
| 		struct { | ||||
| 			__u8	m_i_frag;	/* Fragment number */ | ||||
| 			__u8	m_i_fsize;	/* Fragment size */ | ||||
| 			__u16	m_pad1; | ||||
| 			__u32	m_i_reserved2[2]; | ||||
| 		} masix2; | ||||
| 	} osd2;				/* OS dependent 2 */ | ||||
| 	__u16	i_extra_isize; | ||||
| 	__u16	i_pad1; | ||||
| }; | ||||
|  | ||||
| #define i_size_high	i_dir_acl | ||||
|  | ||||
| /* | ||||
|  * File system states | ||||
|  */ | ||||
| #define EXT2_VALID_FS			0x0001	/* Unmounted cleanly */ | ||||
| #define EXT2_ERROR_FS			0x0002	/* Errors detected */ | ||||
|  | ||||
| /* | ||||
|  * Mount flags | ||||
|  */ | ||||
| #define EXT2_MOUNT_CHECK		0x0001	/* Do mount-time checks */ | ||||
| #define EXT2_MOUNT_GRPID		0x0004	/* Create files with directory's group */ | ||||
| #define EXT2_MOUNT_DEBUG		0x0008	/* Some debugging messages */ | ||||
| #define EXT2_MOUNT_ERRORS_CONT		0x0010	/* Continue on errors */ | ||||
| #define EXT2_MOUNT_ERRORS_RO		0x0020	/* Remount fs ro on errors */ | ||||
| #define EXT2_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */ | ||||
| #define EXT2_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */ | ||||
| #define EXT2_MOUNT_NO_UID32		0x0200  /* Disable 32-bit UIDs */ | ||||
|  | ||||
| #define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt | ||||
| #define set_opt(o, opt)			o |= EXT2_MOUNT_##opt | ||||
| #define test_opt(sb, opt)		(EXT2_SB(sb)->s_mount_opt & \ | ||||
| 					 EXT2_MOUNT_##opt) | ||||
| /* | ||||
|  * Maximal mount counts between two filesystem checks | ||||
|  */ | ||||
| #define EXT2_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */ | ||||
| #define EXT2_DFL_CHECKINTERVAL		0	/* Don't use interval check */ | ||||
|  | ||||
| /* | ||||
|  * Behaviour when detecting errors | ||||
|  */ | ||||
| #define EXT2_ERRORS_CONTINUE		1	/* Continue execution */ | ||||
| #define EXT2_ERRORS_RO			2	/* Remount fs read-only */ | ||||
| #define EXT2_ERRORS_PANIC		3	/* Panic */ | ||||
| #define EXT2_ERRORS_DEFAULT		EXT2_ERRORS_CONTINUE | ||||
|  | ||||
| /* | ||||
|  * Structure of the super block | ||||
|  */ | ||||
| struct ext2_super_block { | ||||
| 	__u32	s_inodes_count;		/* Inodes count */ | ||||
| 	__u32	s_blocks_count;		/* Blocks count */ | ||||
| 	__u32	s_r_blocks_count;	/* Reserved blocks count */ | ||||
| 	__u32	s_free_blocks_count;	/* Free blocks count */ | ||||
| 	__u32	s_free_inodes_count;	/* Free inodes count */ | ||||
| 	__u32	s_first_data_block;	/* First Data Block */ | ||||
| 	__u32	s_log_block_size;	/* Block size */ | ||||
| 	__s32	s_log_frag_size;	/* Fragment size */ | ||||
| 	__u32	s_blocks_per_group;	/* # Blocks per group */ | ||||
| 	__u32	s_frags_per_group;	/* # Fragments per group */ | ||||
| 	__u32	s_inodes_per_group;	/* # Inodes per group */ | ||||
| 	__u32	s_mtime;		/* Mount time */ | ||||
| 	__u32	s_wtime;		/* Write time */ | ||||
| 	__u16	s_mnt_count;		/* Mount count */ | ||||
| 	__s16	s_max_mnt_count;	/* Maximal mount count */ | ||||
| 	__u16	s_magic;		/* Magic signature */ | ||||
| 	__u16	s_state;		/* File system state */ | ||||
| 	__u16	s_errors;		/* Behaviour when detecting errors */ | ||||
| 	__u16	s_minor_rev_level;	/* minor revision level */ | ||||
| 	__u32	s_lastcheck;		/* time of last check */ | ||||
| 	__u32	s_checkinterval;	/* max. time between checks */ | ||||
| 	__u32	s_creator_os;		/* OS */ | ||||
| 	__u32	s_rev_level;		/* Revision level */ | ||||
| 	__u16	s_def_resuid;		/* Default uid for reserved blocks */ | ||||
| 	__u16	s_def_resgid;		/* Default gid for reserved blocks */ | ||||
| 	/* | ||||
| 	 * These fields are for EXT2_DYNAMIC_REV superblocks only. | ||||
| 	 * | ||||
| 	 * Note: the difference between the compatible feature set and | ||||
| 	 * the incompatible feature set is that if there is a bit set | ||||
| 	 * in the incompatible feature set that the kernel doesn't | ||||
| 	 * know about, it should refuse to mount the filesystem. | ||||
| 	 * | ||||
| 	 * e2fsck's requirements are more strict; if it doesn't know | ||||
| 	 * about a feature in either the compatible or incompatible | ||||
| 	 * feature set, it must abort and not try to meddle with | ||||
| 	 * things it doesn't understand... | ||||
| 	 */ | ||||
| 	__u32	s_first_ino;		/* First non-reserved inode */ | ||||
| 	__u16   s_inode_size;		/* size of inode structure */ | ||||
| 	__u16	s_block_group_nr;	/* block group # of this superblock */ | ||||
| 	__u32	s_feature_compat;	/* compatible feature set */ | ||||
| 	__u32	s_feature_incompat;	/* incompatible feature set */ | ||||
| 	__u32	s_feature_ro_compat;	/* readonly-compatible feature set */ | ||||
| 	__u8	s_uuid[16];		/* 128-bit uuid for volume */ | ||||
| 	char	s_volume_name[16];	/* volume name */ | ||||
| 	char	s_last_mounted[64];	/* directory where last mounted */ | ||||
| 	__u32	s_algorithm_usage_bitmap; /* For compression */ | ||||
| 	/* | ||||
| 	 * Performance hints.  Directory preallocation should only | ||||
| 	 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. | ||||
| 	 */ | ||||
| 	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/ | ||||
| 	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */ | ||||
| 	__u16	s_reserved_gdt_blocks;	/* Per group table for online growth */ | ||||
| 	/* | ||||
| 	 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. | ||||
| 	 */ | ||||
| 	__u8	s_journal_uuid[16];	/* uuid of journal superblock */ | ||||
| 	__u32	s_journal_inum;		/* inode number of journal file */ | ||||
| 	__u32	s_journal_dev;		/* device number of journal file */ | ||||
| 	__u32	s_last_orphan;		/* start of list of inodes to delete */ | ||||
| 	__u32	s_hash_seed[4];		/* HTREE hash seed */ | ||||
| 	__u8	s_def_hash_version;	/* Default hash version to use */ | ||||
| 	__u8	s_jnl_backup_type;	/* Default type of journal backup */ | ||||
| 	__u16	s_reserved_word_pad; | ||||
| 	__u32	s_default_mount_opts; | ||||
| 	__u32	s_first_meta_bg;	/* First metablock group */ | ||||
| 	__u32	s_mkfs_time;		/* When the filesystem was created */ | ||||
| 	__u32	s_jnl_blocks[17];	/* Backup of the journal inode */ | ||||
| 	__u32	s_reserved[172];	/* Padding to the end of the block */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Codes for operating systems | ||||
|  */ | ||||
| #define EXT2_OS_LINUX		0 | ||||
| #define EXT2_OS_HURD		1 | ||||
| #define EXT2_OS_MASIX		2 | ||||
| #define EXT2_OS_FREEBSD		3 | ||||
| #define EXT2_OS_LITES		4 | ||||
|  | ||||
| /* | ||||
|  * Revision levels | ||||
|  */ | ||||
| #define EXT2_GOOD_OLD_REV	0	/* The good old (original) format */ | ||||
| #define EXT2_DYNAMIC_REV	1	/* V2 format w/ dynamic inode sizes */ | ||||
|  | ||||
| #define EXT2_CURRENT_REV	EXT2_GOOD_OLD_REV | ||||
| #define EXT2_MAX_SUPP_REV	EXT2_DYNAMIC_REV | ||||
|  | ||||
| #define EXT2_GOOD_OLD_INODE_SIZE 128 | ||||
|  | ||||
| /* | ||||
|  * Journal inode backup types | ||||
|  */ | ||||
| #define EXT3_JNL_BACKUP_BLOCKS	1 | ||||
|  | ||||
| /* | ||||
|  * Feature set definitions | ||||
|  */ | ||||
|  | ||||
| #define EXT2_HAS_COMPAT_FEATURE(sb,mask)			\ | ||||
| 	( EXT2_SB(sb)->s_feature_compat & (mask) ) | ||||
| #define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\ | ||||
| 	( EXT2_SB(sb)->s_feature_ro_compat & (mask) ) | ||||
| #define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\ | ||||
| 	( EXT2_SB(sb)->s_feature_incompat & (mask) ) | ||||
|  | ||||
| #define EXT2_FEATURE_COMPAT_DIR_PREALLOC	0x0001 | ||||
| #define EXT2_FEATURE_COMPAT_IMAGIC_INODES	0x0002 | ||||
| #define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004 | ||||
| #define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008 | ||||
| #define EXT2_FEATURE_COMPAT_RESIZE_INO		0x0010 | ||||
| #define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020 | ||||
|  | ||||
| #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001 | ||||
| #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002 | ||||
| /* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004 not used */ | ||||
|  | ||||
| #define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001 | ||||
| #define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002 | ||||
| #define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004 /* Needs recovery */ | ||||
| #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */ | ||||
| #define EXT2_FEATURE_INCOMPAT_META_BG		0x0010 | ||||
| #define EXT3_FEATURE_INCOMPAT_EXTENTS		0x0040 | ||||
|  | ||||
|  | ||||
| #define EXT2_FEATURE_COMPAT_SUPP	0 | ||||
| #define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE) | ||||
| #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ | ||||
| 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ | ||||
| 					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR) | ||||
|  | ||||
| /* | ||||
|  * Default values for user and/or group using reserved blocks | ||||
|  */ | ||||
| #define EXT2_DEF_RESUID		0 | ||||
| #define EXT2_DEF_RESGID		0 | ||||
|  | ||||
| /* | ||||
|  * Default mount options | ||||
|  */ | ||||
| #define EXT2_DEFM_DEBUG		0x0001 | ||||
| #define EXT2_DEFM_BSDGROUPS	0x0002 | ||||
| #define EXT2_DEFM_XATTR_USER	0x0004 | ||||
| #define EXT2_DEFM_ACL		0x0008 | ||||
| #define EXT2_DEFM_UID16		0x0010 | ||||
| #define EXT3_DEFM_JMODE		0x0060 | ||||
| #define EXT3_DEFM_JMODE_DATA	0x0020 | ||||
| #define EXT3_DEFM_JMODE_ORDERED	0x0040 | ||||
| #define EXT3_DEFM_JMODE_WBACK	0x0060 | ||||
|  | ||||
| /* | ||||
|  * Structure of a directory entry | ||||
|  */ | ||||
| #define EXT2_NAME_LEN 255 | ||||
|  | ||||
| struct ext2_dir_entry { | ||||
| 	__u32	inode;			/* Inode number */ | ||||
| 	__u16	rec_len;		/* Directory entry length */ | ||||
| 	__u16	name_len;		/* Name length */ | ||||
| 	char	name[EXT2_NAME_LEN];	/* File name */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * The new version of the directory entry.  Since EXT2 structures are | ||||
|  * stored in intel byte order, and the name_len field could never be | ||||
|  * bigger than 255 chars, it's safe to reclaim the extra byte for the | ||||
|  * file_type field. | ||||
|  */ | ||||
| struct ext2_dir_entry_2 { | ||||
| 	__u32	inode;			/* Inode number */ | ||||
| 	__u16	rec_len;		/* Directory entry length */ | ||||
| 	__u8	name_len;		/* Name length */ | ||||
| 	__u8	file_type; | ||||
| 	char	name[EXT2_NAME_LEN];	/* File name */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Ext2 directory file types.  Only the low 3 bits are used.  The | ||||
|  * other bits are reserved for now. | ||||
|  */ | ||||
| #define EXT2_FT_UNKNOWN		0 | ||||
| #define EXT2_FT_REG_FILE	1 | ||||
| #define EXT2_FT_DIR		2 | ||||
| #define EXT2_FT_CHRDEV		3 | ||||
| #define EXT2_FT_BLKDEV		4 | ||||
| #define EXT2_FT_FIFO		5 | ||||
| #define EXT2_FT_SOCK		6 | ||||
| #define EXT2_FT_SYMLINK		7 | ||||
|  | ||||
| #define EXT2_FT_MAX		8 | ||||
|  | ||||
| /* | ||||
|  * EXT2_DIR_PAD defines the directory entries boundaries | ||||
|  * | ||||
|  * NOTE: It must be a multiple of 4 | ||||
|  */ | ||||
| #define EXT2_DIR_PAD			4 | ||||
| #define EXT2_DIR_ROUND			(EXT2_DIR_PAD - 1) | ||||
| #define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \ | ||||
| 					 ~EXT2_DIR_ROUND) | ||||
|  | ||||
| #endif | ||||
| @@ -1,112 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * io.h --- the I/O manager abstraction | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
| #ifndef EXT2FS_EXT2_IO_H | ||||
| #define EXT2FS_EXT2_IO_H 1 | ||||
|  | ||||
| /* | ||||
|  * ext2_loff_t is defined here since unix_io.c needs it. | ||||
|  */ | ||||
| #if defined(__GNUC__) || defined(HAS_LONG_LONG) | ||||
| typedef long long	ext2_loff_t; | ||||
| #else | ||||
| typedef long		ext2_loff_t; | ||||
| #endif | ||||
|  | ||||
| /* llseek.c */ | ||||
| /* ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); */ | ||||
| #ifdef CONFIG_LFS | ||||
| # define ext2fs_llseek lseek64 | ||||
| #else | ||||
| # define ext2fs_llseek lseek | ||||
| #endif | ||||
|  | ||||
| typedef struct struct_io_manager *io_manager; | ||||
| typedef struct struct_io_channel *io_channel; | ||||
|  | ||||
| #define CHANNEL_FLAGS_WRITETHROUGH	0x01 | ||||
|  | ||||
| struct struct_io_channel { | ||||
| 	errcode_t	magic; | ||||
| 	io_manager	manager; | ||||
| 	char		*name; | ||||
| 	int		block_size; | ||||
| 	errcode_t	(*read_error)(io_channel channel, | ||||
| 				      unsigned long block, | ||||
| 				      int count, | ||||
| 				      void *data, | ||||
| 				      size_t size, | ||||
| 				      int actual_bytes_read, | ||||
| 				      errcode_t error); | ||||
| 	errcode_t       (*write_error)(io_channel channel, | ||||
| 				       unsigned long block, | ||||
| 				       int count, | ||||
| 				       const void *data, | ||||
| 				       size_t size, | ||||
| 				       int actual_bytes_written, | ||||
| 				       errcode_t error); | ||||
| 	int		refcount; | ||||
| 	int		flags; | ||||
| 	int		reserved[14]; | ||||
| 	void		*private_data; | ||||
| 	void		*app_data; | ||||
| }; | ||||
|  | ||||
| struct struct_io_manager { | ||||
| 	errcode_t magic; | ||||
| 	const char *name; | ||||
| 	errcode_t (*open)(const char *name, int flags, io_channel *channel); | ||||
| 	errcode_t (*close)(io_channel channel); | ||||
| 	errcode_t (*set_blksize)(io_channel channel, int blksize); | ||||
| 	errcode_t (*read_blk)(io_channel channel, unsigned long block, | ||||
| 			      int count, void *data); | ||||
| 	errcode_t (*write_blk)(io_channel channel, unsigned long block, | ||||
| 			       int count, const void *data); | ||||
| 	errcode_t (*flush)(io_channel channel); | ||||
| 	errcode_t (*write_byte)(io_channel channel, unsigned long offset, | ||||
| 				int count, const void *data); | ||||
| 	errcode_t (*set_option)(io_channel channel, const char *option, | ||||
| 				const char *arg); | ||||
| 	int             reserved[14]; | ||||
| }; | ||||
|  | ||||
| #define IO_FLAG_RW	1 | ||||
|  | ||||
| /* | ||||
|  * Convenience functions.... | ||||
|  */ | ||||
| #define io_channel_close(c)		((c)->manager->close((c))) | ||||
| #define io_channel_set_blksize(c,s)	((c)->manager->set_blksize((c),s)) | ||||
| #define io_channel_read_blk(c,b,n,d)	((c)->manager->read_blk((c),b,n,d)) | ||||
| #define io_channel_write_blk(c,b,n,d)	((c)->manager->write_blk((c),b,n,d)) | ||||
| #define io_channel_flush(c)		((c)->manager->flush((c))) | ||||
| #define io_channel_bumpcount(c)		((c)->refcount++) | ||||
|  | ||||
| /* io_manager.c */ | ||||
| extern errcode_t io_channel_set_options(io_channel channel, | ||||
| 					const char *options); | ||||
| extern errcode_t io_channel_write_byte(io_channel channel, | ||||
| 				       unsigned long offset, | ||||
| 				       int count, const void *data); | ||||
|  | ||||
| /* unix_io.c */ | ||||
| extern io_manager unix_io_manager; | ||||
|  | ||||
| /* test_io.c */ | ||||
| extern io_manager test_io_manager, test_io_backing_manager; | ||||
| extern void (*test_io_cb_read_blk) | ||||
| 	(unsigned long block, int count, errcode_t err); | ||||
| extern void (*test_io_cb_write_blk) | ||||
| 	(unsigned long block, int count, errcode_t err); | ||||
| extern void (*test_io_cb_set_blksize) | ||||
| 	(int blksize, errcode_t err); | ||||
|  | ||||
| #endif | ||||
| @@ -1,2 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| #include <linux/types.h> | ||||
| @@ -1,922 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ext2fs.h --- ext2fs | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
| #ifndef EXT2FS_EXT2FS_H | ||||
| #define EXT2FS_EXT2FS_H 1 | ||||
|  | ||||
|  | ||||
| #define EXT2FS_ATTR(x) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Where the master copy of the superblock is located, and how big | ||||
|  * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because | ||||
|  * the size of the superblock structure is not necessarily trustworthy | ||||
|  * (some versions have the padding set up so that the superblock is | ||||
|  * 1032 bytes long). | ||||
|  */ | ||||
| #define SUPERBLOCK_OFFSET	1024 | ||||
| #define SUPERBLOCK_SIZE		1024 | ||||
|  | ||||
| /* | ||||
|  * The last ext2fs revision level that this version of the library is | ||||
|  * able to support. | ||||
|  */ | ||||
| #define EXT2_LIB_CURRENT_REV	EXT2_DYNAMIC_REV | ||||
|  | ||||
| #ifdef HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #include "ext2_types.h" | ||||
| #include "ext2_fs.h" | ||||
|  | ||||
| typedef __u32		ext2_ino_t; | ||||
| typedef __u32		blk_t; | ||||
| typedef __u32		dgrp_t; | ||||
| typedef __u32		ext2_off_t; | ||||
| typedef __s64		e2_blkcnt_t; | ||||
| typedef __u32		ext2_dirhash_t; | ||||
|  | ||||
| #include "ext2_io.h" | ||||
| #include "ext2_err.h" | ||||
|  | ||||
| typedef struct struct_ext2_filsys *ext2_filsys; | ||||
|  | ||||
| struct ext2fs_struct_generic_bitmap { | ||||
| 	errcode_t	magic; | ||||
| 	ext2_filsys	fs; | ||||
| 	__u32		start, end; | ||||
| 	__u32		real_end; | ||||
| 	char	*	description; | ||||
| 	char	*	bitmap; | ||||
| 	errcode_t	base_error_code; | ||||
| 	__u32		reserved[7]; | ||||
| }; | ||||
|  | ||||
| #define EXT2FS_MARK_ERROR	0 | ||||
| #define EXT2FS_UNMARK_ERROR	1 | ||||
| #define EXT2FS_TEST_ERROR	2 | ||||
|  | ||||
| typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap; | ||||
| typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap; | ||||
| typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap; | ||||
|  | ||||
| #define EXT2_FIRST_INODE(s)	EXT2_FIRST_INO(s) | ||||
|  | ||||
| /* | ||||
|  * badblocks list definitions | ||||
|  */ | ||||
|  | ||||
| typedef struct ext2_struct_u32_list *ext2_badblocks_list; | ||||
| typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate; | ||||
|  | ||||
| typedef struct ext2_struct_u32_list *ext2_u32_list; | ||||
| typedef struct ext2_struct_u32_iterate *ext2_u32_iterate; | ||||
|  | ||||
| /* old */ | ||||
| typedef struct ext2_struct_u32_list *badblocks_list; | ||||
| typedef struct ext2_struct_u32_iterate *badblocks_iterate; | ||||
|  | ||||
| #define BADBLOCKS_FLAG_DIRTY	1 | ||||
|  | ||||
| /* | ||||
|  * ext2_dblist structure and abstractions (see dblist.c) | ||||
|  */ | ||||
| struct ext2_db_entry { | ||||
| 	ext2_ino_t	ino; | ||||
| 	blk_t	blk; | ||||
| 	int	blockcnt; | ||||
| }; | ||||
|  | ||||
| typedef struct ext2_struct_dblist *ext2_dblist; | ||||
|  | ||||
| #define DBLIST_ABORT	1 | ||||
|  | ||||
| /* | ||||
|  * ext2_fileio definitions | ||||
|  */ | ||||
|  | ||||
| #define EXT2_FILE_WRITE		0x0001 | ||||
| #define EXT2_FILE_CREATE	0x0002 | ||||
|  | ||||
| #define EXT2_FILE_MASK		0x00FF | ||||
|  | ||||
| #define EXT2_FILE_BUF_DIRTY	0x4000 | ||||
| #define EXT2_FILE_BUF_VALID	0x2000 | ||||
|  | ||||
| typedef struct ext2_file *ext2_file_t; | ||||
|  | ||||
| #define EXT2_SEEK_SET	0 | ||||
| #define EXT2_SEEK_CUR	1 | ||||
| #define EXT2_SEEK_END	2 | ||||
|  | ||||
| /* | ||||
|  * Flags for the ext2_filsys structure and for ext2fs_open() | ||||
|  */ | ||||
| #define EXT2_FLAG_RW			0x01 | ||||
| #define EXT2_FLAG_CHANGED		0x02 | ||||
| #define EXT2_FLAG_DIRTY			0x04 | ||||
| #define EXT2_FLAG_VALID			0x08 | ||||
| #define EXT2_FLAG_IB_DIRTY		0x10 | ||||
| #define EXT2_FLAG_BB_DIRTY		0x20 | ||||
| #define EXT2_FLAG_SWAP_BYTES		0x40 | ||||
| #define EXT2_FLAG_SWAP_BYTES_READ	0x80 | ||||
| #define EXT2_FLAG_SWAP_BYTES_WRITE	0x100 | ||||
| #define EXT2_FLAG_MASTER_SB_ONLY	0x200 | ||||
| #define EXT2_FLAG_FORCE			0x400 | ||||
| #define EXT2_FLAG_SUPER_ONLY		0x800 | ||||
| #define EXT2_FLAG_JOURNAL_DEV_OK	0x1000 | ||||
| #define EXT2_FLAG_IMAGE_FILE		0x2000 | ||||
|  | ||||
| /* | ||||
|  * Special flag in the ext2 inode i_flag field that means that this is | ||||
|  * a new inode.  (So that ext2_write_inode() can clear extra fields.) | ||||
|  */ | ||||
| #define EXT2_NEW_INODE_FL	0x80000000 | ||||
|  | ||||
| /* | ||||
|  * Flags for mkjournal | ||||
|  * | ||||
|  * EXT2_MKJOURNAL_V1_SUPER	Make a (deprecated) V1 journal superblock | ||||
|  */ | ||||
| #define EXT2_MKJOURNAL_V1_SUPER	0x0000001 | ||||
|  | ||||
| struct struct_ext2_filsys { | ||||
| 	errcode_t			magic; | ||||
| 	io_channel			io; | ||||
| 	int				flags; | ||||
| 	char *				device_name; | ||||
| 	struct ext2_super_block	*	super; | ||||
| 	unsigned int			blocksize; | ||||
| 	int				fragsize; | ||||
| 	dgrp_t				group_desc_count; | ||||
| 	unsigned long			desc_blocks; | ||||
| 	struct ext2_group_desc *	group_desc; | ||||
| 	int				inode_blocks_per_group; | ||||
| 	ext2fs_inode_bitmap		inode_map; | ||||
| 	ext2fs_block_bitmap		block_map; | ||||
| 	errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); | ||||
| 	errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino); | ||||
| 	errcode_t (*write_bitmaps)(ext2_filsys fs); | ||||
| 	errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				struct ext2_inode *inode); | ||||
| 	errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				struct ext2_inode *inode); | ||||
| 	ext2_badblocks_list		badblocks; | ||||
| 	ext2_dblist			dblist; | ||||
| 	__u32				stride;	/* for mke2fs */ | ||||
| 	struct ext2_super_block *	orig_super; | ||||
| 	struct ext2_image_hdr *		image_header; | ||||
| 	__u32				umask; | ||||
| 	/* | ||||
| 	 * Reserved for future expansion | ||||
| 	 */ | ||||
| 	__u32				reserved[8]; | ||||
|  | ||||
| 	/* | ||||
| 	 * Reserved for the use of the calling application. | ||||
| 	 */ | ||||
| 	void *				priv_data; | ||||
|  | ||||
| 	/* | ||||
| 	 * Inode cache | ||||
| 	 */ | ||||
| 	struct ext2_inode_cache		*icache; | ||||
| 	io_channel			image_io; | ||||
| }; | ||||
|  | ||||
| #include "bitops.h" | ||||
|  | ||||
| /* | ||||
|  * Return flags for the block iterator functions | ||||
|  */ | ||||
| #define BLOCK_CHANGED	1 | ||||
| #define BLOCK_ABORT	2 | ||||
| #define BLOCK_ERROR	4 | ||||
|  | ||||
| /* | ||||
|  * Block interate flags | ||||
|  * | ||||
|  * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator | ||||
|  * function should be called on blocks where the block number is zero. | ||||
|  * This is used by ext2fs_expand_dir() to be able to add a new block | ||||
|  * to an inode.  It can also be used for programs that want to be able | ||||
|  * to deal with files that contain "holes". | ||||
|  * | ||||
|  * BLOCK_FLAG_TRAVERSE indicates that the iterator function for the | ||||
|  * indirect, doubly indirect, etc. blocks should be called after all | ||||
|  * of the blocks containined in the indirect blocks are processed. | ||||
|  * This is useful if you are going to be deallocating blocks from an | ||||
|  * inode. | ||||
|  * | ||||
|  * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be | ||||
|  * called for data blocks only. | ||||
|  * | ||||
|  * BLOCK_FLAG_NO_LARGE is for internal use only.  It informs | ||||
|  * ext2fs_block_iterate2 that large files won't be accepted. | ||||
|  */ | ||||
| #define BLOCK_FLAG_APPEND	1 | ||||
| #define BLOCK_FLAG_HOLE		1 | ||||
| #define BLOCK_FLAG_DEPTH_TRAVERSE	2 | ||||
| #define BLOCK_FLAG_DATA_ONLY	4 | ||||
|  | ||||
| #define BLOCK_FLAG_NO_LARGE	0x1000 | ||||
|  | ||||
| /* | ||||
|  * Magic "block count" return values for the block iterator function. | ||||
|  */ | ||||
| #define BLOCK_COUNT_IND		(-1) | ||||
| #define BLOCK_COUNT_DIND	(-2) | ||||
| #define BLOCK_COUNT_TIND	(-3) | ||||
| #define BLOCK_COUNT_TRANSLATOR	(-4) | ||||
|  | ||||
| #if 0 | ||||
| /* | ||||
|  * Flags for ext2fs_move_blocks | ||||
|  */ | ||||
| #define EXT2_BMOVE_GET_DBLIST	0x0001 | ||||
| #define EXT2_BMOVE_DEBUG	0x0002 | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Flags for directory block reading and writing functions | ||||
|  */ | ||||
| #define EXT2_DIRBLOCK_V2_STRUCT	0x0001 | ||||
|  | ||||
| /* | ||||
|  * Return flags for the directory iterator functions | ||||
|  */ | ||||
| #define DIRENT_CHANGED	1 | ||||
| #define DIRENT_ABORT	2 | ||||
| #define DIRENT_ERROR	3 | ||||
|  | ||||
| /* | ||||
|  * Directory iterator flags | ||||
|  */ | ||||
|  | ||||
| #define DIRENT_FLAG_INCLUDE_EMPTY	1 | ||||
| #define DIRENT_FLAG_INCLUDE_REMOVED	2 | ||||
|  | ||||
| #define DIRENT_DOT_FILE		1 | ||||
| #define DIRENT_DOT_DOT_FILE	2 | ||||
| #define DIRENT_OTHER_FILE	3 | ||||
| #define DIRENT_DELETED_FILE	4 | ||||
|  | ||||
| /* | ||||
|  * Inode scan definitions | ||||
|  */ | ||||
| typedef struct ext2_struct_inode_scan *ext2_inode_scan; | ||||
|  | ||||
| /* | ||||
|  * ext2fs_scan flags | ||||
|  */ | ||||
| #define EXT2_SF_CHK_BADBLOCKS	0x0001 | ||||
| #define EXT2_SF_BAD_INODE_BLK	0x0002 | ||||
| #define EXT2_SF_BAD_EXTRA_BYTES	0x0004 | ||||
| #define EXT2_SF_SKIP_MISSING_ITABLE	0x0008 | ||||
|  | ||||
| /* | ||||
|  * ext2fs_check_if_mounted flags | ||||
|  */ | ||||
| #define EXT2_MF_MOUNTED		1 | ||||
| #define EXT2_MF_ISROOT		2 | ||||
| #define EXT2_MF_READONLY	4 | ||||
| #define EXT2_MF_SWAP		8 | ||||
| #define EXT2_MF_BUSY		16 | ||||
|  | ||||
| /* | ||||
|  * Ext2/linux mode flags.  We define them here so that we don't need | ||||
|  * to depend on the OS's sys/stat.h, since we may be compiling on a | ||||
|  * non-Linux system. | ||||
|  */ | ||||
| #define LINUX_S_IFMT  00170000 | ||||
| #define LINUX_S_IFSOCK 0140000 | ||||
| #define LINUX_S_IFLNK	 0120000 | ||||
| #define LINUX_S_IFREG  0100000 | ||||
| #define LINUX_S_IFBLK  0060000 | ||||
| #define LINUX_S_IFDIR  0040000 | ||||
| #define LINUX_S_IFCHR  0020000 | ||||
| #define LINUX_S_IFIFO  0010000 | ||||
| #define LINUX_S_ISUID  0004000 | ||||
| #define LINUX_S_ISGID  0002000 | ||||
| #define LINUX_S_ISVTX  0001000 | ||||
|  | ||||
| #define LINUX_S_IRWXU 00700 | ||||
| #define LINUX_S_IRUSR 00400 | ||||
| #define LINUX_S_IWUSR 00200 | ||||
| #define LINUX_S_IXUSR 00100 | ||||
|  | ||||
| #define LINUX_S_IRWXG 00070 | ||||
| #define LINUX_S_IRGRP 00040 | ||||
| #define LINUX_S_IWGRP 00020 | ||||
| #define LINUX_S_IXGRP 00010 | ||||
|  | ||||
| #define LINUX_S_IRWXO 00007 | ||||
| #define LINUX_S_IROTH 00004 | ||||
| #define LINUX_S_IWOTH 00002 | ||||
| #define LINUX_S_IXOTH 00001 | ||||
|  | ||||
| #define LINUX_S_ISLNK(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFLNK) | ||||
| #define LINUX_S_ISREG(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFREG) | ||||
| #define LINUX_S_ISDIR(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFDIR) | ||||
| #define LINUX_S_ISCHR(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFCHR) | ||||
| #define LINUX_S_ISBLK(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFBLK) | ||||
| #define LINUX_S_ISFIFO(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFIFO) | ||||
| #define LINUX_S_ISSOCK(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK) | ||||
|  | ||||
| /* | ||||
|  * ext2 size of an inode | ||||
|  */ | ||||
| #define EXT2_I_SIZE(i)	((i)->i_size | ((__u64) (i)->i_size_high << 32)) | ||||
|  | ||||
| /* | ||||
|  * ext2_icount_t abstraction | ||||
|  */ | ||||
| #define EXT2_ICOUNT_OPT_INCREMENT	0x01 | ||||
|  | ||||
| typedef struct ext2_icount *ext2_icount_t; | ||||
|  | ||||
| /* | ||||
|  * Flags for ext2fs_bmap | ||||
|  */ | ||||
| #define BMAP_ALLOC	0x0001 | ||||
| #define BMAP_SET	0x0002 | ||||
|  | ||||
| /* | ||||
|  * Flags for imager.c functions | ||||
|  */ | ||||
| #define IMAGER_FLAG_INODEMAP	1 | ||||
| #define IMAGER_FLAG_SPARSEWRITE	2 | ||||
|  | ||||
| /* | ||||
|  * For checking structure magic numbers... | ||||
|  */ | ||||
|  | ||||
| #define EXT2_CHECK_MAGIC(struct, code) \ | ||||
| 	  if ((struct)->magic != (code)) return (code) | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * For ext2 compression support | ||||
|  */ | ||||
| #define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff) | ||||
| #define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR) | ||||
|  | ||||
| /* | ||||
|  * Features supported by this version of the library | ||||
|  */ | ||||
| #define EXT2_LIB_FEATURE_COMPAT_SUPP	(EXT2_FEATURE_COMPAT_DIR_PREALLOC|\ | ||||
| 					 EXT2_FEATURE_COMPAT_IMAGIC_INODES|\ | ||||
| 					 EXT3_FEATURE_COMPAT_HAS_JOURNAL|\ | ||||
| 					 EXT2_FEATURE_COMPAT_RESIZE_INO|\ | ||||
| 					 EXT2_FEATURE_COMPAT_DIR_INDEX|\ | ||||
| 					 EXT2_FEATURE_COMPAT_EXT_ATTR) | ||||
|  | ||||
| /* This #ifdef is temporary until compression is fully supported */ | ||||
| #ifdef ENABLE_COMPRESSION | ||||
| #ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL | ||||
| /* If the below warning bugs you, then have | ||||
|    `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your | ||||
|    environment at configure time. */ | ||||
|  #warning "Compression support is experimental" | ||||
| #endif | ||||
| #define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\ | ||||
| 					 EXT2_FEATURE_INCOMPAT_COMPRESSION|\ | ||||
| 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ | ||||
| 					 EXT2_FEATURE_INCOMPAT_META_BG|\ | ||||
| 					 EXT3_FEATURE_INCOMPAT_RECOVER) | ||||
| #else | ||||
| #define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\ | ||||
| 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ | ||||
| 					 EXT2_FEATURE_INCOMPAT_META_BG|\ | ||||
| 					 EXT3_FEATURE_INCOMPAT_RECOVER) | ||||
| #endif | ||||
| #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ | ||||
| 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) | ||||
| /* | ||||
|  * function prototypes | ||||
|  */ | ||||
|  | ||||
| /* alloc.c */ | ||||
| extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode, | ||||
| 				  ext2fs_inode_bitmap map, ext2_ino_t *ret); | ||||
| extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, | ||||
| 				  ext2fs_block_bitmap map, blk_t *ret); | ||||
| extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, | ||||
| 					blk_t finish, int num, | ||||
| 					ext2fs_block_bitmap map, | ||||
| 					blk_t *ret); | ||||
| extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, | ||||
| 				    char *block_buf, blk_t *ret); | ||||
|  | ||||
| /* alloc_sb.c */ | ||||
| extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, | ||||
| 					dgrp_t group, | ||||
| 					ext2fs_block_bitmap bmap); | ||||
|  | ||||
| /* alloc_stats.c */ | ||||
| void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse); | ||||
| void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			       int inuse, int isdir); | ||||
| void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse); | ||||
|  | ||||
| /* alloc_tables.c */ | ||||
| extern errcode_t ext2fs_allocate_tables(ext2_filsys fs); | ||||
| extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, | ||||
| 					     ext2fs_block_bitmap bmap); | ||||
|  | ||||
| /* badblocks.c */ | ||||
| extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size); | ||||
| extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk); | ||||
| extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk); | ||||
| extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk); | ||||
| extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, | ||||
| 					       ext2_u32_iterate *ret); | ||||
| extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk); | ||||
| extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter); | ||||
| extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest); | ||||
| extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2); | ||||
|  | ||||
| extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, | ||||
| 					    int size); | ||||
| extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, | ||||
| 					   blk_t blk); | ||||
| extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb, | ||||
| 				    blk_t blk); | ||||
| extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk); | ||||
| extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk); | ||||
| extern errcode_t | ||||
| 	ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, | ||||
| 					    ext2_badblocks_iterate *ret); | ||||
| extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, | ||||
| 					 blk_t *blk); | ||||
| extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter); | ||||
| extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, | ||||
| 				       ext2_badblocks_list *dest); | ||||
| extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1, | ||||
| 				  ext2_badblocks_list bb2); | ||||
| extern int ext2fs_u32_list_count(ext2_u32_list bb); | ||||
|  | ||||
| /* bb_compat */ | ||||
| extern errcode_t badblocks_list_create(badblocks_list *ret, int size); | ||||
| extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk); | ||||
| extern int badblocks_list_test(badblocks_list bb, blk_t blk); | ||||
| extern errcode_t badblocks_list_iterate_begin(badblocks_list bb, | ||||
| 					      badblocks_iterate *ret); | ||||
| extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk); | ||||
| extern void badblocks_list_iterate_end(badblocks_iterate iter); | ||||
| extern void badblocks_list_free(badblocks_list bb); | ||||
|  | ||||
| /* bb_inode.c */ | ||||
| extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs, | ||||
| 					ext2_badblocks_list bb_list); | ||||
|  | ||||
| /* bitmaps.c */ | ||||
| extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs); | ||||
| extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs); | ||||
| extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs); | ||||
| extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); | ||||
| extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start, | ||||
| 						__u32 end, | ||||
| 						__u32 real_end, | ||||
| 						const char *descr, | ||||
| 						ext2fs_generic_bitmap *ret); | ||||
| extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, | ||||
| 					      const char *descr, | ||||
| 					      ext2fs_block_bitmap *ret); | ||||
| extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, | ||||
| 					      const char *descr, | ||||
| 					      ext2fs_inode_bitmap *ret); | ||||
| extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, | ||||
| 					       ext2_ino_t end, ext2_ino_t *oend); | ||||
| extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, | ||||
| 					       blk_t end, blk_t *oend); | ||||
| extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap); | ||||
| extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap); | ||||
| extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs); | ||||
| extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs); | ||||
|  | ||||
| /* block.c */ | ||||
| extern errcode_t ext2fs_block_iterate(ext2_filsys fs, | ||||
| 				      ext2_ino_t	ino, | ||||
| 				      int	flags, | ||||
| 				      char *block_buf, | ||||
| 				      int (*func)(ext2_filsys fs, | ||||
| 						  blk_t	*blocknr, | ||||
| 						  int	blockcnt, | ||||
| 						  void	*priv_data), | ||||
| 				      void *priv_data); | ||||
| errcode_t ext2fs_block_iterate2(ext2_filsys fs, | ||||
| 				ext2_ino_t	ino, | ||||
| 				int	flags, | ||||
| 				char *block_buf, | ||||
| 				int (*func)(ext2_filsys fs, | ||||
| 					    blk_t	*blocknr, | ||||
| 					    e2_blkcnt_t	blockcnt, | ||||
| 					    blk_t	ref_blk, | ||||
| 					    int		ref_offset, | ||||
| 					    void	*priv_data), | ||||
| 				void *priv_data); | ||||
|  | ||||
| /* bmap.c */ | ||||
| extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			     struct ext2_inode *inode, | ||||
| 			     char *block_buf, int bmap_flags, | ||||
| 			     blk_t block, blk_t *phys_blk); | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| /* bmove.c */ | ||||
| extern errcode_t ext2fs_move_blocks(ext2_filsys fs, | ||||
| 				    ext2fs_block_bitmap reserve, | ||||
| 				    ext2fs_block_bitmap alloc_map, | ||||
| 				    int flags); | ||||
| #endif | ||||
|  | ||||
| /* check_desc.c */ | ||||
| extern errcode_t ext2fs_check_desc(ext2_filsys fs); | ||||
|  | ||||
| /* closefs.c */ | ||||
| extern errcode_t ext2fs_close(ext2_filsys fs); | ||||
| extern errcode_t ext2fs_flush(ext2_filsys fs); | ||||
| extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block); | ||||
| extern int ext2fs_super_and_bgd_loc(ext2_filsys fs, | ||||
| 				    dgrp_t group, | ||||
| 				    blk_t *ret_super_blk, | ||||
| 				    blk_t *ret_old_desc_blk, | ||||
| 				    blk_t *ret_new_desc_blk, | ||||
| 				    int *ret_meta_bg); | ||||
| extern void ext2fs_update_dynamic_rev(ext2_filsys fs); | ||||
|  | ||||
| /* cmp_bitmaps.c */ | ||||
| extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, | ||||
| 					     ext2fs_block_bitmap bm2); | ||||
| extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, | ||||
| 					     ext2fs_inode_bitmap bm2); | ||||
|  | ||||
| /* dblist.c */ | ||||
|  | ||||
| extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs); | ||||
| extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist); | ||||
| extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, | ||||
| 				      blk_t blk, int blockcnt); | ||||
| extern void ext2fs_dblist_sort(ext2_dblist dblist, | ||||
| 			       int (*sortfunc)(const void *, | ||||
| 							   const void *)); | ||||
| extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, | ||||
| 	int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info, | ||||
| 		    void	*priv_data), | ||||
|        void *priv_data); | ||||
| extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, | ||||
| 				      blk_t blk, int blockcnt); | ||||
| extern errcode_t ext2fs_copy_dblist(ext2_dblist src, | ||||
| 				    ext2_dblist *dest); | ||||
| extern int ext2fs_dblist_count(ext2_dblist dblist); | ||||
|  | ||||
| /* dblist_dir.c */ | ||||
| extern errcode_t | ||||
| 	ext2fs_dblist_dir_iterate(ext2_dblist dblist, | ||||
| 				  int	flags, | ||||
| 				  char	*block_buf, | ||||
| 				  int (*func)(ext2_ino_t	dir, | ||||
| 					      int		entry, | ||||
| 					      struct ext2_dir_entry *dirent, | ||||
| 					      int	offset, | ||||
| 					      int	blocksize, | ||||
| 					      char	*buf, | ||||
| 					      void	*priv_data), | ||||
| 				  void *priv_data); | ||||
|  | ||||
| /* dirblock.c */ | ||||
| extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, | ||||
| 				       void *buf); | ||||
| extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, | ||||
| 					void *buf, int flags); | ||||
| extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, | ||||
| 					void *buf); | ||||
| extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, | ||||
| 					 void *buf, int flags); | ||||
|  | ||||
| /* dirhash.c */ | ||||
| extern errcode_t ext2fs_dirhash(int version, const char *name, int len, | ||||
| 				const __u32 *seed, | ||||
| 				ext2_dirhash_t *ret_hash, | ||||
| 				ext2_dirhash_t *ret_minor_hash); | ||||
|  | ||||
|  | ||||
| /* dir_iterate.c */ | ||||
| extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, | ||||
| 			      ext2_ino_t dir, | ||||
| 			      int flags, | ||||
| 			      char *block_buf, | ||||
| 			      int (*func)(struct ext2_dir_entry *dirent, | ||||
| 					  int	offset, | ||||
| 					  int	blocksize, | ||||
| 					  char	*buf, | ||||
| 					  void	*priv_data), | ||||
| 			      void *priv_data); | ||||
| extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs, | ||||
| 			      ext2_ino_t dir, | ||||
| 			      int flags, | ||||
| 			      char *block_buf, | ||||
| 			      int (*func)(ext2_ino_t	dir, | ||||
| 					  int	entry, | ||||
| 					  struct ext2_dir_entry *dirent, | ||||
| 					  int	offset, | ||||
| 					  int	blocksize, | ||||
| 					  char	*buf, | ||||
| 					  void	*priv_data), | ||||
| 			      void *priv_data); | ||||
|  | ||||
| /* dupfs.c */ | ||||
| extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest); | ||||
|  | ||||
| /* expanddir.c */ | ||||
| extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir); | ||||
|  | ||||
| /* ext_attr.c */ | ||||
| extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf); | ||||
| extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, | ||||
| 				       void *buf); | ||||
| extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, | ||||
| 					   char *block_buf, | ||||
| 					   int adjust, __u32 *newcount); | ||||
|  | ||||
| /* fileio.c */ | ||||
| extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				   struct ext2_inode *inode, | ||||
| 				   int flags, ext2_file_t *ret); | ||||
| extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				  int flags, ext2_file_t *ret); | ||||
| extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file); | ||||
| extern errcode_t ext2fs_file_close(ext2_file_t file); | ||||
| extern errcode_t ext2fs_file_flush(ext2_file_t file); | ||||
| extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf, | ||||
| 				  unsigned int wanted, unsigned int *got); | ||||
| extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, | ||||
| 				   unsigned int nbytes, unsigned int *written); | ||||
| extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, | ||||
| 				   int whence, __u64 *ret_pos); | ||||
| extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, | ||||
| 				   int whence, ext2_off_t *ret_pos); | ||||
| errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size); | ||||
| extern ext2_off_t ext2fs_file_get_size(ext2_file_t file); | ||||
| extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size); | ||||
|  | ||||
| /* finddev.c */ | ||||
| extern char *ext2fs_find_block_device(dev_t device); | ||||
|  | ||||
| /* flushb.c */ | ||||
| extern errcode_t ext2fs_sync_device(int fd, int flushb); | ||||
|  | ||||
| /* freefs.c */ | ||||
| extern void ext2fs_free(ext2_filsys fs); | ||||
| extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap); | ||||
| extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap); | ||||
| extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap); | ||||
| extern void ext2fs_free_dblist(ext2_dblist dblist); | ||||
| extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb); | ||||
| extern void ext2fs_u32_list_free(ext2_u32_list bb); | ||||
|  | ||||
| /* getsize.c */ | ||||
| extern errcode_t ext2fs_get_device_size(const char *file, int blocksize, | ||||
| 					blk_t *retblocks); | ||||
|  | ||||
| /* getsectsize.c */ | ||||
| errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize); | ||||
|  | ||||
| /* imager.c */ | ||||
| extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags); | ||||
| extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags); | ||||
| extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags); | ||||
| extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags); | ||||
| extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags); | ||||
| extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags); | ||||
|  | ||||
| /* ind_block.c */ | ||||
| errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf); | ||||
| errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf); | ||||
|  | ||||
| /* initialize.c */ | ||||
| extern errcode_t ext2fs_initialize(const char *name, int flags, | ||||
| 				   struct ext2_super_block *param, | ||||
| 				   io_manager manager, ext2_filsys *ret_fs); | ||||
|  | ||||
| /* icount.c */ | ||||
| extern void ext2fs_free_icount(ext2_icount_t icount); | ||||
| extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, | ||||
| 				       unsigned int size, | ||||
| 				       ext2_icount_t hint, ext2_icount_t *ret); | ||||
| extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, | ||||
| 				      unsigned int size, | ||||
| 				      ext2_icount_t *ret); | ||||
| extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 				     __u16 *ret); | ||||
| extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 					 __u16 *ret); | ||||
| extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 					 __u16 *ret); | ||||
| extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 				     __u16 count); | ||||
| extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount); | ||||
| errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *); | ||||
|  | ||||
| /* inode.c */ | ||||
| extern errcode_t ext2fs_flush_icache(ext2_filsys fs); | ||||
| extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, | ||||
| 					    ext2_ino_t *ino, | ||||
| 					    struct ext2_inode *inode, | ||||
| 					    int bufsize); | ||||
| extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, | ||||
| 				  ext2_inode_scan *ret_scan); | ||||
| extern void ext2fs_close_inode_scan(ext2_inode_scan scan); | ||||
| extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, | ||||
| 			       struct ext2_inode *inode); | ||||
| extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, | ||||
| 						   int	group); | ||||
| extern void ext2fs_set_inode_callback | ||||
| 	(ext2_inode_scan scan, | ||||
| 	 errcode_t (*done_group)(ext2_filsys fs, | ||||
| 				 dgrp_t group, | ||||
| 				 void * priv_data), | ||||
| 	 void *done_group_data); | ||||
| extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, | ||||
| 				   int clear_flags); | ||||
| extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, | ||||
| 					struct ext2_inode * inode, | ||||
| 					int bufsize); | ||||
| extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, | ||||
| 			    struct ext2_inode * inode); | ||||
| extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, | ||||
| 					 struct ext2_inode * inode, | ||||
| 					 int bufsize); | ||||
| extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			    struct ext2_inode * inode); | ||||
| extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			    struct ext2_inode * inode); | ||||
| extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); | ||||
| extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino); | ||||
|  | ||||
| /* inode_io.c */ | ||||
| extern io_manager inode_io_manager; | ||||
| extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, | ||||
| 					char **name); | ||||
| extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino, | ||||
| 					 struct ext2_inode *inode, | ||||
| 					 char **name); | ||||
|  | ||||
| /* ismounted.c */ | ||||
| extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags); | ||||
| extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, | ||||
| 					  char *mtpt, int mtlen); | ||||
|  | ||||
| /* namei.c */ | ||||
| extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||||
| 			 int namelen, char *buf, ext2_ino_t *inode); | ||||
| extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, | ||||
| 			const char *name, ext2_ino_t *inode); | ||||
| errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, | ||||
| 			      const char *name, ext2_ino_t *inode); | ||||
| extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, | ||||
| 			ext2_ino_t inode, ext2_ino_t *res_inode); | ||||
|  | ||||
| /* native.c */ | ||||
| int ext2fs_native_flag(void); | ||||
|  | ||||
| /* newdir.c */ | ||||
| extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, | ||||
| 				ext2_ino_t parent_ino, char **block); | ||||
|  | ||||
| /* mkdir.c */ | ||||
| extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, | ||||
| 			      const char *name); | ||||
|  | ||||
| /* mkjournal.c */ | ||||
| extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, | ||||
| 						  __u32 size, int flags, | ||||
| 						  char  **ret_jsb); | ||||
| extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, | ||||
| 					   ext2_filsys journal_dev); | ||||
| extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, | ||||
| 					  int flags); | ||||
|  | ||||
| /* openfs.c */ | ||||
| extern errcode_t ext2fs_open(const char *name, int flags, int superblock, | ||||
| 			     unsigned int block_size, io_manager manager, | ||||
| 			     ext2_filsys *ret_fs); | ||||
| extern errcode_t ext2fs_open2(const char *name, const char *io_options, | ||||
| 			      int flags, int superblock, | ||||
| 			      unsigned int block_size, io_manager manager, | ||||
| 			      ext2_filsys *ret_fs); | ||||
| extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, | ||||
| 					 dgrp_t i); | ||||
| errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io); | ||||
| errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io); | ||||
| errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io); | ||||
|  | ||||
| /* get_pathname.c */ | ||||
| extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, | ||||
| 			       char **name); | ||||
|  | ||||
| /* link.c */ | ||||
| errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||||
| 		      ext2_ino_t ino, int flags); | ||||
| errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||||
| 			ext2_ino_t ino, int flags); | ||||
|  | ||||
| /* read_bb.c */ | ||||
| extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs, | ||||
| 				      ext2_badblocks_list *bb_list); | ||||
|  | ||||
| /* read_bb_file.c */ | ||||
| extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, | ||||
| 				      ext2_badblocks_list *bb_list, | ||||
| 				      void *priv_data, | ||||
| 				      void (*invalid)(ext2_filsys fs, | ||||
| 						      blk_t blk, | ||||
| 						      char *badstr, | ||||
| 						      void *priv_data)); | ||||
| extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, | ||||
| 				     ext2_badblocks_list *bb_list, | ||||
| 				     void (*invalid)(ext2_filsys fs, | ||||
| 						     blk_t blk)); | ||||
|  | ||||
| /* res_gdt.c */ | ||||
| extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); | ||||
|  | ||||
| /* rs_bitmap.c */ | ||||
| extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, | ||||
| 					      __u32 new_real_end, | ||||
| 					      ext2fs_generic_bitmap bmap); | ||||
| extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, | ||||
| 					    ext2fs_inode_bitmap bmap); | ||||
| extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, | ||||
| 					    ext2fs_block_bitmap bmap); | ||||
| extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, | ||||
| 				    ext2fs_generic_bitmap *dest); | ||||
|  | ||||
| /* swapfs.c */ | ||||
| extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, | ||||
| 				 int has_header); | ||||
| extern void ext2fs_swap_super(struct ext2_super_block * super); | ||||
| extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp); | ||||
| extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, | ||||
| 				   struct ext2_inode_large *f, int hostorder, | ||||
| 				   int bufsize); | ||||
| extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t, | ||||
| 			      struct ext2_inode *f, int hostorder); | ||||
|  | ||||
| /* valid_blk.c */ | ||||
| extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode); | ||||
|  | ||||
| /* version.c */ | ||||
| extern int ext2fs_parse_version_string(const char *ver_string); | ||||
| extern int ext2fs_get_library_version(const char **ver_string, | ||||
| 				      const char **date_string); | ||||
|  | ||||
| /* write_bb_file.c */ | ||||
| extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, | ||||
| 				      unsigned int flags, | ||||
| 				      FILE *f); | ||||
|  | ||||
|  | ||||
| /* inline functions */ | ||||
| extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr); | ||||
| extern errcode_t ext2fs_free_mem(void *ptr); | ||||
| extern errcode_t ext2fs_resize_mem(unsigned long old_size, | ||||
| 				   unsigned long size, void *ptr); | ||||
| extern void ext2fs_mark_super_dirty(ext2_filsys fs); | ||||
| extern void ext2fs_mark_changed(ext2_filsys fs); | ||||
| extern int ext2fs_test_changed(ext2_filsys fs); | ||||
| extern void ext2fs_mark_valid(ext2_filsys fs); | ||||
| extern void ext2fs_unmark_valid(ext2_filsys fs); | ||||
| extern int ext2fs_test_valid(ext2_filsys fs); | ||||
| extern void ext2fs_mark_ib_dirty(ext2_filsys fs); | ||||
| extern void ext2fs_mark_bb_dirty(ext2_filsys fs); | ||||
| extern int ext2fs_test_ib_dirty(ext2_filsys fs); | ||||
| extern int ext2fs_test_bb_dirty(ext2_filsys fs); | ||||
| extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk); | ||||
| extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino); | ||||
| extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs, | ||||
| 				      struct ext2_inode *inode); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,87 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ext2fsP.h --- private header file for ext2 library | ||||
|  * | ||||
|  * Copyright (C) 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * Badblocks list | ||||
|  */ | ||||
| struct ext2_struct_u32_list { | ||||
| 	int	magic; | ||||
| 	int	num; | ||||
| 	int	size; | ||||
| 	__u32	*list; | ||||
| 	int	badblocks_flags; | ||||
| }; | ||||
|  | ||||
| struct ext2_struct_u32_iterate { | ||||
| 	int			magic; | ||||
| 	ext2_u32_list		bb; | ||||
| 	int			ptr; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Directory block iterator definition | ||||
|  */ | ||||
| struct ext2_struct_dblist { | ||||
| 	int			magic; | ||||
| 	ext2_filsys		fs; | ||||
| 	ext2_ino_t		size; | ||||
| 	ext2_ino_t		count; | ||||
| 	int			sorted; | ||||
| 	struct ext2_db_entry *	list; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * For directory iterators | ||||
|  */ | ||||
| struct dir_context { | ||||
| 	ext2_ino_t		dir; | ||||
| 	int		flags; | ||||
| 	char		*buf; | ||||
| 	int (*func)(ext2_ino_t	dir, | ||||
| 		    int	entry, | ||||
| 		    struct ext2_dir_entry *dirent, | ||||
| 		    int	offset, | ||||
| 		    int	blocksize, | ||||
| 		    char	*buf, | ||||
| 		    void	*priv_data); | ||||
| 	void		*priv_data; | ||||
| 	errcode_t	errcode; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Inode cache structure | ||||
|  */ | ||||
| struct ext2_inode_cache { | ||||
| 	void *				buffer; | ||||
| 	blk_t				buffer_blk; | ||||
| 	int				cache_last; | ||||
| 	int				cache_size; | ||||
| 	int				refcount; | ||||
| 	struct ext2_inode_cache_ent	*cache; | ||||
| }; | ||||
|  | ||||
| struct ext2_inode_cache_ent { | ||||
| 	ext2_ino_t		ino; | ||||
| 	struct ext2_inode	inode; | ||||
| }; | ||||
|  | ||||
| /* Function prototypes */ | ||||
|  | ||||
| extern int ext2fs_process_dir_block(ext2_filsys		fs, | ||||
| 				    blk_t		*blocknr, | ||||
| 				    e2_blkcnt_t		blockcnt, | ||||
| 				    blk_t		ref_block, | ||||
| 				    int			ref_offset, | ||||
| 				    void		*priv_data); | ||||
| @@ -1,365 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ext2fs.h --- ext2fs | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include "ext2fs.h" | ||||
| #include "bitops.h" | ||||
| #include <string.h> | ||||
|  | ||||
| /* | ||||
|  *  Allocate memory | ||||
|  */ | ||||
| errcode_t ext2fs_get_mem(unsigned long size, void *ptr) | ||||
| { | ||||
| 	void **pp = (void **)ptr; | ||||
|  | ||||
| 	*pp = malloc(size); | ||||
| 	if (!*pp) | ||||
| 		return EXT2_ET_NO_MEMORY; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Free memory | ||||
|  */ | ||||
| errcode_t ext2fs_free_mem(void *ptr) | ||||
| { | ||||
| 	void **pp = (void **)ptr; | ||||
|  | ||||
| 	free(*pp); | ||||
| 	*pp = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *  Resize memory | ||||
|  */ | ||||
| errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size, | ||||
| 				     unsigned long size, void *ptr) | ||||
| { | ||||
| 	void *p; | ||||
|  | ||||
| 	/* Use "memcpy" for pointer assignments here to avoid problems | ||||
| 	 * with C99 strict type aliasing rules. */ | ||||
| 	memcpy(&p, ptr, sizeof (p)); | ||||
| 	p = xrealloc(p, size); | ||||
| 	memcpy(ptr, &p, sizeof (p)); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mark a filesystem superblock as dirty | ||||
|  */ | ||||
| void ext2fs_mark_super_dirty(ext2_filsys fs) | ||||
| { | ||||
| 	fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mark a filesystem as changed | ||||
|  */ | ||||
| void ext2fs_mark_changed(ext2_filsys fs) | ||||
| { | ||||
| 	fs->flags |= EXT2_FLAG_CHANGED; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Check to see if a filesystem has changed | ||||
|  */ | ||||
| int ext2fs_test_changed(ext2_filsys fs) | ||||
| { | ||||
| 	return (fs->flags & EXT2_FLAG_CHANGED); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mark a filesystem as valid | ||||
|  */ | ||||
| void ext2fs_mark_valid(ext2_filsys fs) | ||||
| { | ||||
| 	fs->flags |= EXT2_FLAG_VALID; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mark a filesystem as NOT valid | ||||
|  */ | ||||
| void ext2fs_unmark_valid(ext2_filsys fs) | ||||
| { | ||||
| 	fs->flags &= ~EXT2_FLAG_VALID; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Check to see if a filesystem is valid | ||||
|  */ | ||||
| int ext2fs_test_valid(ext2_filsys fs) | ||||
| { | ||||
| 	return (fs->flags & EXT2_FLAG_VALID); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mark the inode bitmap as dirty | ||||
|  */ | ||||
| void ext2fs_mark_ib_dirty(ext2_filsys fs) | ||||
| { | ||||
| 	fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mark the block bitmap as dirty | ||||
|  */ | ||||
| void ext2fs_mark_bb_dirty(ext2_filsys fs) | ||||
| { | ||||
| 	fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Check to see if a filesystem's inode bitmap is dirty | ||||
|  */ | ||||
| int ext2fs_test_ib_dirty(ext2_filsys fs) | ||||
| { | ||||
| 	return (fs->flags & EXT2_FLAG_IB_DIRTY); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Check to see if a filesystem's block bitmap is dirty | ||||
|  */ | ||||
| int ext2fs_test_bb_dirty(ext2_filsys fs) | ||||
| { | ||||
| 	return (fs->flags & EXT2_FLAG_BB_DIRTY); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the group # of a block | ||||
|  */ | ||||
| int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk) | ||||
| { | ||||
| 	return (blk - fs->super->s_first_data_block) / | ||||
| 		fs->super->s_blocks_per_group; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the group # of an inode number | ||||
|  */ | ||||
| int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino) | ||||
| { | ||||
| 	return (ino - 1) / fs->super->s_inodes_per_group; | ||||
| } | ||||
|  | ||||
| blk_t ext2fs_inode_data_blocks(ext2_filsys fs, | ||||
| 					struct ext2_inode *inode) | ||||
| { | ||||
| 	return inode->i_blocks - | ||||
| 		(inode->i_file_acl ? fs->blocksize >> 9 : 0); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| __u16 ext2fs_swab16(__u16 val) | ||||
| { | ||||
| 	return (val >> 8) | (val << 8); | ||||
| } | ||||
|  | ||||
| __u32 ext2fs_swab32(__u32 val) | ||||
| { | ||||
| 	return ((val>>24) | ((val>>8)&0xFF00) | | ||||
| 		((val<<8)&0xFF0000) | (val<<24)); | ||||
| } | ||||
|  | ||||
| int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||||
| 					blk_t bitno); | ||||
|  | ||||
| int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||||
| 					blk_t bitno) | ||||
| { | ||||
| 	if ((bitno < bitmap->start) || (bitno > bitmap->end)) { | ||||
| 		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 				       blk_t block) | ||||
| { | ||||
| 	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) | ||||
| 				       bitmap, | ||||
| 					  block); | ||||
| } | ||||
|  | ||||
| int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					 blk_t block) | ||||
| { | ||||
| 	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, | ||||
| 					    block); | ||||
| } | ||||
|  | ||||
| int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 				       blk_t block) | ||||
| { | ||||
| 	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, | ||||
| 					  block); | ||||
| } | ||||
|  | ||||
| int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 				       ext2_ino_t inode) | ||||
| { | ||||
| 	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, | ||||
| 					  inode); | ||||
| } | ||||
|  | ||||
| int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					 ext2_ino_t inode) | ||||
| { | ||||
| 	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, | ||||
| 				     inode); | ||||
| } | ||||
|  | ||||
| int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 				       ext2_ino_t inode) | ||||
| { | ||||
| 	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, | ||||
| 					  inode); | ||||
| } | ||||
|  | ||||
| void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					    blk_t block) | ||||
| { | ||||
| 	ext2fs_set_bit(block - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					      blk_t block) | ||||
| { | ||||
| 	ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, | ||||
| 					    blk_t block) | ||||
| { | ||||
| 	return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					    ext2_ino_t inode) | ||||
| { | ||||
| 	ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					      ext2_ino_t inode) | ||||
| { | ||||
| 	ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||||
| 					   ext2_ino_t inode) | ||||
| { | ||||
| 	return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap) | ||||
| { | ||||
| 	return bitmap->start; | ||||
| } | ||||
|  | ||||
| ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap) | ||||
| { | ||||
| 	return bitmap->start; | ||||
| } | ||||
|  | ||||
| blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap) | ||||
| { | ||||
| 	return bitmap->end; | ||||
| } | ||||
|  | ||||
| ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap) | ||||
| { | ||||
| 	return bitmap->end; | ||||
| } | ||||
|  | ||||
| int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					    blk_t block, int num) | ||||
| { | ||||
| 	int	i; | ||||
|  | ||||
| 	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { | ||||
| 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, | ||||
| 				   block, bitmap->description); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	for (i=0; i < num; i++) { | ||||
| 		if (ext2fs_fast_test_block_bitmap(bitmap, block+i)) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 						 blk_t block, int num) | ||||
| { | ||||
| 	int	i; | ||||
|  | ||||
| 	for (i=0; i < num; i++) { | ||||
| 		if (ext2fs_fast_test_block_bitmap(bitmap, block+i)) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					     blk_t block, int num) | ||||
| { | ||||
| 	int	i; | ||||
|  | ||||
| 	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { | ||||
| 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, | ||||
| 				   bitmap->description); | ||||
| 		return; | ||||
| 	} | ||||
| 	for (i=0; i < num; i++) | ||||
| 		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 						  blk_t block, int num) | ||||
| { | ||||
| 	int	i; | ||||
|  | ||||
| 	for (i=0; i < num; i++) | ||||
| 		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 					       blk_t block, int num) | ||||
| { | ||||
| 	int	i; | ||||
|  | ||||
| 	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { | ||||
| 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, | ||||
| 				   bitmap->description); | ||||
| 		return; | ||||
| 	} | ||||
| 	for (i=0; i < num; i++) | ||||
| 		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||||
| 						    blk_t block, int num) | ||||
| { | ||||
| 	int	i; | ||||
| 	for (i=0; i < num; i++) | ||||
| 		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
| @@ -1,101 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ext_attr.c --- extended attribute blocks | ||||
|  * | ||||
|  * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> | ||||
|  * | ||||
|  * Copyright (C) 2002 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2_ext_attr.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	retval = io_channel_read_blk(fs->io, block, 1, buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if ((fs->flags & (EXT2_FLAG_SWAP_BYTES| | ||||
| 			  EXT2_FLAG_SWAP_BYTES_READ)) != 0) | ||||
| 		ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1); | ||||
| #endif | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	char		*write_buf; | ||||
| 	char		*buf = NULL; | ||||
|  | ||||
| 	if (BB_BIG_ENDIAN && ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize, &buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		write_buf = buf; | ||||
| 		ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1); | ||||
| 	} else | ||||
| 		write_buf = (char *) inbuf; | ||||
| 	retval = io_channel_write_blk(fs->io, block, 1, write_buf); | ||||
| 	if (buf) | ||||
| 		ext2fs_free_mem(&buf); | ||||
| 	if (!retval) | ||||
| 		ext2fs_mark_changed(fs); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function adjusts the reference count of the EA block. | ||||
|  */ | ||||
| errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, | ||||
| 				    char *block_buf, int adjust, | ||||
| 				    __u32 *newcount) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	struct ext2_ext_attr_header *header; | ||||
| 	char	*buf = NULL; | ||||
|  | ||||
| 	if ((blk >= fs->super->s_blocks_count) || | ||||
| 	    (blk < fs->super->s_first_data_block)) | ||||
| 		return EXT2_ET_BAD_EA_BLOCK_NUM; | ||||
|  | ||||
| 	if (!block_buf) { | ||||
| 		retval = ext2fs_get_mem(fs->blocksize, &buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		block_buf = buf; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_read_ext_attr(fs, blk, block_buf); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
|  | ||||
| 	header = (struct ext2_ext_attr_header *) block_buf; | ||||
| 	header->h_refcount += adjust; | ||||
| 	if (newcount) | ||||
| 		*newcount = header->h_refcount; | ||||
|  | ||||
| 	retval = ext2fs_write_ext_attr(fs, blk, block_buf); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
|  | ||||
| errout: | ||||
| 	if (buf) | ||||
| 		ext2fs_free_mem(&buf); | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,377 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * fileio.c --- Simple file I/O routines | ||||
|  * | ||||
|  * Copyright (C) 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct ext2_file { | ||||
| 	errcode_t		magic; | ||||
| 	ext2_filsys		fs; | ||||
| 	ext2_ino_t		ino; | ||||
| 	struct ext2_inode	inode; | ||||
| 	int			flags; | ||||
| 	__u64			pos; | ||||
| 	blk_t			blockno; | ||||
| 	blk_t			physblock; | ||||
| 	char			*buf; | ||||
| }; | ||||
|  | ||||
| #define BMAP_BUFFER (file->buf + fs->blocksize) | ||||
|  | ||||
| errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			    struct ext2_inode *inode, | ||||
| 			    int flags, ext2_file_t *ret) | ||||
| { | ||||
| 	ext2_file_t	file; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	/* | ||||
| 	 * Don't let caller create or open a file for writing if the | ||||
| 	 * filesystem is read-only. | ||||
| 	 */ | ||||
| 	if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) && | ||||
| 	    !(fs->flags & EXT2_FLAG_RW)) | ||||
| 		return EXT2_ET_RO_FILSYS; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_file), &file); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	memset(file, 0, sizeof(struct ext2_file)); | ||||
| 	file->magic = EXT2_ET_MAGIC_EXT2_FILE; | ||||
| 	file->fs = fs; | ||||
| 	file->ino = ino; | ||||
| 	file->flags = flags & EXT2_FILE_MASK; | ||||
|  | ||||
| 	if (inode) { | ||||
| 		memcpy(&file->inode, inode, sizeof(struct ext2_inode)); | ||||
| 	} else { | ||||
| 		retval = ext2fs_read_inode(fs, ino, &file->inode); | ||||
| 		if (retval) | ||||
| 			goto fail; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf); | ||||
| 	if (retval) | ||||
| 		goto fail; | ||||
|  | ||||
| 	*ret = file; | ||||
| 	return 0; | ||||
|  | ||||
| fail: | ||||
| 	ext2fs_free_mem(&file->buf); | ||||
| 	ext2fs_free_mem(&file); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			   int flags, ext2_file_t *ret) | ||||
| { | ||||
| 	return ext2fs_file_open2(fs, ino, NULL, flags, ret); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function returns the filesystem handle of a file from the structure | ||||
|  */ | ||||
| ext2_filsys ext2fs_file_get_fs(ext2_file_t file) | ||||
| { | ||||
| 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) | ||||
| 		return 0; | ||||
| 	return file->fs; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function flushes the dirty block buffer out to disk if | ||||
|  * necessary. | ||||
|  */ | ||||
| errcode_t ext2fs_file_flush(ext2_file_t file) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	ext2_filsys fs; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); | ||||
| 	fs = file->fs; | ||||
|  | ||||
| 	if (!(file->flags & EXT2_FILE_BUF_VALID) || | ||||
| 	    !(file->flags & EXT2_FILE_BUF_DIRTY)) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * OK, the physical block hasn't been allocated yet. | ||||
| 	 * Allocate it. | ||||
| 	 */ | ||||
| 	if (!file->physblock) { | ||||
| 		retval = ext2fs_bmap(fs, file->ino, &file->inode, | ||||
| 				     BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0, | ||||
| 				     file->blockno, &file->physblock); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	retval = io_channel_write_blk(fs->io, file->physblock, | ||||
| 				      1, file->buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	file->flags &= ~EXT2_FILE_BUF_DIRTY; | ||||
|  | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function synchronizes the file's block buffer and the current | ||||
|  * file position, possibly invalidating block buffer if necessary | ||||
|  */ | ||||
| static errcode_t sync_buffer_position(ext2_file_t file) | ||||
| { | ||||
| 	blk_t	b; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	b = file->pos / file->fs->blocksize; | ||||
| 	if (b != file->blockno) { | ||||
| 		retval = ext2fs_file_flush(file); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		file->flags &= ~EXT2_FILE_BUF_VALID; | ||||
| 	} | ||||
| 	file->blockno = b; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function loads the file's block buffer with valid data from | ||||
|  * the disk as necessary. | ||||
|  * | ||||
|  * If dontfill is true, then skip initializing the buffer since we're | ||||
|  * going to be replacing its entire contents anyway.  If set, then the | ||||
|  * function basically only sets file->physblock and EXT2_FILE_BUF_VALID | ||||
|  */ | ||||
| #define DONTFILL 1 | ||||
| static errcode_t load_buffer(ext2_file_t file, int dontfill) | ||||
| { | ||||
| 	ext2_filsys	fs = file->fs; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (!(file->flags & EXT2_FILE_BUF_VALID)) { | ||||
| 		retval = ext2fs_bmap(fs, file->ino, &file->inode, | ||||
| 				     BMAP_BUFFER, 0, file->blockno, | ||||
| 				     &file->physblock); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		if (!dontfill) { | ||||
| 			if (file->physblock) { | ||||
| 				retval = io_channel_read_blk(fs->io, | ||||
| 							     file->physblock, | ||||
| 							     1, file->buf); | ||||
| 				if (retval) | ||||
| 					return retval; | ||||
| 			} else | ||||
| 				memset(file->buf, 0, fs->blocksize); | ||||
| 		} | ||||
| 		file->flags |= EXT2_FILE_BUF_VALID; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_file_close(ext2_file_t file) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); | ||||
|  | ||||
| 	retval = ext2fs_file_flush(file); | ||||
|  | ||||
| 	ext2fs_free_mem(&file->buf); | ||||
| 	ext2fs_free_mem(&file); | ||||
|  | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_file_read(ext2_file_t file, void *buf, | ||||
| 			   unsigned int wanted, unsigned int *got) | ||||
| { | ||||
| 	ext2_filsys	fs; | ||||
| 	errcode_t	retval = 0; | ||||
| 	unsigned int	start, c, count = 0; | ||||
| 	__u64		left; | ||||
| 	char		*ptr = (char *) buf; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); | ||||
| 	fs = file->fs; | ||||
|  | ||||
| 	while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) { | ||||
| 		retval = sync_buffer_position(file); | ||||
| 		if (retval) | ||||
| 			goto fail; | ||||
| 		retval = load_buffer(file, 0); | ||||
| 		if (retval) | ||||
| 			goto fail; | ||||
|  | ||||
| 		start = file->pos % fs->blocksize; | ||||
| 		c = fs->blocksize - start; | ||||
| 		if (c > wanted) | ||||
| 			c = wanted; | ||||
| 		left = EXT2_I_SIZE(&file->inode) - file->pos; | ||||
| 		if (c > left) | ||||
| 			c = left; | ||||
|  | ||||
| 		memcpy(ptr, file->buf+start, c); | ||||
| 		file->pos += c; | ||||
| 		ptr += c; | ||||
| 		count += c; | ||||
| 		wanted -= c; | ||||
| 	} | ||||
|  | ||||
| fail: | ||||
| 	if (got) | ||||
| 		*got = count; | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, | ||||
| 			    unsigned int nbytes, unsigned int *written) | ||||
| { | ||||
| 	ext2_filsys	fs; | ||||
| 	errcode_t	retval = 0; | ||||
| 	unsigned int	start, c, count = 0; | ||||
| 	const char	*ptr = (const char *) buf; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); | ||||
| 	fs = file->fs; | ||||
|  | ||||
| 	if (!(file->flags & EXT2_FILE_WRITE)) | ||||
| 		return EXT2_ET_FILE_RO; | ||||
|  | ||||
| 	while (nbytes > 0) { | ||||
| 		retval = sync_buffer_position(file); | ||||
| 		if (retval) | ||||
| 			goto fail; | ||||
|  | ||||
| 		start = file->pos % fs->blocksize; | ||||
| 		c = fs->blocksize - start; | ||||
| 		if (c > nbytes) | ||||
| 			c = nbytes; | ||||
|  | ||||
| 		/* | ||||
| 		 * We only need to do a read-modify-update cycle if | ||||
| 		 * we're doing a partial write. | ||||
| 		 */ | ||||
| 		retval = load_buffer(file, (c == fs->blocksize)); | ||||
| 		if (retval) | ||||
| 			goto fail; | ||||
|  | ||||
| 		file->flags |= EXT2_FILE_BUF_DIRTY; | ||||
| 		memcpy(file->buf+start, ptr, c); | ||||
| 		file->pos += c; | ||||
| 		ptr += c; | ||||
| 		count += c; | ||||
| 		nbytes -= c; | ||||
| 	} | ||||
|  | ||||
| fail: | ||||
| 	if (written) | ||||
| 		*written = count; | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, | ||||
| 			    int whence, __u64 *ret_pos) | ||||
| { | ||||
| 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); | ||||
|  | ||||
| 	if (whence == EXT2_SEEK_SET) | ||||
| 		file->pos = offset; | ||||
| 	else if (whence == EXT2_SEEK_CUR) | ||||
| 		file->pos += offset; | ||||
| 	else if (whence == EXT2_SEEK_END) | ||||
| 		file->pos = EXT2_I_SIZE(&file->inode) + offset; | ||||
| 	else | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	if (ret_pos) | ||||
| 		*ret_pos = file->pos; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, | ||||
| 			    int whence, ext2_off_t *ret_pos) | ||||
| { | ||||
| 	__u64		loffset, ret_loffset; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	loffset = offset; | ||||
| 	retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset); | ||||
| 	if (ret_pos) | ||||
| 		*ret_pos = (ext2_off_t) ret_loffset; | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This function returns the size of the file, according to the inode | ||||
|  */ | ||||
| errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size) | ||||
| { | ||||
| 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) | ||||
| 		return EXT2_ET_MAGIC_EXT2_FILE; | ||||
| 	*ret_size = EXT2_I_SIZE(&file->inode); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function returns the size of the file, according to the inode | ||||
|  */ | ||||
| ext2_off_t ext2fs_file_get_size(ext2_file_t file) | ||||
| { | ||||
| 	__u64	size; | ||||
|  | ||||
| 	if (ext2fs_file_get_lsize(file, &size)) | ||||
| 		return 0; | ||||
| 	if ((size >> 32) != 0) | ||||
| 		return 0; | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function sets the size of the file, truncating it if necessary | ||||
|  * | ||||
|  * XXX still need to call truncate | ||||
|  */ | ||||
| errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); | ||||
|  | ||||
| 	file->inode.i_size = size; | ||||
| 	file->inode.i_size_high = 0; | ||||
| 	if (file->ino) { | ||||
| 		retval = ext2fs_write_inode(file->fs, file->ino, &file->inode); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * XXX truncate inode if necessary | ||||
| 	 */ | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,199 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * finddev.c -- this routine attempts to find a particular device in | ||||
|  *	/dev | ||||
|  * | ||||
|  * Copyright (C) 2000 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #ifdef HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #ifdef HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #include <dirent.h> | ||||
| #ifdef HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_MKDEV_H | ||||
| #include <sys/mkdev.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct dir_list { | ||||
| 	char	*name; | ||||
| 	struct dir_list *next; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * This function adds an entry to the directory list | ||||
|  */ | ||||
| static void add_to_dirlist(const char *name, struct dir_list **list) | ||||
| { | ||||
| 	struct dir_list *dp; | ||||
|  | ||||
| 	dp = xmalloc(sizeof(struct dir_list)); | ||||
| 	dp->name = xmalloc(strlen(name)+1); | ||||
| 	strcpy(dp->name, name); | ||||
| 	dp->next = *list; | ||||
| 	*list = dp; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function frees a directory list | ||||
|  */ | ||||
| static void free_dirlist(struct dir_list **list) | ||||
| { | ||||
| 	struct dir_list *dp, *next; | ||||
|  | ||||
| 	for (dp = *list; dp; dp = next) { | ||||
| 		next = dp->next; | ||||
| 		free(dp->name); | ||||
| 		free(dp); | ||||
| 	} | ||||
| 	*list = 0; | ||||
| } | ||||
|  | ||||
| static int scan_dir(char *dir_name, dev_t device, struct dir_list **list, | ||||
| 		    char **ret_path) | ||||
| { | ||||
| 	DIR	*dir; | ||||
| 	struct dirent *dp; | ||||
| 	char	path[1024], *cp; | ||||
| 	int	dirlen; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	dirlen = strlen(dir_name); | ||||
| 	if ((dir = opendir(dir_name)) == NULL) | ||||
| 		return errno; | ||||
| 	dp = readdir(dir); | ||||
| 	while (dp) { | ||||
| 		if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path)) | ||||
| 			goto skip_to_next; | ||||
| 		if (dp->d_name[0] == '.' && | ||||
| 		    ((dp->d_name[1] == 0) || | ||||
| 		     ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) | ||||
| 			goto skip_to_next; | ||||
| 		sprintf(path, "%s/%s", dir_name, dp->d_name); | ||||
| 		if (stat(path, &st) < 0) | ||||
| 			goto skip_to_next; | ||||
| 		if (S_ISDIR(st.st_mode)) | ||||
| 			add_to_dirlist(path, list); | ||||
| 		if (S_ISBLK(st.st_mode) && st.st_rdev == device) { | ||||
| 			cp = xmalloc(strlen(path)+1); | ||||
| 			strcpy(cp, path); | ||||
| 			*ret_path = cp; | ||||
| 			goto success; | ||||
| 		} | ||||
| 	skip_to_next: | ||||
| 		dp = readdir(dir); | ||||
| 	} | ||||
| success: | ||||
| 	closedir(dir); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function finds the pathname to a block device with a given | ||||
|  * device number.  It returns a pointer to allocated memory to the | ||||
|  * pathname on success, and NULL on failure. | ||||
|  */ | ||||
| char *ext2fs_find_block_device(dev_t device) | ||||
| { | ||||
| 	struct dir_list *list = NULL, *new_list = NULL; | ||||
| 	struct dir_list *current; | ||||
| 	char	*ret_path = NULL; | ||||
|  | ||||
| 	/* | ||||
| 	 * Add the starting directories to search... | ||||
| 	 */ | ||||
| 	add_to_dirlist("/devices", &list); | ||||
| 	add_to_dirlist("/devfs", &list); | ||||
| 	add_to_dirlist("/dev", &list); | ||||
|  | ||||
| 	while (list) { | ||||
| 		current = list; | ||||
| 		list = list->next; | ||||
| #ifdef DEBUG | ||||
| 		printf("Scanning directory %s\n", current->name); | ||||
| #endif | ||||
| 		scan_dir(current->name, device, &new_list, &ret_path); | ||||
| 		free(current->name); | ||||
| 		free(current); | ||||
| 		if (ret_path) | ||||
| 			break; | ||||
| 		/* | ||||
| 		 * If we're done checking at this level, descend to | ||||
| 		 * the next level of subdirectories. (breadth-first) | ||||
| 		 */ | ||||
| 		if (list == 0) { | ||||
| 			list = new_list; | ||||
| 			new_list = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	free_dirlist(&list); | ||||
| 	free_dirlist(&new_list); | ||||
| 	return ret_path; | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifdef DEBUG | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	char	*devname, *tmp; | ||||
| 	int	major, minor; | ||||
| 	dev_t	device; | ||||
| 	const char *errmsg = "Cannot parse %s: %s\n"; | ||||
|  | ||||
| 	if ((argc != 2) && (argc != 3)) { | ||||
| 		fprintf(stderr, "Usage: %s device_number\n", argv[0]); | ||||
| 		fprintf(stderr, "\t: %s major minor\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if (argc == 2) { | ||||
| 		device = strtoul(argv[1], &tmp, 0); | ||||
| 		if (*tmp) { | ||||
| 			fprintf(stderr, errmsg, "device number", argv[1]); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 	} else { | ||||
| 		major = strtoul(argv[1], &tmp, 0); | ||||
| 		if (*tmp) { | ||||
| 			fprintf(stderr, errmsg, "major number", argv[1]); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		minor = strtoul(argv[2], &tmp, 0); | ||||
| 		if (*tmp) { | ||||
| 			fprintf(stderr, errmsg, "minor number", argv[2]); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		device = makedev(major, minor); | ||||
| 		printf("Looking for device 0x%04x (%d:%d)\n", device, | ||||
| 		       major, minor); | ||||
| 	} | ||||
| 	devname = ext2fs_find_block_device(device); | ||||
| 	if (devname) { | ||||
| 		printf("Found device!  %s\n", devname); | ||||
| 		free(devname); | ||||
| 	} else { | ||||
| 		printf("Cannot find device.\n"); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -1,83 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * flushb.c --- Hides system-dependent information for both syncing a | ||||
|  *	device to disk and to flush any buffers from disk cache. | ||||
|  * | ||||
|  * Copyright (C) 2000 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_SYS_IOCTL_H | ||||
| #include <sys/ioctl.h> | ||||
| #endif | ||||
| #if HAVE_SYS_MOUNT_H | ||||
| #include <sys/param.h> | ||||
| #include <sys/mount.h>  /* This may define BLKFLSBUF */ | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since | ||||
|  * not all portable header file does so for us.  This really should be | ||||
|  * fixed in the glibc header files.  (Recent glibcs appear to define | ||||
|  * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be | ||||
|  * defined anywhere portable.)  Until then.... | ||||
|  */ | ||||
| #ifdef __linux__ | ||||
| #ifndef BLKFLSBUF | ||||
| #define BLKFLSBUF  _IO(0x12,97)  /* flush buffer cache */ | ||||
| #endif | ||||
| #ifndef FDFLUSH | ||||
| #define FDFLUSH    _IO(2,0x4b)  /* flush floppy disk */ | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * This function will sync a device/file, and optionally attempt to | ||||
|  * flush the buffer cache.  The latter is basically only useful for | ||||
|  * system benchmarks and for torturing systems in burn-in tests.  :) | ||||
|  */ | ||||
| errcode_t ext2fs_sync_device(int fd, int flushb) | ||||
| { | ||||
| 	/* | ||||
| 	 * We always sync the device in case we're running on old | ||||
| 	 * kernels for which we can lose data if we don't.  (There | ||||
| 	 * still is a race condition for those kernels, but this | ||||
| 	 * reduces it greatly.) | ||||
| 	 */ | ||||
| 	if (fsync (fd) == -1) | ||||
| 		return errno; | ||||
|  | ||||
| 	if (flushb) { | ||||
|  | ||||
| #ifdef BLKFLSBUF | ||||
| 		if (ioctl (fd, BLKFLSBUF, 0) == 0) | ||||
| 			return 0; | ||||
| #else | ||||
| #ifdef __GNUC__ | ||||
| # warning BLKFLSBUF not defined | ||||
| #endif /* __GNUC__ */ | ||||
| #endif | ||||
| #ifdef FDFLUSH | ||||
| 		ioctl (fd, FDFLUSH, 0);   /* In case this is a floppy */ | ||||
| #else | ||||
| #ifdef __GNUC__ | ||||
| # warning FDFLUSH not defined | ||||
| #endif /* __GNUC__ */ | ||||
| #endif | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,127 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * freefs.c --- free an ext2 filesystem | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
|  | ||||
| static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache); | ||||
|  | ||||
| void ext2fs_free(ext2_filsys fs) | ||||
| { | ||||
| 	if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)) | ||||
| 		return; | ||||
| 	if (fs->image_io != fs->io) { | ||||
| 		if (fs->image_io) | ||||
| 			io_channel_close(fs->image_io); | ||||
| 	} | ||||
| 	if (fs->io) { | ||||
| 		io_channel_close(fs->io); | ||||
| 	} | ||||
| 	ext2fs_free_mem(&fs->device_name); | ||||
| 	ext2fs_free_mem(&fs->super); | ||||
| 	ext2fs_free_mem(&fs->orig_super); | ||||
| 	ext2fs_free_mem(&fs->group_desc); | ||||
| 	ext2fs_free_block_bitmap(fs->block_map); | ||||
| 	ext2fs_free_inode_bitmap(fs->inode_map); | ||||
|  | ||||
| 	ext2fs_badblocks_list_free(fs->badblocks); | ||||
| 	fs->badblocks = 0; | ||||
|  | ||||
| 	ext2fs_free_dblist(fs->dblist); | ||||
|  | ||||
| 	if (fs->icache) | ||||
| 		ext2fs_free_inode_cache(fs->icache); | ||||
|  | ||||
| 	fs->magic = 0; | ||||
|  | ||||
| 	ext2fs_free_mem(&fs); | ||||
| } | ||||
|  | ||||
| void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap) | ||||
| { | ||||
| 	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP)) | ||||
| 		return; | ||||
|  | ||||
| 	bitmap->magic = 0; | ||||
| 	ext2fs_free_mem(&bitmap->description); | ||||
| 	ext2fs_free_mem(&bitmap->bitmap); | ||||
| 	ext2fs_free_mem(&bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap) | ||||
| { | ||||
| 	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP)) | ||||
| 		return; | ||||
|  | ||||
| 	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP; | ||||
| 	ext2fs_free_generic_bitmap(bitmap); | ||||
| } | ||||
|  | ||||
| void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap) | ||||
| { | ||||
| 	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP)) | ||||
| 		return; | ||||
|  | ||||
| 	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP; | ||||
| 	ext2fs_free_generic_bitmap(bitmap); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Free the inode cache structure | ||||
|  */ | ||||
| static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache) | ||||
| { | ||||
| 	if (--icache->refcount) | ||||
| 		return; | ||||
| 	ext2fs_free_mem(&icache->buffer); | ||||
| 	ext2fs_free_mem(&icache->cache); | ||||
| 	icache->buffer_blk = 0; | ||||
| 	ext2fs_free_mem(&icache); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This procedure frees a badblocks list. | ||||
|  */ | ||||
| void ext2fs_u32_list_free(ext2_u32_list bb) | ||||
| { | ||||
| 	if (!bb || bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) | ||||
| 		return; | ||||
|  | ||||
| 	ext2fs_free_mem(&bb->list); | ||||
| 	ext2fs_free_mem(&bb); | ||||
| } | ||||
|  | ||||
| void ext2fs_badblocks_list_free(ext2_badblocks_list bb) | ||||
| { | ||||
| 	ext2fs_u32_list_free((ext2_u32_list) bb); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Free a directory block list | ||||
|  */ | ||||
| void ext2fs_free_dblist(ext2_dblist dblist) | ||||
| { | ||||
| 	if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST)) | ||||
| 		return; | ||||
|  | ||||
| 	ext2fs_free_mem(&dblist->list); | ||||
| 	if (dblist->fs && dblist->fs->dblist == dblist) | ||||
| 		dblist->fs->dblist = 0; | ||||
| 	dblist->magic = 0; | ||||
| 	ext2fs_free_mem(&dblist); | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * gen_bitmap.c --- Generic bitmap routines that used to be inlined. | ||||
|  * | ||||
|  * Copyright (C) 2001 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||||
| 					 __u32 bitno) | ||||
| { | ||||
| 	if ((bitno < bitmap->start) || (bitno > bitmap->end)) { | ||||
| 		ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
|  | ||||
| int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||||
| 					   blk_t bitno) | ||||
| { | ||||
| 	if ((bitno < bitmap->start) || (bitno > bitmap->end)) { | ||||
| 		ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap); | ||||
| } | ||||
| @@ -1,156 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * get_pathname.c --- do directry/inode -> name translation | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  * | ||||
|  *	ext2fs_get_pathname(fs, dir, ino, name) | ||||
|  * | ||||
|  *	This function translates takes two inode numbers into a | ||||
|  *	string, placing the result in <name>.  <dir> is the containing | ||||
|  *	directory inode, and <ino> is the inode number itself.  If | ||||
|  *	<ino> is zero, then ext2fs_get_pathname will return pathname | ||||
|  *	of the directory <dir>. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct get_pathname_struct { | ||||
| 	ext2_ino_t	search_ino; | ||||
| 	ext2_ino_t	parent; | ||||
| 	char		*name; | ||||
| 	errcode_t	errcode; | ||||
| }; | ||||
|  | ||||
| #ifdef __TURBOC__ | ||||
| # pragma argsused | ||||
| #endif | ||||
| static int get_pathname_proc(struct ext2_dir_entry *dirent, | ||||
| 			     int	offset EXT2FS_ATTR((unused)), | ||||
| 			     int	blocksize EXT2FS_ATTR((unused)), | ||||
| 			     char	*buf EXT2FS_ATTR((unused)), | ||||
| 			     void	*priv_data) | ||||
| { | ||||
| 	struct get_pathname_struct	*gp; | ||||
| 	errcode_t			retval; | ||||
|  | ||||
| 	gp = (struct get_pathname_struct *) priv_data; | ||||
|  | ||||
| 	if (((dirent->name_len & 0xFF) == 2) && | ||||
| 	    !strncmp(dirent->name, "..", 2)) | ||||
| 		gp->parent = dirent->inode; | ||||
| 	if (dirent->inode == gp->search_ino) { | ||||
| 		retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1, | ||||
| 					&gp->name); | ||||
| 		if (retval) { | ||||
| 			gp->errcode = retval; | ||||
| 			return DIRENT_ABORT; | ||||
| 		} | ||||
| 		strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF)); | ||||
| 		gp->name[dirent->name_len & 0xFF] = '\0'; | ||||
| 		return DIRENT_ABORT; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir, | ||||
| 					 ext2_ino_t ino, int maxdepth, | ||||
| 					 char *buf, char **name) | ||||
| { | ||||
| 	struct get_pathname_struct gp; | ||||
| 	char	*parent_name, *ret; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (dir == ino) { | ||||
| 		retval = ext2fs_get_mem(2, name); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : "."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!dir || (maxdepth < 0)) { | ||||
| 		retval = ext2fs_get_mem(4, name); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		strcpy(*name, "..."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	gp.search_ino = ino; | ||||
| 	gp.parent = 0; | ||||
| 	gp.name = 0; | ||||
| 	gp.errcode = 0; | ||||
|  | ||||
| 	retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	if (gp.errcode) { | ||||
| 		retval = gp.errcode; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1, | ||||
| 					 buf, &parent_name); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	if (!ino) { | ||||
| 		*name = parent_name; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (gp.name) | ||||
| 		retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2, | ||||
| 					&ret); | ||||
| 	else | ||||
| 		retval = ext2fs_get_mem(strlen(parent_name)+5, &ret); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	ret[0] = 0; | ||||
| 	if (parent_name[1]) | ||||
| 		strcat(ret, parent_name); | ||||
| 	strcat(ret, "/"); | ||||
| 	if (gp.name) | ||||
| 		strcat(ret, gp.name); | ||||
| 	else | ||||
| 		strcat(ret, "???"); | ||||
| 	*name = ret; | ||||
| 	ext2fs_free_mem(&parent_name); | ||||
| 	retval = 0; | ||||
|  | ||||
| cleanup: | ||||
| 	ext2fs_free_mem(&gp.name); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, | ||||
| 			      char **name) | ||||
| { | ||||
| 	char	*buf; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(fs->blocksize, &buf); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	if (dir == ino) | ||||
| 		ino = 0; | ||||
| 	retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name); | ||||
| 	ext2fs_free_mem(&buf); | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,58 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * getsectsize.c --- get the sector size of a device. | ||||
|  * | ||||
|  * Copyright (C) 1995, 1995 Theodore Ts'o. | ||||
|  * Copyright (C) 2003 VMware, Inc. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #ifdef HAVE_LINUX_FD_H | ||||
| #include <sys/ioctl.h> | ||||
| #include <linux/fd.h> | ||||
| #endif | ||||
|  | ||||
| #if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET) | ||||
| #define BLKSSZGET  _IO(0x12,104)/* get block device sector size */ | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * Returns the number of blocks in a partition | ||||
|  */ | ||||
| errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize) | ||||
| { | ||||
| 	int	fd; | ||||
|  | ||||
| #ifdef CONFIG_LFS | ||||
| 	fd = open64(file, O_RDONLY); | ||||
| #else | ||||
| 	fd = open(file, O_RDONLY); | ||||
| #endif | ||||
| 	if (fd < 0) | ||||
| 		return errno; | ||||
|  | ||||
| #ifdef BLKSSZGET | ||||
| 	if (ioctl(fd, BLKSSZGET, sectsize) >= 0) { | ||||
| 		close(fd); | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
| 	*sectsize = 0; | ||||
| 	close(fd); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,291 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * getsize.c --- get the size of a partition. | ||||
|  * | ||||
|  * Copyright (C) 1995, 1995 Theodore Ts'o. | ||||
|  * Copyright (C) 2003 VMware, Inc. | ||||
|  * | ||||
|  * Windows version of ext2fs_get_device_size by Chris Li, VMware. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #ifdef HAVE_SYS_IOCTL_H | ||||
| #include <sys/ioctl.h> | ||||
| #endif | ||||
| #ifdef HAVE_LINUX_FD_H | ||||
| #include <linux/fd.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISKLABEL_H | ||||
| #include <sys/disklabel.h> | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISK_H | ||||
| #ifdef HAVE_SYS_QUEUE_H | ||||
| #include <sys/queue.h> /* for LIST_HEAD */ | ||||
| #endif | ||||
| #include <sys/disk.h> | ||||
| #endif | ||||
| #ifdef __linux__ | ||||
| #include <sys/utsname.h> | ||||
| #endif | ||||
|  | ||||
| #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) | ||||
| #define BLKGETSIZE _IO(0x12,96)	/* return device size */ | ||||
| #endif | ||||
|  | ||||
| #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) | ||||
| #define BLKGETSIZE64 _IOR(0x12,114,size_t)	/* return device size in bytes (u64 *arg) */ | ||||
| #endif | ||||
|  | ||||
| #ifdef APPLE_DARWIN | ||||
| #define BLKGETSIZE DKIOCGETBLOCKCOUNT32 | ||||
| #endif /* APPLE_DARWIN */ | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| #if defined(__CYGWIN__) || defined(WIN32) | ||||
| #include <windows.h> | ||||
| #include <winioctl.h> | ||||
|  | ||||
| #if (_WIN32_WINNT >= 0x0500) | ||||
| #define HAVE_GET_FILE_SIZE_EX 1 | ||||
| #endif | ||||
|  | ||||
| errcode_t ext2fs_get_device_size(const char *file, int blocksize, | ||||
| 				 blk_t *retblocks) | ||||
| { | ||||
| 	HANDLE dev; | ||||
| 	PARTITION_INFORMATION pi; | ||||
| 	DISK_GEOMETRY gi; | ||||
| 	DWORD retbytes; | ||||
| #ifdef HAVE_GET_FILE_SIZE_EX | ||||
| 	LARGE_INTEGER filesize; | ||||
| #else | ||||
| 	DWORD filesize; | ||||
| #endif /* HAVE_GET_FILE_SIZE_EX */ | ||||
|  | ||||
| 	dev = CreateFile(file, GENERIC_READ, | ||||
| 			 FILE_SHARE_READ | FILE_SHARE_WRITE , | ||||
| 			 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||||
|  | ||||
| 	if (dev == INVALID_HANDLE_VALUE) | ||||
| 		return EBADF; | ||||
| 	if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, | ||||
| 			    &pi, sizeof(PARTITION_INFORMATION), | ||||
| 			    &pi, sizeof(PARTITION_INFORMATION), | ||||
| 			    &retbytes, NULL)) { | ||||
|  | ||||
| 		*retblocks = pi.PartitionLength.QuadPart / blocksize; | ||||
|  | ||||
| 	} else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, | ||||
| 				&gi, sizeof(DISK_GEOMETRY), | ||||
| 				&gi, sizeof(DISK_GEOMETRY), | ||||
| 				&retbytes, NULL)) { | ||||
|  | ||||
| 		*retblocks = gi.BytesPerSector * | ||||
| 			     gi.SectorsPerTrack * | ||||
| 			     gi.TracksPerCylinder * | ||||
| 			     gi.Cylinders.QuadPart / blocksize; | ||||
|  | ||||
| #ifdef HAVE_GET_FILE_SIZE_EX | ||||
| 	} else if (GetFileSizeEx(dev, &filesize)) { | ||||
| 		*retblocks = filesize.QuadPart / blocksize; | ||||
| 	} | ||||
| #else | ||||
| 	} else { | ||||
| 		filesize = GetFileSize(dev, NULL); | ||||
| 		if (INVALID_FILE_SIZE != filesize) { | ||||
| 			*retblocks = filesize / blocksize; | ||||
| 		} | ||||
| 	} | ||||
| #endif /* HAVE_GET_FILE_SIZE_EX */ | ||||
|  | ||||
| 	CloseHandle(dev); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| static int valid_offset (int fd, ext2_loff_t offset) | ||||
| { | ||||
| 	char ch; | ||||
|  | ||||
| 	if (ext2fs_llseek (fd, offset, 0) < 0) | ||||
| 		return 0; | ||||
| 	if (read (fd, &ch, 1) < 1) | ||||
| 		return 0; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the number of blocks in a partition | ||||
|  */ | ||||
| errcode_t ext2fs_get_device_size(const char *file, int blocksize, | ||||
| 				 blk_t *retblocks) | ||||
| { | ||||
| 	int	fd; | ||||
| 	int valid_blkgetsize64 = 1; | ||||
| #ifdef __linux__ | ||||
| 	struct		utsname ut; | ||||
| #endif | ||||
| 	unsigned long long size64; | ||||
| 	unsigned long	size; | ||||
| 	ext2_loff_t high, low; | ||||
| #ifdef FDGETPRM | ||||
| 	struct floppy_struct this_floppy; | ||||
| #endif | ||||
| #ifdef HAVE_SYS_DISKLABEL_H | ||||
| 	int part; | ||||
| 	struct disklabel lab; | ||||
| 	struct partition *pp; | ||||
| 	char ch; | ||||
| #endif /* HAVE_SYS_DISKLABEL_H */ | ||||
|  | ||||
| #ifdef CONFIG_LFS | ||||
| 	fd = open64(file, O_RDONLY); | ||||
| #else | ||||
| 	fd = open(file, O_RDONLY); | ||||
| #endif | ||||
| 	if (fd < 0) | ||||
| 		return errno; | ||||
|  | ||||
| #ifdef DKIOCGETBLOCKCOUNT	/* For Apple Darwin */ | ||||
| 	if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) { | ||||
| 		if ((sizeof(*retblocks) < sizeof(unsigned long long)) | ||||
| 		    && ((size64 / (blocksize / 512)) > 0xFFFFFFFF)) | ||||
| 			return EFBIG; | ||||
| 		close(fd); | ||||
| 		*retblocks = size64 / (blocksize / 512); | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef BLKGETSIZE64 | ||||
| #ifdef __linux__ | ||||
| 	uname(&ut); | ||||
| 	if ((ut.release[0] == '2') && (ut.release[1] == '.') && | ||||
| 	     (ut.release[2] < '6') && (ut.release[3] == '.')) | ||||
| 		valid_blkgetsize64 = 0; | ||||
| #endif | ||||
| 	if (valid_blkgetsize64 && | ||||
| 	    ioctl(fd, BLKGETSIZE64, &size64) >= 0) { | ||||
| 		if ((sizeof(*retblocks) < sizeof(unsigned long long)) | ||||
| 		    && ((size64 / blocksize) > 0xFFFFFFFF)) | ||||
| 			return EFBIG; | ||||
| 		close(fd); | ||||
| 		*retblocks = size64 / blocksize; | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef BLKGETSIZE | ||||
| 	if (ioctl(fd, BLKGETSIZE, &size) >= 0) { | ||||
| 		close(fd); | ||||
| 		*retblocks = size / (blocksize / 512); | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef FDGETPRM | ||||
| 	if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { | ||||
| 		close(fd); | ||||
| 		*retblocks = this_floppy.size / (blocksize / 512); | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef HAVE_SYS_DISKLABEL_H | ||||
| #if defined(DIOCGMEDIASIZE) | ||||
| 	{ | ||||
| 	    off_t ms; | ||||
| 	    u_int bs; | ||||
| 	    if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) { | ||||
| 		*retblocks = ms / blocksize; | ||||
| 		return 0; | ||||
| 	    } | ||||
| 	} | ||||
| #elif defined(DIOCGDINFO) | ||||
| 	/* old disklabel interface */ | ||||
| 	part = strlen(file) - 1; | ||||
| 	if (part >= 0) { | ||||
| 		ch = file[part]; | ||||
| 		if (isdigit(ch)) | ||||
| 			part = 0; | ||||
| 		else if (ch >= 'a' && ch <= 'h') | ||||
| 			part = ch - 'a'; | ||||
| 		else | ||||
| 			part = -1; | ||||
| 	} | ||||
| 	if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { | ||||
| 		pp = &lab.d_partitions[part]; | ||||
| 		if (pp->p_size) { | ||||
| 			close(fd); | ||||
| 			*retblocks = pp->p_size / (blocksize / 512); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| #endif /* defined(DIOCG*) */ | ||||
| #endif /* HAVE_SYS_DISKLABEL_H */ | ||||
|  | ||||
| 	/* | ||||
| 	 * OK, we couldn't figure it out by using a specialized ioctl, | ||||
| 	 * which is generally the best way.  So do binary search to | ||||
| 	 * find the size of the partition. | ||||
| 	 */ | ||||
| 	low = 0; | ||||
| 	for (high = 1024; valid_offset (fd, high); high *= 2) | ||||
| 		low = high; | ||||
| 	while (low < high - 1) | ||||
| 	{ | ||||
| 		const ext2_loff_t mid = (low + high) / 2; | ||||
|  | ||||
| 		if (valid_offset (fd, mid)) | ||||
| 			low = mid; | ||||
| 		else | ||||
| 			high = mid; | ||||
| 	} | ||||
| 	valid_offset (fd, 0); | ||||
| 	close(fd); | ||||
| 	size64 = low + 1; | ||||
| 	if ((sizeof(*retblocks) < sizeof(unsigned long long)) | ||||
| 	    && ((size64 / blocksize) > 0xFFFFFFFF)) | ||||
| 		return EFBIG; | ||||
| 	*retblocks = size64 / blocksize; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif /* WIN32 */ | ||||
|  | ||||
| #ifdef DEBUG | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	blk_t	blocks; | ||||
| 	int	retval; | ||||
|  | ||||
| 	if (argc < 2) { | ||||
| 		fprintf(stderr, "Usage: %s device\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_device_size(argv[1], 1024, &blocks); | ||||
| 	if (retval) { | ||||
| 		com_err(argv[0], retval, | ||||
| 			"while calling ext2fs_get_device_size"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	printf("Device %s has %d 1k blocks.\n", argv[1], blocks); | ||||
| 	exit(0); | ||||
| } | ||||
| #endif | ||||
| @@ -1,467 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * icount.c --- an efficient inode count abstraction | ||||
|  * | ||||
|  * Copyright (C) 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * The data storage strategy used by icount relies on the observation | ||||
|  * that most inode counts are either zero (for non-allocated inodes), | ||||
|  * one (for most files), and only a few that are two or more | ||||
|  * (directories and files that are linked to more than one directory). | ||||
|  * | ||||
|  * Also, e2fsck tends to load the icount data sequentially. | ||||
|  * | ||||
|  * So, we use an inode bitmap to indicate which inodes have a count of | ||||
|  * one, and then use a sorted list to store the counts for inodes | ||||
|  * which are greater than one. | ||||
|  * | ||||
|  * We also use an optional bitmap to indicate which inodes are already | ||||
|  * in the sorted list, to speed up the use of this abstraction by | ||||
|  * e2fsck's pass 2.  Pass 2 increments inode counts as it finds them, | ||||
|  * so this extra bitmap avoids searching the sorted list to see if a | ||||
|  * particular inode is on the sorted list already. | ||||
|  */ | ||||
|  | ||||
| struct ext2_icount_el { | ||||
| 	ext2_ino_t	ino; | ||||
| 	__u16	count; | ||||
| }; | ||||
|  | ||||
| struct ext2_icount { | ||||
| 	errcode_t		magic; | ||||
| 	ext2fs_inode_bitmap	single; | ||||
| 	ext2fs_inode_bitmap	multiple; | ||||
| 	ext2_ino_t		count; | ||||
| 	ext2_ino_t		size; | ||||
| 	ext2_ino_t		num_inodes; | ||||
| 	ext2_ino_t		cursor; | ||||
| 	struct ext2_icount_el	*list; | ||||
| }; | ||||
|  | ||||
| void ext2fs_free_icount(ext2_icount_t icount) | ||||
| { | ||||
| 	if (!icount) | ||||
| 		return; | ||||
|  | ||||
| 	icount->magic = 0; | ||||
| 	ext2fs_free_mem(&icount->list); | ||||
| 	ext2fs_free_inode_bitmap(icount->single); | ||||
| 	ext2fs_free_inode_bitmap(icount->multiple); | ||||
| 	ext2fs_free_mem(&icount); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size, | ||||
| 				ext2_icount_t hint, ext2_icount_t *ret) | ||||
| { | ||||
| 	ext2_icount_t	icount; | ||||
| 	errcode_t	retval; | ||||
| 	size_t		bytes; | ||||
| 	ext2_ino_t	i; | ||||
|  | ||||
| 	if (hint) { | ||||
| 		EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT); | ||||
| 		if (hint->size > size) | ||||
| 			size = (size_t) hint->size; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	memset(icount, 0, sizeof(struct ext2_icount)); | ||||
|  | ||||
| 	retval = ext2fs_allocate_inode_bitmap(fs, 0, | ||||
| 					      &icount->single); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
|  | ||||
| 	if (flags & EXT2_ICOUNT_OPT_INCREMENT) { | ||||
| 		retval = ext2fs_allocate_inode_bitmap(fs, 0, | ||||
| 						      &icount->multiple); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 	} else | ||||
| 		icount->multiple = 0; | ||||
|  | ||||
| 	if (size) { | ||||
| 		icount->size = size; | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * Figure out how many special case inode counts we will | ||||
| 		 * have.  We know we will need one for each directory; | ||||
| 		 * we also need to reserve some extra room for file links | ||||
| 		 */ | ||||
| 		retval = ext2fs_get_num_dirs(fs, &icount->size); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
| 		icount->size += fs->super->s_inodes_count / 50; | ||||
| 	} | ||||
|  | ||||
| 	bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el)); | ||||
| 	retval = ext2fs_get_mem(bytes, &icount->list); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(icount->list, 0, bytes); | ||||
|  | ||||
| 	icount->magic = EXT2_ET_MAGIC_ICOUNT; | ||||
| 	icount->count = 0; | ||||
| 	icount->cursor = 0; | ||||
| 	icount->num_inodes = fs->super->s_inodes_count; | ||||
|  | ||||
| 	/* | ||||
| 	 * Populate the sorted list with those entries which were | ||||
| 	 * found in the hint icount (since those are ones which will | ||||
| 	 * likely need to be in the sorted list this time around). | ||||
| 	 */ | ||||
| 	if (hint) { | ||||
| 		for (i=0; i < hint->count; i++) | ||||
| 			icount->list[i].ino = hint->list[i].ino; | ||||
| 		icount->count = hint->count; | ||||
| 	} | ||||
|  | ||||
| 	*ret = icount; | ||||
| 	return 0; | ||||
|  | ||||
| errout: | ||||
| 	ext2fs_free_icount(icount); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, | ||||
| 			       unsigned int size, | ||||
| 			       ext2_icount_t *ret) | ||||
| { | ||||
| 	return ext2fs_create_icount2(fs, flags, size, 0, ret); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * insert_icount_el() --- Insert a new entry into the sorted list at a | ||||
|  *	specified position. | ||||
|  */ | ||||
| static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount, | ||||
| 					    ext2_ino_t ino, int pos) | ||||
| { | ||||
| 	struct ext2_icount_el	*el; | ||||
| 	errcode_t		retval; | ||||
| 	ext2_ino_t			new_size = 0; | ||||
| 	int			num; | ||||
|  | ||||
| 	if (icount->count >= icount->size) { | ||||
| 		if (icount->count) { | ||||
| 			new_size = icount->list[(unsigned)icount->count-1].ino; | ||||
| 			new_size = (ext2_ino_t) (icount->count * | ||||
| 				((float) icount->num_inodes / new_size)); | ||||
| 		} | ||||
| 		if (new_size < (icount->size + 100)) | ||||
| 			new_size = icount->size + 100; | ||||
| 		retval = ext2fs_resize_mem((size_t) icount->size * | ||||
| 					   sizeof(struct ext2_icount_el), | ||||
| 					   (size_t) new_size * | ||||
| 					   sizeof(struct ext2_icount_el), | ||||
| 					   &icount->list); | ||||
| 		if (retval) | ||||
| 			return 0; | ||||
| 		icount->size = new_size; | ||||
| 	} | ||||
| 	num = (int) icount->count - pos; | ||||
| 	if (num < 0) | ||||
| 		return 0;	/* should never happen */ | ||||
| 	if (num) { | ||||
| 		memmove(&icount->list[pos+1], &icount->list[pos], | ||||
| 			sizeof(struct ext2_icount_el) * num); | ||||
| 	} | ||||
| 	icount->count++; | ||||
| 	el = &icount->list[pos]; | ||||
| 	el->count = 0; | ||||
| 	el->ino = ino; | ||||
| 	return el; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * get_icount_el() --- given an inode number, try to find icount | ||||
|  *	information in the sorted list.  If the create flag is set, | ||||
|  *	and we can't find an entry, create one in the sorted list. | ||||
|  */ | ||||
| static struct ext2_icount_el *get_icount_el(ext2_icount_t icount, | ||||
| 					    ext2_ino_t ino, int create) | ||||
| { | ||||
| 	float	range; | ||||
| 	int	low, high, mid; | ||||
| 	ext2_ino_t	lowval, highval; | ||||
|  | ||||
| 	if (!icount || !icount->list) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (create && ((icount->count == 0) || | ||||
| 		       (ino > icount->list[(unsigned)icount->count-1].ino))) { | ||||
| 		return insert_icount_el(icount, ino, (unsigned) icount->count); | ||||
| 	} | ||||
| 	if (icount->count == 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (icount->cursor >= icount->count) | ||||
| 		icount->cursor = 0; | ||||
| 	if (ino == icount->list[icount->cursor].ino) | ||||
| 		return &icount->list[icount->cursor++]; | ||||
| 	low = 0; | ||||
| 	high = (int) icount->count-1; | ||||
| 	while (low <= high) { | ||||
| 		if (low == high) | ||||
| 			mid = low; | ||||
| 		else { | ||||
| 			/* Interpolate for efficiency */ | ||||
| 			lowval = icount->list[low].ino; | ||||
| 			highval = icount->list[high].ino; | ||||
|  | ||||
| 			if (ino < lowval) | ||||
| 				range = 0; | ||||
| 			else if (ino > highval) | ||||
| 				range = 1; | ||||
| 			else | ||||
| 				range = ((float) (ino - lowval)) / | ||||
| 					(highval - lowval); | ||||
| 			mid = low + ((int) (range * (high-low))); | ||||
| 		} | ||||
| 		if (ino == icount->list[mid].ino) { | ||||
| 			icount->cursor = mid+1; | ||||
| 			return &icount->list[mid]; | ||||
| 		} | ||||
| 		if (ino < icount->list[mid].ino) | ||||
| 			high = mid-1; | ||||
| 		else | ||||
| 			low = mid+1; | ||||
| 	} | ||||
| 	/* | ||||
| 	 * If we need to create a new entry, it should be right at | ||||
| 	 * low (where high will be left at low-1). | ||||
| 	 */ | ||||
| 	if (create) | ||||
| 		return insert_icount_el(icount, ino, low); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out) | ||||
| { | ||||
| 	errcode_t	ret = 0; | ||||
| 	unsigned int	i; | ||||
| 	const char *bad = "bad icount"; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); | ||||
|  | ||||
| 	if (icount->count > icount->size) { | ||||
| 		fprintf(out, "%s: count > size\n", bad); | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	} | ||||
| 	for (i=1; i < icount->count; i++) { | ||||
| 		if (icount->list[i-1].ino >= icount->list[i].ino) { | ||||
| 			fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n", | ||||
| 				bad, i-1, icount->list[i-1].ino, | ||||
| 				i, icount->list[i].ino); | ||||
| 			ret = EXT2_ET_INVALID_ARGUMENT; | ||||
| 		} | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) | ||||
| { | ||||
| 	struct ext2_icount_el	*el; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); | ||||
|  | ||||
| 	if (!ino || (ino > icount->num_inodes)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	if (ext2fs_test_inode_bitmap(icount->single, ino)) { | ||||
| 		*ret = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (icount->multiple && | ||||
| 	    !ext2fs_test_inode_bitmap(icount->multiple, ino)) { | ||||
| 		*ret = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	el = get_icount_el(icount, ino, 0); | ||||
| 	if (!el) { | ||||
| 		*ret = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*ret = el->count; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 				  __u16 *ret) | ||||
| { | ||||
| 	struct ext2_icount_el	*el; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); | ||||
|  | ||||
| 	if (!ino || (ino > icount->num_inodes)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	if (ext2fs_test_inode_bitmap(icount->single, ino)) { | ||||
| 		/* | ||||
| 		 * If the existing count is 1, then we know there is | ||||
| 		 * no entry in the list. | ||||
| 		 */ | ||||
| 		el = get_icount_el(icount, ino, 1); | ||||
| 		if (!el) | ||||
| 			return EXT2_ET_NO_MEMORY; | ||||
| 		ext2fs_unmark_inode_bitmap(icount->single, ino); | ||||
| 		el->count = 2; | ||||
| 	} else if (icount->multiple) { | ||||
| 		/* | ||||
| 		 * The count is either zero or greater than 1; if the | ||||
| 		 * inode is set in icount->multiple, then there should | ||||
| 		 * be an entry in the list, so find it using | ||||
| 		 * get_icount_el(). | ||||
| 		 */ | ||||
| 		if (ext2fs_test_inode_bitmap(icount->multiple, ino)) { | ||||
| 			el = get_icount_el(icount, ino, 1); | ||||
| 			if (!el) | ||||
| 				return EXT2_ET_NO_MEMORY; | ||||
| 			el->count++; | ||||
| 		} else { | ||||
| 			/* | ||||
| 			 * The count was zero; mark the single bitmap | ||||
| 			 * and return. | ||||
| 			 */ | ||||
| 		zero_count: | ||||
| 			ext2fs_mark_inode_bitmap(icount->single, ino); | ||||
| 			if (ret) | ||||
| 				*ret = 1; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * The count is either zero or greater than 1; try to | ||||
| 		 * find an entry in the list to determine which. | ||||
| 		 */ | ||||
| 		el = get_icount_el(icount, ino, 0); | ||||
| 		if (!el) { | ||||
| 			/* No entry means the count was zero */ | ||||
| 			goto zero_count; | ||||
| 		} | ||||
| 		el = get_icount_el(icount, ino, 1); | ||||
| 		if (!el) | ||||
| 			return EXT2_ET_NO_MEMORY; | ||||
| 		el->count++; | ||||
| 	} | ||||
| 	if (icount->multiple) | ||||
| 		ext2fs_mark_inode_bitmap(icount->multiple, ino); | ||||
| 	if (ret) | ||||
| 		*ret = el->count; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 				  __u16 *ret) | ||||
| { | ||||
| 	struct ext2_icount_el	*el; | ||||
|  | ||||
| 	if (!ino || (ino > icount->num_inodes)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); | ||||
|  | ||||
| 	if (ext2fs_test_inode_bitmap(icount->single, ino)) { | ||||
| 		ext2fs_unmark_inode_bitmap(icount->single, ino); | ||||
| 		if (icount->multiple) | ||||
| 			ext2fs_unmark_inode_bitmap(icount->multiple, ino); | ||||
| 		else { | ||||
| 			el = get_icount_el(icount, ino, 0); | ||||
| 			if (el) | ||||
| 				el->count = 0; | ||||
| 		} | ||||
| 		if (ret) | ||||
| 			*ret = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (icount->multiple && | ||||
| 	    !ext2fs_test_inode_bitmap(icount->multiple, ino)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	el = get_icount_el(icount, ino, 0); | ||||
| 	if (!el || el->count == 0) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	el->count--; | ||||
| 	if (el->count == 1) | ||||
| 		ext2fs_mark_inode_bitmap(icount->single, ino); | ||||
| 	if ((el->count == 0) && icount->multiple) | ||||
| 		ext2fs_unmark_inode_bitmap(icount->multiple, ino); | ||||
|  | ||||
| 	if (ret) | ||||
| 		*ret = el->count; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, | ||||
| 			      __u16 count) | ||||
| { | ||||
| 	struct ext2_icount_el	*el; | ||||
|  | ||||
| 	if (!ino || (ino > icount->num_inodes)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); | ||||
|  | ||||
| 	if (count == 1) { | ||||
| 		ext2fs_mark_inode_bitmap(icount->single, ino); | ||||
| 		if (icount->multiple) | ||||
| 			ext2fs_unmark_inode_bitmap(icount->multiple, ino); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (count == 0) { | ||||
| 		ext2fs_unmark_inode_bitmap(icount->single, ino); | ||||
| 		if (icount->multiple) { | ||||
| 			/* | ||||
| 			 * If the icount->multiple bitmap is enabled, | ||||
| 			 * we can just clear both bitmaps and we're done | ||||
| 			 */ | ||||
| 			ext2fs_unmark_inode_bitmap(icount->multiple, ino); | ||||
| 		} else { | ||||
| 			el = get_icount_el(icount, ino, 0); | ||||
| 			if (el) | ||||
| 				el->count = 0; | ||||
| 		} | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Get the icount element | ||||
| 	 */ | ||||
| 	el = get_icount_el(icount, ino, 1); | ||||
| 	if (!el) | ||||
| 		return EXT2_ET_NO_MEMORY; | ||||
| 	el->count = count; | ||||
| 	ext2fs_unmark_inode_bitmap(icount->single, ino); | ||||
| 	if (icount->multiple) | ||||
| 		ext2fs_mark_inode_bitmap(icount->multiple, ino); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount) | ||||
| { | ||||
| 	if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT) | ||||
| 		return 0; | ||||
|  | ||||
| 	return icount->size; | ||||
| } | ||||
| @@ -1,377 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * image.c --- writes out the critical parts of the filesystem as a | ||||
|  *	flat file. | ||||
|  * | ||||
|  * Copyright (C) 2000 Theodore Ts'o. | ||||
|  * | ||||
|  * Note: this uses the POSIX IO interfaces, unlike most of the other | ||||
|  * functions in this library.  So sue me. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| #ifndef HAVE_TYPE_SSIZE_T | ||||
| typedef int ssize_t; | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * This function returns 1 if the specified block is all zeros | ||||
|  */ | ||||
| static int check_zero_block(char *buf, int blocksize) | ||||
| { | ||||
| 	char	*cp = buf; | ||||
| 	int	left = blocksize; | ||||
|  | ||||
| 	while (left > 0) { | ||||
| 		if (*cp++) | ||||
| 			return 0; | ||||
| 		left--; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write the inode table out as a single block. | ||||
|  */ | ||||
| #define BUF_BLOCKS	32 | ||||
|  | ||||
| errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags) | ||||
| { | ||||
| 	unsigned int	group, left, c, d; | ||||
| 	char		*buf, *cp; | ||||
| 	blk_t		blk; | ||||
| 	ssize_t		actual; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	buf = xmalloc(fs->blocksize * BUF_BLOCKS); | ||||
|  | ||||
| 	for (group = 0; group < fs->group_desc_count; group++) { | ||||
| 		blk = fs->group_desc[(unsigned)group].bg_inode_table; | ||||
| 		if (!blk) | ||||
| 			return EXT2_ET_MISSING_INODE_TABLE; | ||||
| 		left = fs->inode_blocks_per_group; | ||||
| 		while (left) { | ||||
| 			c = BUF_BLOCKS; | ||||
| 			if (c > left) | ||||
| 				c = left; | ||||
| 			retval = io_channel_read_blk(fs->io, blk, c, buf); | ||||
| 			if (retval) | ||||
| 				goto errout; | ||||
| 			cp = buf; | ||||
| 			while (c) { | ||||
| 				if (!(flags & IMAGER_FLAG_SPARSEWRITE)) { | ||||
| 					d = c; | ||||
| 					goto skip_sparse; | ||||
| 				} | ||||
| 				/* Skip zero blocks */ | ||||
| 				if (check_zero_block(cp, fs->blocksize)) { | ||||
| 					c--; | ||||
| 					blk++; | ||||
| 					left--; | ||||
| 					cp += fs->blocksize; | ||||
| 					lseek(fd, fs->blocksize, SEEK_CUR); | ||||
| 					continue; | ||||
| 				} | ||||
| 				/* Find non-zero blocks */ | ||||
| 				for (d=1; d < c; d++) { | ||||
| 					if (check_zero_block(cp + d*fs->blocksize, fs->blocksize)) | ||||
| 						break; | ||||
| 				} | ||||
| 			skip_sparse: | ||||
| 				actual = write(fd, cp, fs->blocksize * d); | ||||
| 				if (actual == -1) { | ||||
| 					retval = errno; | ||||
| 					goto errout; | ||||
| 				} | ||||
| 				if (actual != (ssize_t) (fs->blocksize * d)) { | ||||
| 					retval = EXT2_ET_SHORT_WRITE; | ||||
| 					goto errout; | ||||
| 				} | ||||
| 				blk += d; | ||||
| 				left -= d; | ||||
| 				cp += fs->blocksize * d; | ||||
| 				c -= d; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	retval = 0; | ||||
|  | ||||
| errout: | ||||
| 	free(buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Read in the inode table and stuff it into place | ||||
|  */ | ||||
| errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, | ||||
| 				  int flags EXT2FS_ATTR((unused))) | ||||
| { | ||||
| 	unsigned int	group, c, left; | ||||
| 	char		*buf; | ||||
| 	blk_t		blk; | ||||
| 	ssize_t		actual; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	buf = xmalloc(fs->blocksize * BUF_BLOCKS); | ||||
|  | ||||
| 	for (group = 0; group < fs->group_desc_count; group++) { | ||||
| 		blk = fs->group_desc[(unsigned)group].bg_inode_table; | ||||
| 		if (!blk) { | ||||
| 			retval = EXT2_ET_MISSING_INODE_TABLE; | ||||
| 			goto errout; | ||||
| 		} | ||||
| 		left = fs->inode_blocks_per_group; | ||||
| 		while (left) { | ||||
| 			c = BUF_BLOCKS; | ||||
| 			if (c > left) | ||||
| 				c = left; | ||||
| 			actual = read(fd, buf, fs->blocksize * c); | ||||
| 			if (actual == -1) { | ||||
| 				retval = errno; | ||||
| 				goto errout; | ||||
| 			} | ||||
| 			if (actual != (ssize_t) (fs->blocksize * c)) { | ||||
| 				retval = EXT2_ET_SHORT_READ; | ||||
| 				goto errout; | ||||
| 			} | ||||
| 			retval = io_channel_write_blk(fs->io, blk, c, buf); | ||||
| 			if (retval) | ||||
| 				goto errout; | ||||
|  | ||||
| 			blk += c; | ||||
| 			left -= c; | ||||
| 		} | ||||
| 	} | ||||
| 	retval = ext2fs_flush_icache(fs); | ||||
|  | ||||
| errout: | ||||
| 	free(buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write out superblock and group descriptors | ||||
|  */ | ||||
| errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, | ||||
| 				   int flags EXT2FS_ATTR((unused))) | ||||
| { | ||||
| 	char		*buf, *cp; | ||||
| 	ssize_t		actual; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	buf = xmalloc(fs->blocksize); | ||||
|  | ||||
| 	/* | ||||
| 	 * Write out the superblock | ||||
| 	 */ | ||||
| 	memset(buf, 0, fs->blocksize); | ||||
| 	memcpy(buf, fs->super, SUPERBLOCK_SIZE); | ||||
| 	actual = write(fd, buf, fs->blocksize); | ||||
| 	if (actual == -1) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (actual != (ssize_t) fs->blocksize) { | ||||
| 		retval = EXT2_ET_SHORT_WRITE; | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Now write out the block group descriptors | ||||
| 	 */ | ||||
| 	cp = (char *) fs->group_desc; | ||||
| 	actual = write(fd, cp, fs->blocksize * fs->desc_blocks); | ||||
| 	if (actual == -1) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) { | ||||
| 		retval = EXT2_ET_SHORT_WRITE; | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	retval = 0; | ||||
|  | ||||
| errout: | ||||
| 	free(buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Read the superblock and group descriptors and overwrite them. | ||||
|  */ | ||||
| errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, | ||||
| 				  int flags EXT2FS_ATTR((unused))) | ||||
| { | ||||
| 	char		*buf; | ||||
| 	ssize_t		actual, size; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	size = fs->blocksize * (fs->group_desc_count + 1); | ||||
| 	buf = xmalloc(size); | ||||
|  | ||||
| 	/* | ||||
| 	 * Read it all in. | ||||
| 	 */ | ||||
| 	actual = read(fd, buf, size); | ||||
| 	if (actual == -1) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (actual != size) { | ||||
| 		retval = EXT2_ET_SHORT_READ; | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Now copy in the superblock and group descriptors | ||||
| 	 */ | ||||
| 	memcpy(fs->super, buf, SUPERBLOCK_SIZE); | ||||
|  | ||||
| 	memcpy(fs->group_desc, buf + fs->blocksize, | ||||
| 	       fs->blocksize * fs->group_desc_count); | ||||
|  | ||||
| 	retval = 0; | ||||
|  | ||||
| errout: | ||||
| 	free(buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write the block/inode bitmaps. | ||||
|  */ | ||||
| errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) | ||||
| { | ||||
| 	char		*ptr; | ||||
| 	int		c, size; | ||||
| 	char		zero_buf[1024]; | ||||
| 	ssize_t		actual; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (flags & IMAGER_FLAG_INODEMAP) { | ||||
| 		if (!fs->inode_map) { | ||||
| 			retval = ext2fs_read_inode_bitmap(fs); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		ptr = fs->inode_map->bitmap; | ||||
| 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8); | ||||
| 	} else { | ||||
| 		if (!fs->block_map) { | ||||
| 			retval = ext2fs_read_block_bitmap(fs); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		ptr = fs->block_map->bitmap; | ||||
| 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; | ||||
| 	} | ||||
| 	size = size * fs->group_desc_count; | ||||
|  | ||||
| 	actual = write(fd, ptr, size); | ||||
| 	if (actual == -1) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (actual != size) { | ||||
| 		retval = EXT2_ET_SHORT_WRITE; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	size = size % fs->blocksize; | ||||
| 	memset(zero_buf, 0, sizeof(zero_buf)); | ||||
| 	if (size) { | ||||
| 		size = fs->blocksize - size; | ||||
| 		while (size) { | ||||
| 			c = size; | ||||
| 			if (c > (int) sizeof(zero_buf)) | ||||
| 				c = sizeof(zero_buf); | ||||
| 			actual = write(fd, zero_buf, c); | ||||
| 			if (actual == -1) { | ||||
| 				retval = errno; | ||||
| 				goto errout; | ||||
| 			} | ||||
| 			if (actual != c) { | ||||
| 				retval = EXT2_ET_SHORT_WRITE; | ||||
| 				goto errout; | ||||
| 			} | ||||
| 			size -= c; | ||||
| 		} | ||||
| 	} | ||||
| 	retval = 0; | ||||
| errout: | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Read the block/inode bitmaps. | ||||
|  */ | ||||
| errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) | ||||
| { | ||||
| 	char		*ptr, *buf = NULL; | ||||
| 	int		size; | ||||
| 	ssize_t		actual; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (flags & IMAGER_FLAG_INODEMAP) { | ||||
| 		if (!fs->inode_map) { | ||||
| 			retval = ext2fs_read_inode_bitmap(fs); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		ptr = fs->inode_map->bitmap; | ||||
| 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8); | ||||
| 	} else { | ||||
| 		if (!fs->block_map) { | ||||
| 			retval = ext2fs_read_block_bitmap(fs); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		ptr = fs->block_map->bitmap; | ||||
| 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; | ||||
| 	} | ||||
| 	size = size * fs->group_desc_count; | ||||
|  | ||||
| 	buf = xmalloc(size); | ||||
|  | ||||
| 	actual = read(fd, buf, size); | ||||
| 	if (actual == -1) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (actual != size) { | ||||
| 		retval = EXT2_ET_SHORT_WRITE; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	memcpy(ptr, buf, size); | ||||
|  | ||||
| 	retval = 0; | ||||
| errout: | ||||
| 	free(buf); | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ind_block.c --- indirect block I/O routines | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, | ||||
|  *	2001, 2002, 2003, 2004, 2005 by  Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| #if BB_BIG_ENDIAN | ||||
| 	blk_t		*block_nr; | ||||
| 	int		i; | ||||
| 	int		limit = fs->blocksize >> 2; | ||||
| #endif | ||||
|  | ||||
| 	if ((fs->flags & EXT2_FLAG_IMAGE_FILE) && | ||||
| 	    (fs->io != fs->image_io)) | ||||
| 		memset(buf, 0, fs->blocksize); | ||||
| 	else { | ||||
| 		retval = io_channel_read_blk(fs->io, blk, 1, buf); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) { | ||||
| 		block_nr = (blk_t *) buf; | ||||
| 		for (i = 0; i < limit; i++, block_nr++) | ||||
| 			*block_nr = ext2fs_swab32(*block_nr); | ||||
| 	} | ||||
| #endif | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf) | ||||
| { | ||||
| #if BB_BIG_ENDIAN | ||||
| 	blk_t		*block_nr; | ||||
| 	int		i; | ||||
| 	int		limit = fs->blocksize >> 2; | ||||
| #endif | ||||
|  | ||||
| 	if (fs->flags & EXT2_FLAG_IMAGE_FILE) | ||||
| 		return 0; | ||||
|  | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) { | ||||
| 		block_nr = (blk_t *) buf; | ||||
| 		for (i = 0; i < limit; i++, block_nr++) | ||||
| 			*block_nr = ext2fs_swab32(*block_nr); | ||||
| 	} | ||||
| #endif | ||||
| 	return io_channel_write_blk(fs->io, blk, 1, buf); | ||||
| } | ||||
| @@ -1,388 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * initialize.c --- initialize a filesystem handle given superblock | ||||
|  *	parameters.  Used by mke2fs when initializing a filesystem. | ||||
|  * | ||||
|  * Copyright (C) 1994, 1995, 1996 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| #if defined(__linux__)    &&	defined(EXT2_OS_LINUX) | ||||
| #define CREATOR_OS EXT2_OS_LINUX | ||||
| #else | ||||
| #if defined(__GNU__)     &&	defined(EXT2_OS_HURD) | ||||
| #define CREATOR_OS EXT2_OS_HURD | ||||
| #else | ||||
| #if defined(__FreeBSD__) &&	defined(EXT2_OS_FREEBSD) | ||||
| #define CREATOR_OS EXT2_OS_FREEBSD | ||||
| #else | ||||
| #if defined(LITES)	   &&	defined(EXT2_OS_LITES) | ||||
| #define CREATOR_OS EXT2_OS_LITES | ||||
| #else | ||||
| #define CREATOR_OS EXT2_OS_LINUX /* by default */ | ||||
| #endif /* defined(LITES) && defined(EXT2_OS_LITES) */ | ||||
| #endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */ | ||||
| #endif /* defined(__GNU__)     && defined(EXT2_OS_HURD) */ | ||||
| #endif /* defined(__linux__)   && defined(EXT2_OS_LINUX) */ | ||||
|  | ||||
| /* | ||||
|  * Note we override the kernel include file's idea of what the default | ||||
|  * check interval (never) should be.  It's a good idea to check at | ||||
|  * least *occasionally*, specially since servers will never rarely get | ||||
|  * to reboot, since Linux is so robust these days.  :-) | ||||
|  * | ||||
|  * 180 days (six months) seems like a good value. | ||||
|  */ | ||||
| #ifdef EXT2_DFL_CHECKINTERVAL | ||||
| #undef EXT2_DFL_CHECKINTERVAL | ||||
| #endif | ||||
| #define EXT2_DFL_CHECKINTERVAL (86400L * 180L) | ||||
|  | ||||
| /* | ||||
|  * Calculate the number of GDT blocks to reserve for online filesystem growth. | ||||
|  * The absolute maximum number of GDT blocks we can reserve is determined by | ||||
|  * the number of block pointers that can fit into a single block. | ||||
|  */ | ||||
| static int calc_reserved_gdt_blocks(ext2_filsys fs) | ||||
| { | ||||
| 	struct ext2_super_block *sb = fs->super; | ||||
| 	unsigned long bpg = sb->s_blocks_per_group; | ||||
| 	unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc); | ||||
| 	unsigned long max_blocks = 0xffffffff; | ||||
| 	unsigned long rsv_groups; | ||||
| 	int rsv_gdb; | ||||
|  | ||||
| 	/* We set it at 1024x the current filesystem size, or | ||||
| 	 * the upper block count limit (2^32), whichever is lower. | ||||
| 	 */ | ||||
| 	if (sb->s_blocks_count < max_blocks / 1024) | ||||
| 		max_blocks = sb->s_blocks_count * 1024; | ||||
| 	rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg; | ||||
| 	rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks; | ||||
| 	if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb)) | ||||
| 		rsv_gdb = EXT2_ADDR_PER_BLOCK(sb); | ||||
| #ifdef RES_GDT_DEBUG | ||||
| 	printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n", | ||||
| 	       max_blocks, rsv_groups, rsv_gdb); | ||||
| #endif | ||||
|  | ||||
| 	return rsv_gdb; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_initialize(const char *name, int flags, | ||||
| 			    struct ext2_super_block *param, | ||||
| 			    io_manager manager, ext2_filsys *ret_fs) | ||||
| { | ||||
| 	ext2_filsys	fs; | ||||
| 	errcode_t	retval; | ||||
| 	struct ext2_super_block *super; | ||||
| 	int		frags_per_block; | ||||
| 	unsigned int	rem; | ||||
| 	unsigned int	overhead = 0; | ||||
| 	blk_t		group_block; | ||||
| 	unsigned int	ipg; | ||||
| 	dgrp_t		i; | ||||
| 	blk_t		numblocks; | ||||
| 	int		rsv_gdt; | ||||
| 	char		*buf; | ||||
|  | ||||
| 	if (!param || !param->s_blocks_count) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	memset(fs, 0, sizeof(struct struct_ext2_filsys)); | ||||
| 	fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS; | ||||
| 	fs->flags = flags | EXT2_FLAG_RW; | ||||
| 	fs->umask = 022; | ||||
| #ifdef WORDS_BIGENDIAN | ||||
| 	fs->flags |= EXT2_FLAG_SWAP_BYTES; | ||||
| #endif | ||||
| 	retval = manager->open(name, IO_FLAG_RW, &fs->io); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	fs->image_io = fs->io; | ||||
| 	fs->io->app_data = fs; | ||||
| 	retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	strcpy(fs->device_name, name); | ||||
| 	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	fs->super = super; | ||||
|  | ||||
| 	memset(super, 0, SUPERBLOCK_SIZE); | ||||
|  | ||||
| #define set_field(field, default) (super->field = param->field ? \ | ||||
| 				   param->field : (default)) | ||||
|  | ||||
| 	super->s_magic = EXT2_SUPER_MAGIC; | ||||
| 	super->s_state = EXT2_VALID_FS; | ||||
|  | ||||
| 	set_field(s_log_block_size, 0);	/* default blocksize: 1024 bytes */ | ||||
| 	set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */ | ||||
| 	set_field(s_first_data_block, super->s_log_block_size ? 0 : 1); | ||||
| 	set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT); | ||||
| 	set_field(s_errors, EXT2_ERRORS_DEFAULT); | ||||
| 	set_field(s_feature_compat, 0); | ||||
| 	set_field(s_feature_incompat, 0); | ||||
| 	set_field(s_feature_ro_compat, 0); | ||||
| 	set_field(s_first_meta_bg, 0); | ||||
| 	if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { | ||||
| 		retval = EXT2_ET_UNSUPP_FEATURE; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
| 	if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { | ||||
| 		retval = EXT2_ET_RO_UNSUPP_FEATURE; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	set_field(s_rev_level, EXT2_GOOD_OLD_REV); | ||||
| 	if (super->s_rev_level >= EXT2_DYNAMIC_REV) { | ||||
| 		set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO); | ||||
| 		set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE); | ||||
| 	} | ||||
|  | ||||
| 	set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL); | ||||
| 	super->s_mkfs_time = super->s_lastcheck = time(NULL); | ||||
|  | ||||
| 	super->s_creator_os = CREATOR_OS; | ||||
|  | ||||
| 	fs->blocksize = EXT2_BLOCK_SIZE(super); | ||||
| 	fs->fragsize = EXT2_FRAG_SIZE(super); | ||||
| 	frags_per_block = fs->blocksize / fs->fragsize; | ||||
|  | ||||
| 	/* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */ | ||||
| 	set_field(s_blocks_per_group, fs->blocksize * 8); | ||||
| 	if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super)) | ||||
| 		super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super); | ||||
| 	super->s_frags_per_group = super->s_blocks_per_group * frags_per_block; | ||||
|  | ||||
| 	super->s_blocks_count = param->s_blocks_count; | ||||
| 	super->s_r_blocks_count = param->s_r_blocks_count; | ||||
| 	if (super->s_r_blocks_count >= param->s_blocks_count) { | ||||
| 		retval = EXT2_ET_INVALID_ARGUMENT; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If we're creating an external journal device, we don't need | ||||
| 	 * to bother with the rest. | ||||
| 	 */ | ||||
| 	if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { | ||||
| 		fs->group_desc_count = 0; | ||||
| 		ext2fs_mark_super_dirty(fs); | ||||
| 		*ret_fs = fs; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| retry: | ||||
| 	fs->group_desc_count = (super->s_blocks_count - | ||||
| 				super->s_first_data_block + | ||||
| 				EXT2_BLOCKS_PER_GROUP(super) - 1) | ||||
| 		/ EXT2_BLOCKS_PER_GROUP(super); | ||||
| 	if (fs->group_desc_count == 0) { | ||||
| 		retval = EXT2_ET_TOOSMALL; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
| 	fs->desc_blocks = (fs->group_desc_count + | ||||
| 			   EXT2_DESC_PER_BLOCK(super) - 1) | ||||
| 		/ EXT2_DESC_PER_BLOCK(super); | ||||
|  | ||||
| 	i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize; | ||||
| 	set_field(s_inodes_count, super->s_blocks_count / i); | ||||
|  | ||||
| 	/* | ||||
| 	 * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so | ||||
| 	 * that we have enough inodes for the filesystem(!) | ||||
| 	 */ | ||||
| 	if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1) | ||||
| 		super->s_inodes_count = EXT2_FIRST_INODE(super)+1; | ||||
|  | ||||
| 	/* | ||||
| 	 * There should be at least as many inodes as the user | ||||
| 	 * requested.  Figure out how many inodes per group that | ||||
| 	 * should be.  But make sure that we don't allocate more than | ||||
| 	 * one bitmap's worth of inodes each group. | ||||
| 	 */ | ||||
| 	ipg = (super->s_inodes_count + fs->group_desc_count - 1) / | ||||
| 		fs->group_desc_count; | ||||
| 	if (ipg > fs->blocksize * 8) { | ||||
| 		if (super->s_blocks_per_group >= 256) { | ||||
| 			/* Try again with slightly different parameters */ | ||||
| 			super->s_blocks_per_group -= 8; | ||||
| 			super->s_blocks_count = param->s_blocks_count; | ||||
| 			super->s_frags_per_group = super->s_blocks_per_group * | ||||
| 				frags_per_block; | ||||
| 			goto retry; | ||||
| 		} else | ||||
| 			return EXT2_ET_TOO_MANY_INODES; | ||||
| 	} | ||||
|  | ||||
| 	if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super)) | ||||
| 		ipg = EXT2_MAX_INODES_PER_GROUP(super); | ||||
|  | ||||
| 	super->s_inodes_per_group = ipg; | ||||
| 	if (super->s_inodes_count > ipg * fs->group_desc_count) | ||||
| 		super->s_inodes_count = ipg * fs->group_desc_count; | ||||
|  | ||||
| 	/* | ||||
| 	 * Make sure the number of inodes per group completely fills | ||||
| 	 * the inode table blocks in the descriptor.  If not, add some | ||||
| 	 * additional inodes/group.  Waste not, want not... | ||||
| 	 */ | ||||
| 	fs->inode_blocks_per_group = (((super->s_inodes_per_group * | ||||
| 					EXT2_INODE_SIZE(super)) + | ||||
| 				       EXT2_BLOCK_SIZE(super) - 1) / | ||||
| 				      EXT2_BLOCK_SIZE(super)); | ||||
| 	super->s_inodes_per_group = ((fs->inode_blocks_per_group * | ||||
| 				      EXT2_BLOCK_SIZE(super)) / | ||||
| 				     EXT2_INODE_SIZE(super)); | ||||
| 	/* | ||||
| 	 * Finally, make sure the number of inodes per group is a | ||||
| 	 * multiple of 8.  This is needed to simplify the bitmap | ||||
| 	 * splicing code. | ||||
| 	 */ | ||||
| 	super->s_inodes_per_group &= ~7; | ||||
| 	fs->inode_blocks_per_group = (((super->s_inodes_per_group * | ||||
| 					EXT2_INODE_SIZE(super)) + | ||||
| 				       EXT2_BLOCK_SIZE(super) - 1) / | ||||
| 				      EXT2_BLOCK_SIZE(super)); | ||||
|  | ||||
| 	/* | ||||
| 	 * adjust inode count to reflect the adjusted inodes_per_group | ||||
| 	 */ | ||||
| 	super->s_inodes_count = super->s_inodes_per_group * | ||||
| 		fs->group_desc_count; | ||||
| 	super->s_free_inodes_count = super->s_inodes_count; | ||||
|  | ||||
| 	/* | ||||
| 	 * check the number of reserved group descriptor table blocks | ||||
| 	 */ | ||||
| 	if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) | ||||
| 		rsv_gdt = calc_reserved_gdt_blocks(fs); | ||||
| 	else | ||||
| 		rsv_gdt = 0; | ||||
| 	set_field(s_reserved_gdt_blocks, rsv_gdt); | ||||
| 	if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) { | ||||
| 		retval = EXT2_ET_RES_GDT_BLOCKS; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Overhead is the number of bookkeeping blocks per group.  It | ||||
| 	 * includes the superblock backup, the group descriptor | ||||
| 	 * backups, the inode bitmap, the block bitmap, and the inode | ||||
| 	 * table. | ||||
| 	 */ | ||||
|  | ||||
| 	overhead = (int) (2 + fs->inode_blocks_per_group); | ||||
|  | ||||
| 	if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1)) | ||||
| 		overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks; | ||||
|  | ||||
| 	/* This can only happen if the user requested too many inodes */ | ||||
| 	if (overhead > super->s_blocks_per_group) | ||||
| 		return EXT2_ET_TOO_MANY_INODES; | ||||
|  | ||||
| 	/* | ||||
| 	 * See if the last group is big enough to support the | ||||
| 	 * necessary data structures.  If not, we need to get rid of | ||||
| 	 * it. | ||||
| 	 */ | ||||
| 	rem = ((super->s_blocks_count - super->s_first_data_block) % | ||||
| 	       super->s_blocks_per_group); | ||||
| 	if ((fs->group_desc_count == 1) && rem && (rem < overhead)) | ||||
| 		return EXT2_ET_TOOSMALL; | ||||
| 	if (rem && (rem < overhead+50)) { | ||||
| 		super->s_blocks_count -= rem; | ||||
| 		goto retry; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * At this point we know how big the filesystem will be.  So | ||||
| 	 * we can do any and all allocations that depend on the block | ||||
| 	 * count. | ||||
| 	 */ | ||||
|  | ||||
| 	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	sprintf(buf, "block bitmap for %s", fs->device_name); | ||||
| 	retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	sprintf(buf, "inode bitmap for %s", fs->device_name); | ||||
| 	retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	ext2fs_free_mem(&buf); | ||||
|  | ||||
| 	retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize, | ||||
| 				&fs->group_desc); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize); | ||||
|  | ||||
| 	/* | ||||
| 	 * Reserve the superblock and group descriptors for each | ||||
| 	 * group, and fill in the correct group statistics for group. | ||||
| 	 * Note that although the block bitmap, inode bitmap, and | ||||
| 	 * inode table have not been allocated (and in fact won't be | ||||
| 	 * by this routine), they are accounted for nevertheless. | ||||
| 	 */ | ||||
| 	group_block = super->s_first_data_block; | ||||
| 	super->s_free_blocks_count = 0; | ||||
| 	for (i = 0; i < fs->group_desc_count; i++) { | ||||
| 		numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map); | ||||
|  | ||||
| 		super->s_free_blocks_count += numblocks; | ||||
| 		fs->group_desc[i].bg_free_blocks_count = numblocks; | ||||
| 		fs->group_desc[i].bg_free_inodes_count = | ||||
| 			fs->super->s_inodes_per_group; | ||||
| 		fs->group_desc[i].bg_used_dirs_count = 0; | ||||
|  | ||||
| 		group_block += super->s_blocks_per_group; | ||||
| 	} | ||||
|  | ||||
| 	ext2fs_mark_super_dirty(fs); | ||||
| 	ext2fs_mark_bb_dirty(fs); | ||||
| 	ext2fs_mark_ib_dirty(fs); | ||||
|  | ||||
| 	io_channel_set_blksize(fs->io, fs->blocksize); | ||||
|  | ||||
| 	*ret_fs = fs; | ||||
| 	return 0; | ||||
| cleanup: | ||||
| 	ext2fs_free(fs); | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,32 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * inline.c --- Includes the inlined functions defined in the header | ||||
|  * files as standalone functions, in case the application program | ||||
|  * is compiled with inlining turned off. | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #define INCLUDE_INLINE_FUNCS | ||||
| #include "ext2fs.h" | ||||
| @@ -1,766 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * inode.c --- utility routines to read and write inodes | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fsP.h" | ||||
| #include "e2image.h" | ||||
|  | ||||
| struct ext2_struct_inode_scan { | ||||
| 	errcode_t		magic; | ||||
| 	ext2_filsys		fs; | ||||
| 	ext2_ino_t		current_inode; | ||||
| 	blk_t			current_block; | ||||
| 	dgrp_t			current_group; | ||||
| 	ext2_ino_t		inodes_left; | ||||
| 	blk_t			blocks_left; | ||||
| 	dgrp_t			groups_left; | ||||
| 	blk_t			inode_buffer_blocks; | ||||
| 	char *			inode_buffer; | ||||
| 	int			inode_size; | ||||
| 	char *			ptr; | ||||
| 	int			bytes_left; | ||||
| 	char			*temp_buffer; | ||||
| 	errcode_t		(*done_group)(ext2_filsys fs, | ||||
| 					      dgrp_t group, | ||||
| 					      void * priv_data); | ||||
| 	void *			done_group_data; | ||||
| 	int			bad_block_ptr; | ||||
| 	int			scan_flags; | ||||
| 	int			reserved[6]; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * This routine flushes the icache, if it exists. | ||||
|  */ | ||||
| errcode_t ext2fs_flush_icache(ext2_filsys fs) | ||||
| { | ||||
| 	int	i; | ||||
|  | ||||
| 	if (!fs->icache) | ||||
| 		return 0; | ||||
|  | ||||
| 	for (i=0; i < fs->icache->cache_size; i++) | ||||
| 		fs->icache->cache[i].ino = 0; | ||||
|  | ||||
| 	fs->icache->buffer_blk = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t create_icache(ext2_filsys fs) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (fs->icache) | ||||
| 		return 0; | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	memset(fs->icache, 0, sizeof(struct ext2_inode_cache)); | ||||
| 	retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer); | ||||
| 	if (retval) { | ||||
| 		ext2fs_free_mem(&fs->icache); | ||||
| 		return retval; | ||||
| 	} | ||||
| 	fs->icache->buffer_blk = 0; | ||||
| 	fs->icache->cache_last = -1; | ||||
| 	fs->icache->cache_size = 4; | ||||
| 	fs->icache->refcount = 1; | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent) | ||||
| 				* fs->icache->cache_size, | ||||
| 				&fs->icache->cache); | ||||
| 	if (retval) { | ||||
| 		ext2fs_free_mem(&fs->icache->buffer); | ||||
| 		ext2fs_free_mem(&fs->icache); | ||||
| 		return retval; | ||||
| 	} | ||||
| 	ext2fs_flush_icache(fs); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, | ||||
| 				 ext2_inode_scan *ret_scan) | ||||
| { | ||||
| 	ext2_inode_scan	scan; | ||||
| 	errcode_t	retval; | ||||
| 	errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks); | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	/* | ||||
| 	 * If fs->badblocks isn't set, then set it --- since the inode | ||||
| 	 * scanning functions require it. | ||||
| 	 */ | ||||
| 	if (fs->badblocks == 0) { | ||||
| 		/* | ||||
| 		 * Temporarly save fs->get_blocks and set it to zero, | ||||
| 		 * for compatibility with old e2fsck's. | ||||
| 		 */ | ||||
| 		save_get_blocks = fs->get_blocks; | ||||
| 		fs->get_blocks = 0; | ||||
| 		retval = ext2fs_read_bb_inode(fs, &fs->badblocks); | ||||
| 		if (retval) { | ||||
| 			ext2fs_badblocks_list_free(fs->badblocks); | ||||
| 			fs->badblocks = 0; | ||||
| 		} | ||||
| 		fs->get_blocks = save_get_blocks; | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	memset(scan, 0, sizeof(struct ext2_struct_inode_scan)); | ||||
|  | ||||
| 	scan->magic = EXT2_ET_MAGIC_INODE_SCAN; | ||||
| 	scan->fs = fs; | ||||
| 	scan->inode_size = EXT2_INODE_SIZE(fs->super); | ||||
| 	scan->bytes_left = 0; | ||||
| 	scan->current_group = 0; | ||||
| 	scan->groups_left = fs->group_desc_count - 1; | ||||
| 	scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8; | ||||
| 	scan->current_block = scan->fs-> | ||||
| 		group_desc[scan->current_group].bg_inode_table; | ||||
| 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); | ||||
| 	scan->blocks_left = scan->fs->inode_blocks_per_group; | ||||
| 	retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * | ||||
| 					  fs->blocksize), | ||||
| 				&scan->inode_buffer); | ||||
| 	scan->done_group = 0; | ||||
| 	scan->done_group_data = 0; | ||||
| 	scan->bad_block_ptr = 0; | ||||
| 	if (retval) { | ||||
| 		ext2fs_free_mem(&scan); | ||||
| 		return retval; | ||||
| 	} | ||||
| 	retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer); | ||||
| 	if (retval) { | ||||
| 		ext2fs_free_mem(&scan->inode_buffer); | ||||
| 		ext2fs_free_mem(&scan); | ||||
| 		return retval; | ||||
| 	} | ||||
| 	if (scan->fs->badblocks && scan->fs->badblocks->num) | ||||
| 		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS; | ||||
| 	*ret_scan = scan; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void ext2fs_close_inode_scan(ext2_inode_scan scan) | ||||
| { | ||||
| 	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) | ||||
| 		return; | ||||
|  | ||||
| 	ext2fs_free_mem(&scan->inode_buffer); | ||||
| 	scan->inode_buffer = NULL; | ||||
| 	ext2fs_free_mem(&scan->temp_buffer); | ||||
| 	scan->temp_buffer = NULL; | ||||
| 	ext2fs_free_mem(&scan); | ||||
| } | ||||
|  | ||||
| void ext2fs_set_inode_callback(ext2_inode_scan scan, | ||||
| 			       errcode_t (*done_group)(ext2_filsys fs, | ||||
| 						       dgrp_t group, | ||||
| 						       void * priv_data), | ||||
| 			       void *done_group_data) | ||||
| { | ||||
| 	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) | ||||
| 		return; | ||||
|  | ||||
| 	scan->done_group = done_group; | ||||
| 	scan->done_group_data = done_group_data; | ||||
| } | ||||
|  | ||||
| int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, | ||||
| 			    int clear_flags) | ||||
| { | ||||
| 	int	old_flags; | ||||
|  | ||||
| 	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) | ||||
| 		return 0; | ||||
|  | ||||
| 	old_flags = scan->scan_flags; | ||||
| 	scan->scan_flags &= ~clear_flags; | ||||
| 	scan->scan_flags |= set_flags; | ||||
| 	return old_flags; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function is called by ext2fs_get_next_inode when it needs to | ||||
|  * get ready to read in a new blockgroup. | ||||
|  */ | ||||
| static errcode_t get_next_blockgroup(ext2_inode_scan scan) | ||||
| { | ||||
| 	scan->current_group++; | ||||
| 	scan->groups_left--; | ||||
|  | ||||
| 	scan->current_block = scan->fs-> | ||||
| 		group_desc[scan->current_group].bg_inode_table; | ||||
|  | ||||
| 	scan->current_inode = scan->current_group * | ||||
| 		EXT2_INODES_PER_GROUP(scan->fs->super); | ||||
|  | ||||
| 	scan->bytes_left = 0; | ||||
| 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); | ||||
| 	scan->blocks_left = scan->fs->inode_blocks_per_group; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, | ||||
| 					    int	group) | ||||
| { | ||||
| 	scan->current_group = group - 1; | ||||
| 	scan->groups_left = scan->fs->group_desc_count - group; | ||||
| 	return get_next_blockgroup(scan); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function is called by get_next_blocks() to check for bad | ||||
|  * blocks in the inode table. | ||||
|  * | ||||
|  * This function assumes that badblocks_list->list is sorted in | ||||
|  * increasing order. | ||||
|  */ | ||||
| static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, | ||||
| 					    blk_t *num_blocks) | ||||
| { | ||||
| 	blk_t	blk = scan->current_block; | ||||
| 	badblocks_list	bb = scan->fs->badblocks; | ||||
|  | ||||
| 	/* | ||||
| 	 * If the inode table is missing, then obviously there are no | ||||
| 	 * bad blocks.  :-) | ||||
| 	 */ | ||||
| 	if (blk == 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * If the current block is greater than the bad block listed | ||||
| 	 * in the bad block list, then advance the pointer until this | ||||
| 	 * is no longer the case.  If we run out of bad blocks, then | ||||
| 	 * we don't need to do any more checking! | ||||
| 	 */ | ||||
| 	while (blk > bb->list[scan->bad_block_ptr]) { | ||||
| 		if (++scan->bad_block_ptr >= bb->num) { | ||||
| 			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If the current block is equal to the bad block listed in | ||||
| 	 * the bad block list, then handle that one block specially. | ||||
| 	 * (We could try to handle runs of bad blocks, but that | ||||
| 	 * only increases CPU efficiency by a small amount, at the | ||||
| 	 * expense of a huge expense of code complexity, and for an | ||||
| 	 * uncommon case at that.) | ||||
| 	 */ | ||||
| 	if (blk == bb->list[scan->bad_block_ptr]) { | ||||
| 		scan->scan_flags |= EXT2_SF_BAD_INODE_BLK; | ||||
| 		*num_blocks = 1; | ||||
| 		if (++scan->bad_block_ptr >= bb->num) | ||||
| 			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If there is a bad block in the range that we're about to | ||||
| 	 * read in, adjust the number of blocks to read so that we we | ||||
| 	 * don't read in the bad block.  (Then the next block to read | ||||
| 	 * will be the bad block, which is handled in the above case.) | ||||
| 	 */ | ||||
| 	if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr]) | ||||
| 		*num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function is called by ext2fs_get_next_inode when it needs to | ||||
|  * read in more blocks from the current blockgroup's inode table. | ||||
|  */ | ||||
| static errcode_t get_next_blocks(ext2_inode_scan scan) | ||||
| { | ||||
| 	blk_t		num_blocks; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	/* | ||||
| 	 * Figure out how many blocks to read; we read at most | ||||
| 	 * inode_buffer_blocks, and perhaps less if there aren't that | ||||
| 	 * many blocks left to read. | ||||
| 	 */ | ||||
| 	num_blocks = scan->inode_buffer_blocks; | ||||
| 	if (num_blocks > scan->blocks_left) | ||||
| 		num_blocks = scan->blocks_left; | ||||
|  | ||||
| 	/* | ||||
| 	 * If the past block "read" was a bad block, then mark the | ||||
| 	 * left-over extra bytes as also being bad. | ||||
| 	 */ | ||||
| 	if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) { | ||||
| 		if (scan->bytes_left) | ||||
| 			scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES; | ||||
| 		scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Do inode bad block processing, if necessary. | ||||
| 	 */ | ||||
| 	if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) { | ||||
| 		retval = check_for_inode_bad_blocks(scan, &num_blocks); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) || | ||||
| 	    (scan->current_block == 0)) { | ||||
| 		memset(scan->inode_buffer, 0, | ||||
| 		       (size_t) num_blocks * scan->fs->blocksize); | ||||
| 	} else { | ||||
| 		retval = io_channel_read_blk(scan->fs->io, | ||||
| 					     scan->current_block, | ||||
| 					     (int) num_blocks, | ||||
| 					     scan->inode_buffer); | ||||
| 		if (retval) | ||||
| 			return EXT2_ET_NEXT_INODE_READ; | ||||
| 	} | ||||
| 	scan->ptr = scan->inode_buffer; | ||||
| 	scan->bytes_left = num_blocks * scan->fs->blocksize; | ||||
|  | ||||
| 	scan->blocks_left -= num_blocks; | ||||
| 	if (scan->current_block) | ||||
| 		scan->current_block += num_blocks; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, | ||||
| 				     struct ext2_inode *inode, int bufsize) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	int		extra_bytes = 0; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN); | ||||
|  | ||||
| 	/* | ||||
| 	 * Do we need to start reading a new block group? | ||||
| 	 */ | ||||
| 	if (scan->inodes_left <= 0) { | ||||
| 	force_new_group: | ||||
| 		if (scan->done_group) { | ||||
| 			retval = (scan->done_group) | ||||
| 				(scan->fs, scan->current_group, | ||||
| 				 scan->done_group_data); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		if (scan->groups_left <= 0) { | ||||
| 			*ino = 0; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		retval = get_next_blockgroup(scan); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	/* | ||||
| 	 * This is done outside the above if statement so that the | ||||
| 	 * check can be done for block group #0. | ||||
| 	 */ | ||||
| 	if (scan->current_block == 0) { | ||||
| 		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) { | ||||
| 			goto force_new_group; | ||||
| 		} else | ||||
| 			return EXT2_ET_MISSING_INODE_TABLE; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/* | ||||
| 	 * Have we run out of space in the inode buffer?  If so, we | ||||
| 	 * need to read in more blocks. | ||||
| 	 */ | ||||
| 	if (scan->bytes_left < scan->inode_size) { | ||||
| 		memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left); | ||||
| 		extra_bytes = scan->bytes_left; | ||||
|  | ||||
| 		retval = get_next_blocks(scan); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| #if 0 | ||||
| 		/* | ||||
| 		 * XXX test  Need check for used inode somehow. | ||||
| 		 * (Note: this is hard.) | ||||
| 		 */ | ||||
| 		if (is_empty_scan(scan)) | ||||
| 			goto force_new_group; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	retval = 0; | ||||
| 	if (extra_bytes) { | ||||
| 		memcpy(scan->temp_buffer+extra_bytes, scan->ptr, | ||||
| 		       scan->inode_size - extra_bytes); | ||||
| 		scan->ptr += scan->inode_size - extra_bytes; | ||||
| 		scan->bytes_left -= scan->inode_size - extra_bytes; | ||||
|  | ||||
| #if BB_BIG_ENDIAN | ||||
| 		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | ||||
| 			ext2fs_swap_inode_full(scan->fs, | ||||
| 				(struct ext2_inode_large *) inode, | ||||
| 				(struct ext2_inode_large *) scan->temp_buffer, | ||||
| 				0, bufsize); | ||||
| 		else | ||||
| #endif | ||||
| 			*inode = *((struct ext2_inode *) scan->temp_buffer); | ||||
| 		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES) | ||||
| 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; | ||||
| 		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES; | ||||
| 	} else { | ||||
| #if BB_BIG_ENDIAN | ||||
| 		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | ||||
| 			ext2fs_swap_inode_full(scan->fs, | ||||
| 				(struct ext2_inode_large *) inode, | ||||
| 				(struct ext2_inode_large *) scan->ptr, | ||||
| 				0, bufsize); | ||||
| 		else | ||||
| #endif | ||||
| 			memcpy(inode, scan->ptr, bufsize); | ||||
| 		scan->ptr += scan->inode_size; | ||||
| 		scan->bytes_left -= scan->inode_size; | ||||
| 		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) | ||||
| 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; | ||||
| 	} | ||||
|  | ||||
| 	scan->inodes_left--; | ||||
| 	scan->current_inode++; | ||||
| 	*ino = scan->current_inode; | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, | ||||
| 				struct ext2_inode *inode) | ||||
| { | ||||
| 	return ext2fs_get_next_inode_full(scan, ino, inode, | ||||
| 						sizeof(struct ext2_inode)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Functions to read and write a single inode. | ||||
|  */ | ||||
| errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				 struct ext2_inode * inode, int bufsize) | ||||
| { | ||||
| 	unsigned long	group, block, block_nr, offset; | ||||
| 	char		*ptr; | ||||
| 	errcode_t	retval; | ||||
| 	int		clen, i, inodes_per_block, length; | ||||
| 	io_channel	io; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	/* Check to see if user has an override function */ | ||||
| 	if (fs->read_inode) { | ||||
| 		retval = (fs->read_inode)(fs, ino, inode); | ||||
| 		if (retval != EXT2_ET_CALLBACK_NOTHANDLED) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	/* Create inode cache if not present */ | ||||
| 	if (!fs->icache) { | ||||
| 		retval = create_icache(fs); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	/* Check to see if it's in the inode cache */ | ||||
| 	if (bufsize == sizeof(struct ext2_inode)) { | ||||
| 		/* only old good inode can be retrieve from the cache */ | ||||
| 		for (i=0; i < fs->icache->cache_size; i++) { | ||||
| 			if (fs->icache->cache[i].ino == ino) { | ||||
| 				*inode = fs->icache->cache[i].inode; | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if ((ino == 0) || (ino > fs->super->s_inodes_count)) | ||||
| 		return EXT2_ET_BAD_INODE_NUM; | ||||
| 	if (fs->flags & EXT2_FLAG_IMAGE_FILE) { | ||||
| 		inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); | ||||
| 		block_nr = fs->image_header->offset_inode / fs->blocksize; | ||||
| 		block_nr += (ino - 1) / inodes_per_block; | ||||
| 		offset = ((ino - 1) % inodes_per_block) * | ||||
| 			EXT2_INODE_SIZE(fs->super); | ||||
| 		io = fs->image_io; | ||||
| 	} else { | ||||
| 		group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); | ||||
| 		offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * | ||||
| 			EXT2_INODE_SIZE(fs->super); | ||||
| 		block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); | ||||
| 		if (!fs->group_desc[(unsigned)group].bg_inode_table) | ||||
| 			return EXT2_ET_MISSING_INODE_TABLE; | ||||
| 		block_nr = fs->group_desc[(unsigned)group].bg_inode_table + | ||||
| 			block; | ||||
| 		io = fs->io; | ||||
| 	} | ||||
| 	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); | ||||
|  | ||||
| 	length = EXT2_INODE_SIZE(fs->super); | ||||
| 	if (bufsize < length) | ||||
| 		length = bufsize; | ||||
|  | ||||
| 	ptr = (char *) inode; | ||||
| 	while (length) { | ||||
| 		clen = length; | ||||
| 		if ((offset + length) > fs->blocksize) | ||||
| 			clen = fs->blocksize - offset; | ||||
|  | ||||
| 		if (block_nr != fs->icache->buffer_blk) { | ||||
| 			retval = io_channel_read_blk(io, block_nr, 1, | ||||
| 						     fs->icache->buffer); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 			fs->icache->buffer_blk = block_nr; | ||||
| 		} | ||||
|  | ||||
| 		memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset, | ||||
| 		       clen); | ||||
|  | ||||
| 		offset = 0; | ||||
| 		length -= clen; | ||||
| 		ptr += clen; | ||||
| 		block_nr++; | ||||
| 	} | ||||
|  | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | ||||
| 		ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, | ||||
| 				       (struct ext2_inode_large *) inode, | ||||
| 				       0, length); | ||||
| #endif | ||||
|  | ||||
| 	/* Update the inode cache */ | ||||
| 	fs->icache->cache_last = (fs->icache->cache_last + 1) % | ||||
| 		fs->icache->cache_size; | ||||
| 	fs->icache->cache[fs->icache->cache_last].ino = ino; | ||||
| 	fs->icache->cache[fs->icache->cache_last].inode = *inode; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			    struct ext2_inode * inode) | ||||
| { | ||||
| 	return ext2fs_read_inode_full(fs, ino, inode, | ||||
| 					sizeof(struct ext2_inode)); | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				  struct ext2_inode * inode, int bufsize) | ||||
| { | ||||
| 	unsigned long group, block, block_nr, offset; | ||||
| 	errcode_t retval = 0; | ||||
| 	struct ext2_inode_large temp_inode, *w_inode; | ||||
| 	char *ptr; | ||||
| 	int clen, i, length; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	/* Check to see if user provided an override function */ | ||||
| 	if (fs->write_inode) { | ||||
| 		retval = (fs->write_inode)(fs, ino, inode); | ||||
| 		if (retval != EXT2_ET_CALLBACK_NOTHANDLED) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	/* Check to see if the inode cache needs to be updated */ | ||||
| 	if (fs->icache) { | ||||
| 		for (i=0; i < fs->icache->cache_size; i++) { | ||||
| 			if (fs->icache->cache[i].ino == ino) { | ||||
| 				fs->icache->cache[i].inode = *inode; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		retval = create_icache(fs); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	if (!(fs->flags & EXT2_FLAG_RW)) | ||||
| 		return EXT2_ET_RO_FILSYS; | ||||
|  | ||||
| 	if ((ino == 0) || (ino > fs->super->s_inodes_count)) | ||||
| 		return EXT2_ET_BAD_INODE_NUM; | ||||
|  | ||||
| 	length = bufsize; | ||||
| 	if (length < EXT2_INODE_SIZE(fs->super)) | ||||
| 		length = EXT2_INODE_SIZE(fs->super); | ||||
|  | ||||
| 	if (length > (int) sizeof(struct ext2_inode_large)) { | ||||
| 		w_inode = xmalloc(length); | ||||
| 	} else | ||||
| 		w_inode = &temp_inode; | ||||
| 	memset(w_inode, 0, length); | ||||
|  | ||||
| #if BB_BIG_ENDIAN | ||||
| 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | ||||
| 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) | ||||
| 		ext2fs_swap_inode_full(fs, w_inode, | ||||
| 				       (struct ext2_inode_large *) inode, | ||||
| 				       1, bufsize); | ||||
| 	else | ||||
| #endif | ||||
| 		memcpy(w_inode, inode, bufsize); | ||||
|  | ||||
| 	group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); | ||||
| 	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * | ||||
| 		EXT2_INODE_SIZE(fs->super); | ||||
| 	block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); | ||||
| 	if (!fs->group_desc[(unsigned) group].bg_inode_table) | ||||
| 		return EXT2_ET_MISSING_INODE_TABLE; | ||||
| 	block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block; | ||||
|  | ||||
| 	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); | ||||
|  | ||||
| 	length = EXT2_INODE_SIZE(fs->super); | ||||
| 	if (length > bufsize) | ||||
| 		length = bufsize; | ||||
|  | ||||
| 	ptr = (char *) w_inode; | ||||
|  | ||||
| 	while (length) { | ||||
| 		clen = length; | ||||
| 		if ((offset + length) > fs->blocksize) | ||||
| 			clen = fs->blocksize - offset; | ||||
|  | ||||
| 		if (fs->icache->buffer_blk != block_nr) { | ||||
| 			retval = io_channel_read_blk(fs->io, block_nr, 1, | ||||
| 						     fs->icache->buffer); | ||||
| 			if (retval) | ||||
| 				goto errout; | ||||
| 			fs->icache->buffer_blk = block_nr; | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		memcpy((char *) fs->icache->buffer + (unsigned) offset, | ||||
| 		       ptr, clen); | ||||
|  | ||||
| 		retval = io_channel_write_blk(fs->io, block_nr, 1, | ||||
| 					      fs->icache->buffer); | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
|  | ||||
| 		offset = 0; | ||||
| 		ptr += clen; | ||||
| 		length -= clen; | ||||
| 		block_nr++; | ||||
| 	} | ||||
|  | ||||
| 	fs->flags |= EXT2_FLAG_CHANGED; | ||||
| errout: | ||||
| 	if (w_inode && w_inode != &temp_inode) | ||||
| 		free(w_inode); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, | ||||
| 			     struct ext2_inode *inode) | ||||
| { | ||||
| 	return ext2fs_write_inode_full(fs, ino, inode, | ||||
| 				       sizeof(struct ext2_inode)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function should be called when writing a new inode.  It makes | ||||
|  * sure that extra part of large inodes is initialized properly. | ||||
|  */ | ||||
| errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				 struct ext2_inode *inode) | ||||
| { | ||||
| 	struct ext2_inode	*buf; | ||||
| 	int			size = EXT2_INODE_SIZE(fs->super); | ||||
| 	struct ext2_inode_large	*large_inode; | ||||
|  | ||||
| 	if (size == sizeof(struct ext2_inode)) | ||||
| 		return ext2fs_write_inode_full(fs, ino, inode, | ||||
| 					       sizeof(struct ext2_inode)); | ||||
|  | ||||
| 	buf = xmalloc(size); | ||||
|  | ||||
| 	memset(buf, 0, size); | ||||
| 	*buf = *inode; | ||||
|  | ||||
| 	large_inode = (struct ext2_inode_large *) buf; | ||||
| 	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - | ||||
| 		EXT2_GOOD_OLD_INODE_SIZE; | ||||
|  | ||||
| 	return ext2fs_write_inode_full(fs, ino, buf, size); | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks) | ||||
| { | ||||
| 	struct ext2_inode	inode; | ||||
| 	int			i; | ||||
| 	errcode_t		retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (ino > fs->super->s_inodes_count) | ||||
| 		return EXT2_ET_BAD_INODE_NUM; | ||||
|  | ||||
| 	if (fs->get_blocks) { | ||||
| 		if (!(*fs->get_blocks)(fs, ino, blocks)) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	retval = ext2fs_read_inode(fs, ino, &inode); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	for (i=0; i < EXT2_N_BLOCKS; i++) | ||||
| 		blocks[i] = inode.i_block[i]; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) | ||||
| { | ||||
| 	struct	ext2_inode	inode; | ||||
| 	errcode_t		retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (ino > fs->super->s_inodes_count) | ||||
| 		return EXT2_ET_BAD_INODE_NUM; | ||||
|  | ||||
| 	if (fs->check_directory) { | ||||
| 		retval = (fs->check_directory)(fs, ino); | ||||
| 		if (retval != EXT2_ET_CALLBACK_NOTHANDLED) | ||||
| 			return retval; | ||||
| 	} | ||||
| 	retval = ext2fs_read_inode(fs, ino, &inode); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 	if (!LINUX_S_ISDIR(inode.i_mode)) | ||||
| 		return EXT2_ET_NO_DIRECTORY; | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,270 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * inode_io.c --- This is allows an inode in an ext2 filesystem image | ||||
|  *	to be accessed via the I/O manager interface. | ||||
|  * | ||||
|  * Copyright (C) 2002 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <time.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * For checking structure magic numbers... | ||||
|  */ | ||||
|  | ||||
| #define EXT2_CHECK_MAGIC(struct, code) \ | ||||
| 	  if ((struct)->magic != (code)) return (code) | ||||
|  | ||||
| struct inode_private_data { | ||||
| 	int				magic; | ||||
| 	char				name[32]; | ||||
| 	ext2_file_t			file; | ||||
| 	ext2_filsys			fs; | ||||
| 	ext2_ino_t			ino; | ||||
| 	struct ext2_inode		inode; | ||||
| 	int				flags; | ||||
| 	struct inode_private_data	*next; | ||||
| }; | ||||
|  | ||||
| #define CHANNEL_HAS_INODE	0x8000 | ||||
|  | ||||
| static struct inode_private_data *top_intern; | ||||
| static int ino_unique = 0; | ||||
|  | ||||
| static errcode_t inode_open(const char *name, int flags, io_channel *channel); | ||||
| static errcode_t inode_close(io_channel channel); | ||||
| static errcode_t inode_set_blksize(io_channel channel, int blksize); | ||||
| static errcode_t inode_read_blk(io_channel channel, unsigned long block, | ||||
| 			       int count, void *data); | ||||
| static errcode_t inode_write_blk(io_channel channel, unsigned long block, | ||||
| 				int count, const void *data); | ||||
| static errcode_t inode_flush(io_channel channel); | ||||
| static errcode_t inode_write_byte(io_channel channel, unsigned long offset, | ||||
| 				int size, const void *data); | ||||
|  | ||||
| static struct struct_io_manager struct_inode_manager = { | ||||
| 	EXT2_ET_MAGIC_IO_MANAGER, | ||||
| 	"Inode I/O Manager", | ||||
| 	inode_open, | ||||
| 	inode_close, | ||||
| 	inode_set_blksize, | ||||
| 	inode_read_blk, | ||||
| 	inode_write_blk, | ||||
| 	inode_flush, | ||||
| 	inode_write_byte | ||||
| }; | ||||
|  | ||||
| io_manager inode_io_manager = &struct_inode_manager; | ||||
|  | ||||
| errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				  struct ext2_inode *inode, | ||||
| 				  char **name) | ||||
| { | ||||
| 	struct inode_private_data	*data; | ||||
| 	errcode_t			retval; | ||||
|  | ||||
| 	if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data), | ||||
| 				     &data))) | ||||
| 		return retval; | ||||
| 	data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL; | ||||
| 	sprintf(data->name, "%u:%d", ino, ino_unique++); | ||||
| 	data->file = 0; | ||||
| 	data->fs = fs; | ||||
| 	data->ino = ino; | ||||
| 	data->flags = 0; | ||||
| 	if (inode) { | ||||
| 		memcpy(&data->inode, inode, sizeof(struct ext2_inode)); | ||||
| 		data->flags |= CHANNEL_HAS_INODE; | ||||
| 	} | ||||
| 	data->next = top_intern; | ||||
| 	top_intern = data; | ||||
| 	*name = data->name; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, | ||||
| 				 char **name) | ||||
| { | ||||
| 	return ext2fs_inode_io_intern2(fs, ino, NULL, name); | ||||
| } | ||||
|  | ||||
|  | ||||
| static errcode_t inode_open(const char *name, int flags, io_channel *channel) | ||||
| { | ||||
| 	io_channel	io = NULL; | ||||
| 	struct inode_private_data *prev, *data = NULL; | ||||
| 	errcode_t	retval; | ||||
| 	int		open_flags; | ||||
|  | ||||
| 	if (name == 0) | ||||
| 		return EXT2_ET_BAD_DEVICE_NAME; | ||||
|  | ||||
| 	for (data = top_intern, prev = NULL; data; | ||||
| 	     prev = data, data = data->next) | ||||
| 		if (strcmp(name, data->name) == 0) | ||||
| 			break; | ||||
| 	if (!data) | ||||
| 		return ENOENT; | ||||
| 	if (prev) | ||||
| 		prev->next = data->next; | ||||
| 	else | ||||
| 		top_intern = data->next; | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	memset(io, 0, sizeof(struct struct_io_channel)); | ||||
|  | ||||
| 	io->magic = EXT2_ET_MAGIC_IO_CHANNEL; | ||||
| 	io->manager = inode_io_manager; | ||||
| 	retval = ext2fs_get_mem(strlen(name)+1, &io->name); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	strcpy(io->name, name); | ||||
| 	io->private_data = data; | ||||
| 	io->block_size = 1024; | ||||
| 	io->read_error = 0; | ||||
| 	io->write_error = 0; | ||||
| 	io->refcount = 1; | ||||
|  | ||||
| 	open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0; | ||||
| 	retval = ext2fs_file_open2(data->fs, data->ino, | ||||
| 				   (data->flags & CHANNEL_HAS_INODE) ? | ||||
| 				   &data->inode : 0, open_flags, | ||||
| 				   &data->file); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	*channel = io; | ||||
| 	return 0; | ||||
|  | ||||
| cleanup: | ||||
| 	if (data) { | ||||
| 		ext2fs_free_mem(&data); | ||||
| 	} | ||||
| 	if (io) | ||||
| 		ext2fs_free_mem(&io); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static errcode_t inode_close(io_channel channel) | ||||
| { | ||||
| 	struct inode_private_data *data; | ||||
| 	errcode_t	retval = 0; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
| 	data = (struct inode_private_data *) channel->private_data; | ||||
| 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); | ||||
|  | ||||
| 	if (--channel->refcount > 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	retval = ext2fs_file_close(data->file); | ||||
|  | ||||
| 	ext2fs_free_mem(&channel->private_data); | ||||
| 	if (channel->name) | ||||
| 		ext2fs_free_mem(&channel->name); | ||||
| 	ext2fs_free_mem(&channel); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static errcode_t inode_set_blksize(io_channel channel, int blksize) | ||||
| { | ||||
| 	struct inode_private_data *data; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
| 	data = (struct inode_private_data *) channel->private_data; | ||||
| 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); | ||||
|  | ||||
| 	channel->block_size = blksize; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static errcode_t inode_read_blk(io_channel channel, unsigned long block, | ||||
| 			       int count, void *buf) | ||||
| { | ||||
| 	struct inode_private_data *data; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
| 	data = (struct inode_private_data *) channel->private_data; | ||||
| 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); | ||||
|  | ||||
| 	if ((retval = ext2fs_file_lseek(data->file, | ||||
| 					block * channel->block_size, | ||||
| 					EXT2_SEEK_SET, 0))) | ||||
| 		return retval; | ||||
|  | ||||
| 	count = (count < 0) ? -count : (count * channel->block_size); | ||||
|  | ||||
| 	return ext2fs_file_read(data->file, buf, count, 0); | ||||
| } | ||||
|  | ||||
| static errcode_t inode_write_blk(io_channel channel, unsigned long block, | ||||
| 				int count, const void *buf) | ||||
| { | ||||
| 	struct inode_private_data *data; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
| 	data = (struct inode_private_data *) channel->private_data; | ||||
| 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); | ||||
|  | ||||
| 	if ((retval = ext2fs_file_lseek(data->file, | ||||
| 					block * channel->block_size, | ||||
| 					EXT2_SEEK_SET, 0))) | ||||
| 		return retval; | ||||
|  | ||||
| 	count = (count < 0) ? -count : (count * channel->block_size); | ||||
|  | ||||
| 	return ext2fs_file_write(data->file, buf, count, 0); | ||||
| } | ||||
|  | ||||
| static errcode_t inode_write_byte(io_channel channel, unsigned long offset, | ||||
| 				 int size, const void *buf) | ||||
| { | ||||
| 	struct inode_private_data *data; | ||||
| 	errcode_t	retval = 0; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
| 	data = (struct inode_private_data *) channel->private_data; | ||||
| 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); | ||||
|  | ||||
| 	if ((retval = ext2fs_file_lseek(data->file, offset, | ||||
| 					EXT2_SEEK_SET, 0))) | ||||
| 		return retval; | ||||
|  | ||||
| 	return ext2fs_file_write(data->file, buf, size, 0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Flush data buffers to disk. | ||||
|  */ | ||||
| static errcode_t inode_flush(io_channel channel) | ||||
| { | ||||
| 	struct inode_private_data *data; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
| 	data = (struct inode_private_data *) channel->private_data; | ||||
| 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); | ||||
|  | ||||
| 	return ext2fs_file_flush(data->file); | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * io_manager.c --- the I/O manager abstraction | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| errcode_t io_channel_set_options(io_channel channel, const char *opts) | ||||
| { | ||||
| 	errcode_t retval = 0; | ||||
| 	char *next, *ptr, *options, *arg; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
|  | ||||
| 	if (!opts) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!channel->manager->set_option) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	options = malloc(strlen(opts)+1); | ||||
| 	if (!options) | ||||
| 		return EXT2_ET_NO_MEMORY; | ||||
| 	strcpy(options, opts); | ||||
| 	ptr = options; | ||||
|  | ||||
| 	while (ptr && *ptr) { | ||||
| 		next = strchr(ptr, '&'); | ||||
| 		if (next) | ||||
| 			*next++ = 0; | ||||
|  | ||||
| 		arg = strchr(ptr, '='); | ||||
| 		if (arg) | ||||
| 			*arg++ = 0; | ||||
|  | ||||
| 		retval = (channel->manager->set_option)(channel, ptr, arg); | ||||
| 		if (retval) | ||||
| 			break; | ||||
| 		ptr = next; | ||||
| 	} | ||||
| 	free(options); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| errcode_t io_channel_write_byte(io_channel channel, unsigned long offset, | ||||
| 				int count, const void *data) | ||||
| { | ||||
| 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); | ||||
|  | ||||
| 	if (channel->manager->write_byte) | ||||
| 		return channel->manager->write_byte(channel, offset, | ||||
| 						    count, data); | ||||
|  | ||||
| 	return EXT2_ET_UNIMPLEMENTED; | ||||
| } | ||||
| @@ -1,115 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * irel.h | ||||
|  * | ||||
|  * Copyright (C) 1996, 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| struct ext2_inode_reference { | ||||
| 	blk_t	block; | ||||
| 	__u16 offset; | ||||
| }; | ||||
|  | ||||
| struct ext2_inode_relocate_entry { | ||||
| 	ext2_ino_t	new; | ||||
| 	ext2_ino_t	orig; | ||||
| 	__u16		flags; | ||||
| 	__u16		max_refs; | ||||
| }; | ||||
|  | ||||
| typedef struct ext2_inode_relocation_table *ext2_irel; | ||||
|  | ||||
| struct ext2_inode_relocation_table { | ||||
| 	__u32	magic; | ||||
| 	char	*name; | ||||
| 	ext2_ino_t	current; | ||||
| 	void	*priv_data; | ||||
|  | ||||
| 	/* | ||||
| 	 * Add an inode relocation entry. | ||||
| 	 */ | ||||
| 	errcode_t (*put)(ext2_irel irel, ext2_ino_t old, | ||||
| 			      struct ext2_inode_relocate_entry *ent); | ||||
| 	/* | ||||
| 	 * Get an inode relocation entry. | ||||
| 	 */ | ||||
| 	errcode_t (*get)(ext2_irel irel, ext2_ino_t old, | ||||
| 			      struct ext2_inode_relocate_entry *ent); | ||||
|  | ||||
| 	/* | ||||
| 	 * Get an inode relocation entry by its original inode number | ||||
| 	 */ | ||||
| 	errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, | ||||
| 				 struct ext2_inode_relocate_entry *ent); | ||||
|  | ||||
| 	/* | ||||
| 	 * Initialize for iterating over the inode relocation entries. | ||||
| 	 */ | ||||
| 	errcode_t (*start_iter)(ext2_irel irel); | ||||
|  | ||||
| 	/* | ||||
| 	 * The iterator function for the inode relocation entries. | ||||
| 	 * Returns an inode number of 0 when out of entries. | ||||
| 	 */ | ||||
| 	errcode_t (*next)(ext2_irel irel, ext2_ino_t *old, | ||||
| 			  struct ext2_inode_relocate_entry *ent); | ||||
|  | ||||
| 	/* | ||||
| 	 * Add an inode reference (i.e., note the fact that a | ||||
| 	 * particular block/offset contains a reference to an inode) | ||||
| 	 */ | ||||
| 	errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino, | ||||
| 			     struct ext2_inode_reference *ref); | ||||
|  | ||||
| 	/* | ||||
| 	 * Initialize for iterating over the inode references for a | ||||
| 	 * particular inode. | ||||
| 	 */ | ||||
| 	errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino); | ||||
|  | ||||
| 	/* | ||||
| 	 * The iterator function for the inode references for an | ||||
| 	 * inode.  The references for only one inode can be interator | ||||
| 	 * over at a time, as the iterator state is stored in ext2_irel. | ||||
| 	 */ | ||||
| 	errcode_t (*next_ref)(ext2_irel irel, | ||||
| 			      struct ext2_inode_reference *ref); | ||||
|  | ||||
| 	/* | ||||
| 	 * Move the inode relocation table from one inode number to | ||||
| 	 * another.  Note that the inode references also must move. | ||||
| 	 */ | ||||
| 	errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new); | ||||
|  | ||||
| 	/* | ||||
| 	 * Remove an inode relocation entry, along with all of the | ||||
| 	 * inode references. | ||||
| 	 */ | ||||
| 	errcode_t (*delete)(ext2_irel irel, ext2_ino_t old); | ||||
|  | ||||
| 	/* | ||||
| 	 * Free the inode relocation table. | ||||
| 	 */ | ||||
| 	errcode_t (*free)(ext2_irel irel); | ||||
| }; | ||||
|  | ||||
| errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode, | ||||
| 				    ext2_irel *irel); | ||||
|  | ||||
| #define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent)) | ||||
| #define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent)) | ||||
| #define ext2fs_irel_get_by_orig(irel, orig, old, ent) \ | ||||
| 			((irel)->get_by_orig((irel), orig, old, ent)) | ||||
| #define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel))) | ||||
| #define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent)) | ||||
| #define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref)) | ||||
| #define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino)) | ||||
| #define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref)) | ||||
| #define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new)) | ||||
| #define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old)) | ||||
| #define ext2fs_irel_free(irel) ((irel)->free((irel))) | ||||
| @@ -1,367 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * irel_ma.c | ||||
|  * | ||||
|  * Copyright (C) 1996, 1997 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
| #include "irel.h" | ||||
|  | ||||
| static errcode_t ima_put(ext2_irel irel, ext2_ino_t old, | ||||
| 			 struct ext2_inode_relocate_entry *ent); | ||||
| static errcode_t ima_get(ext2_irel irel, ext2_ino_t old, | ||||
| 			 struct ext2_inode_relocate_entry *ent); | ||||
| static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, | ||||
| 				 struct ext2_inode_relocate_entry *ent); | ||||
| static errcode_t ima_start_iter(ext2_irel irel); | ||||
| static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old, | ||||
| 			  struct ext2_inode_relocate_entry *ent); | ||||
| static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino, | ||||
| 			     struct ext2_inode_reference *ref); | ||||
| static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino); | ||||
| static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref); | ||||
| static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new); | ||||
| static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old); | ||||
| static errcode_t ima_free(ext2_irel irel); | ||||
|  | ||||
| /* | ||||
|  * This data structure stores the array of inode references; there is | ||||
|  * a structure for each inode. | ||||
|  */ | ||||
| struct inode_reference_entry { | ||||
| 	__u16 num; | ||||
| 	struct ext2_inode_reference *refs; | ||||
| }; | ||||
|  | ||||
| struct irel_ma { | ||||
| 	__u32 magic; | ||||
| 	ext2_ino_t max_inode; | ||||
| 	ext2_ino_t ref_current; | ||||
| 	int   ref_iter; | ||||
| 	ext2_ino_t	*orig_map; | ||||
| 	struct ext2_inode_relocate_entry *entries; | ||||
| 	struct inode_reference_entry *ref_entries; | ||||
| }; | ||||
|  | ||||
| errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode, | ||||
| 				      ext2_irel *new_irel) | ||||
| { | ||||
| 	ext2_irel		irel = 0; | ||||
| 	errcode_t	retval; | ||||
| 	struct irel_ma	*ma = 0; | ||||
| 	size_t		size; | ||||
|  | ||||
| 	*new_irel = 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate memory structures | ||||
| 	 */ | ||||
| 	retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table), | ||||
| 				&irel); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(irel, 0, sizeof(struct ext2_inode_relocation_table)); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(strlen(name)+1, &irel->name); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	strcpy(irel->name, name); | ||||
|  | ||||
| 	retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(ma, 0, sizeof(struct irel_ma)); | ||||
| 	irel->priv_data = ma; | ||||
|  | ||||
| 	size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1)); | ||||
| 	retval = ext2fs_get_mem(size, &ma->orig_map); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(ma->orig_map, 0, size); | ||||
|  | ||||
| 	size = (size_t) (sizeof(struct ext2_inode_relocate_entry) * | ||||
| 			 (max_inode+1)); | ||||
| 	retval = ext2fs_get_mem(size, &ma->entries); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(ma->entries, 0, size); | ||||
|  | ||||
| 	size = (size_t) (sizeof(struct inode_reference_entry) * | ||||
| 			 (max_inode+1)); | ||||
| 	retval = ext2fs_get_mem(size, &ma->ref_entries); | ||||
| 	if (retval) | ||||
| 		goto errout; | ||||
| 	memset(ma->ref_entries, 0, size); | ||||
| 	ma->max_inode = max_inode; | ||||
|  | ||||
| 	/* | ||||
| 	 * Fill in the irel data structure | ||||
| 	 */ | ||||
| 	irel->put = ima_put; | ||||
| 	irel->get = ima_get; | ||||
| 	irel->get_by_orig = ima_get_by_orig; | ||||
| 	irel->start_iter = ima_start_iter; | ||||
| 	irel->next = ima_next; | ||||
| 	irel->add_ref = ima_add_ref; | ||||
| 	irel->start_iter_ref = ima_start_iter_ref; | ||||
| 	irel->next_ref = ima_next_ref; | ||||
| 	irel->move = ima_move; | ||||
| 	irel->delete = ima_delete; | ||||
| 	irel->free = ima_free; | ||||
|  | ||||
| 	*new_irel = irel; | ||||
| 	return 0; | ||||
|  | ||||
| errout: | ||||
| 	ima_free(irel); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_put(ext2_irel irel, ext2_ino_t old, | ||||
| 			struct ext2_inode_relocate_entry *ent) | ||||
| { | ||||
| 	struct inode_reference_entry	*ref_ent; | ||||
| 	struct irel_ma			*ma; | ||||
| 	errcode_t			retval; | ||||
| 	size_t				size, old_size; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if (old > ma->max_inode) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	/* | ||||
| 	 * Force the orig field to the correct value; the application | ||||
| 	 * program shouldn't be messing with this field. | ||||
| 	 */ | ||||
| 	if (ma->entries[(unsigned) old].new == 0) | ||||
| 		ent->orig = old; | ||||
| 	else | ||||
| 		ent->orig = ma->entries[(unsigned) old].orig; | ||||
|  | ||||
| 	/* | ||||
| 	 * If max_refs has changed, reallocate the refs array | ||||
| 	 */ | ||||
| 	ref_ent = ma->ref_entries + (unsigned) old; | ||||
| 	if (ref_ent->refs && ent->max_refs != | ||||
| 	    ma->entries[(unsigned) old].max_refs) { | ||||
| 		size = (sizeof(struct ext2_inode_reference) * ent->max_refs); | ||||
| 		old_size = (sizeof(struct ext2_inode_reference) * | ||||
| 			    ma->entries[(unsigned) old].max_refs); | ||||
| 		retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	ma->entries[(unsigned) old] = *ent; | ||||
| 	ma->orig_map[(unsigned) ent->orig] = old; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_get(ext2_irel irel, ext2_ino_t old, | ||||
| 			struct ext2_inode_relocate_entry *ent) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if (old > ma->max_inode) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned) old].new == 0) | ||||
| 		return ENOENT; | ||||
| 	*ent = ma->entries[(unsigned) old]; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, | ||||
| 			struct ext2_inode_relocate_entry *ent) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
| 	ext2_ino_t	ino; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if (orig > ma->max_inode) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	ino = ma->orig_map[(unsigned) orig]; | ||||
| 	if (ino == 0) | ||||
| 		return ENOENT; | ||||
| 	*old = ino; | ||||
| 	*ent = ma->entries[(unsigned) ino]; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_start_iter(ext2_irel irel) | ||||
| { | ||||
| 	irel->current = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old, | ||||
| 			 struct ext2_inode_relocate_entry *ent) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	while (++irel->current < ma->max_inode) { | ||||
| 		if (ma->entries[(unsigned) irel->current].new == 0) | ||||
| 			continue; | ||||
| 		*old = irel->current; | ||||
| 		*ent = ma->entries[(unsigned) irel->current]; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*old = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino, | ||||
| 			     struct ext2_inode_reference *ref) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
| 	size_t		size; | ||||
| 	struct inode_reference_entry *ref_ent; | ||||
| 	struct ext2_inode_relocate_entry *ent; | ||||
| 	errcode_t		retval; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if (ino > ma->max_inode) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
|  | ||||
| 	ref_ent = ma->ref_entries + (unsigned) ino; | ||||
| 	ent = ma->entries + (unsigned) ino; | ||||
|  | ||||
| 	/* | ||||
| 	 * If the inode reference array doesn't exist, create it. | ||||
| 	 */ | ||||
| 	if (ref_ent->refs == 0) { | ||||
| 		size = (size_t) ((sizeof(struct ext2_inode_reference) * | ||||
| 				  ent->max_refs)); | ||||
| 		retval = ext2fs_get_mem(size, &ref_ent->refs); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		memset(ref_ent->refs, 0, size); | ||||
| 		ref_ent->num = 0; | ||||
| 	} | ||||
|  | ||||
| 	if (ref_ent->num >= ent->max_refs) | ||||
| 		return EXT2_ET_TOO_MANY_REFS; | ||||
|  | ||||
| 	ref_ent->refs[(unsigned) ref_ent->num++] = *ref; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if (ino > ma->max_inode) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned) ino].new == 0) | ||||
| 		return ENOENT; | ||||
| 	ma->ref_current = ino; | ||||
| 	ma->ref_iter = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_next_ref(ext2_irel irel, | ||||
| 			      struct ext2_inode_reference *ref) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
| 	struct inode_reference_entry *ref_ent; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
|  | ||||
| 	ref_ent = ma->ref_entries + ma->ref_current; | ||||
|  | ||||
| 	if ((ref_ent->refs == NULL) || | ||||
| 	    (ma->ref_iter >= ref_ent->num)) { | ||||
| 		ref->block = 0; | ||||
| 		ref->offset = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*ref = ref_ent->refs[ma->ref_iter++]; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if ((old > ma->max_inode) || (new > ma->max_inode)) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned) old].new == 0) | ||||
| 		return ENOENT; | ||||
|  | ||||
| 	ma->entries[(unsigned) new] = ma->entries[(unsigned) old]; | ||||
| 	ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs); | ||||
| 	ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old]; | ||||
|  | ||||
| 	ma->entries[(unsigned) old].new = 0; | ||||
| 	ma->ref_entries[(unsigned) old].num = 0; | ||||
| 	ma->ref_entries[(unsigned) old].refs = 0; | ||||
|  | ||||
| 	ma->orig_map[ma->entries[new].orig] = new; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
| 	if (old > ma->max_inode) | ||||
| 		return EXT2_ET_INVALID_ARGUMENT; | ||||
| 	if (ma->entries[(unsigned) old].new == 0) | ||||
| 		return ENOENT; | ||||
|  | ||||
| 	ma->entries[old].new = 0; | ||||
| 	ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs); | ||||
| 	ma->orig_map[ma->entries[(unsigned) old].orig] = 0; | ||||
|  | ||||
| 	ma->ref_entries[(unsigned) old].num = 0; | ||||
| 	ma->ref_entries[(unsigned) old].refs = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static errcode_t ima_free(ext2_irel irel) | ||||
| { | ||||
| 	struct irel_ma	*ma; | ||||
| 	ext2_ino_t	ino; | ||||
|  | ||||
| 	if (!irel) | ||||
| 		return 0; | ||||
|  | ||||
| 	ma = irel->priv_data; | ||||
|  | ||||
| 	if (ma) { | ||||
| 		ext2fs_free_mem(&ma->orig_map); | ||||
| 		ext2fs_free_mem(&ma->entries); | ||||
| 		if (ma->ref_entries) { | ||||
| 			for (ino = 0; ino <= ma->max_inode; ino++) { | ||||
| 				ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs); | ||||
| 			} | ||||
| 			ext2fs_free_mem(&ma->ref_entries); | ||||
| 		} | ||||
| 		ext2fs_free_mem(&ma); | ||||
| 	} | ||||
| 	ext2fs_free_mem(&irel->name); | ||||
| 	ext2fs_free_mem(&irel); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,357 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * ismounted.c --- Check to see if the filesystem was mounted | ||||
|  * | ||||
|  * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #ifdef HAVE_LINUX_FD_H | ||||
| #include <linux/fd.h> | ||||
| #endif | ||||
| #ifdef HAVE_MNTENT_H | ||||
| #include <mntent.h> | ||||
| #endif | ||||
| #ifdef HAVE_GETMNTINFO | ||||
| #include <paths.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/mount.h> | ||||
| #endif /* HAVE_GETMNTINFO */ | ||||
| #include <string.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| #ifdef HAVE_MNTENT_H | ||||
| /* | ||||
|  * Helper function which checks a file in /etc/mtab format to see if a | ||||
|  * filesystem is mounted.  Returns an error if the file doesn't exist | ||||
|  * or can't be opened. | ||||
|  */ | ||||
| static errcode_t check_mntent_file(const char *mtab_file, const char *file, | ||||
| 				   int *mount_flags, char *mtpt, int mtlen) | ||||
| { | ||||
| 	struct mntent	*mnt; | ||||
| 	struct stat	st_buf; | ||||
| 	errcode_t	retval = 0; | ||||
| 	dev_t		file_dev=0, file_rdev=0; | ||||
| 	ino_t		file_ino=0; | ||||
| 	FILE		*f; | ||||
| 	int		fd; | ||||
|  | ||||
| 	*mount_flags = 0; | ||||
| 	if ((f = setmntent (mtab_file, "r")) == NULL) | ||||
| 		return errno; | ||||
| 	if (stat(file, &st_buf) == 0) { | ||||
| 		if (S_ISBLK(st_buf.st_mode)) { | ||||
| #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ | ||||
| 			file_rdev = st_buf.st_rdev; | ||||
| #endif  /* __GNU__ */ | ||||
| 		} else { | ||||
| 			file_dev = st_buf.st_dev; | ||||
| 			file_ino = st_buf.st_ino; | ||||
| 		} | ||||
| 	} | ||||
| 	while ((mnt = getmntent (f)) != NULL) { | ||||
| 		if (strcmp(file, mnt->mnt_fsname) == 0) | ||||
| 			break; | ||||
| 		if (stat(mnt->mnt_fsname, &st_buf) == 0) { | ||||
| 			if (S_ISBLK(st_buf.st_mode)) { | ||||
| #ifndef __GNU__ | ||||
| 				if (file_rdev && (file_rdev == st_buf.st_rdev)) | ||||
| 					break; | ||||
| #endif  /* __GNU__ */ | ||||
| 			} else { | ||||
| 				if (file_dev && ((file_dev == st_buf.st_dev) && | ||||
| 						 (file_ino == st_buf.st_ino))) | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (mnt == 0) { | ||||
| #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ | ||||
| 		/* | ||||
| 		 * Do an extra check to see if this is the root device.  We | ||||
| 		 * can't trust /etc/mtab, and /proc/mounts will only list | ||||
| 		 * /dev/root for the root filesystem.  Argh.  Instead we | ||||
| 		 * check if the given device has the same major/minor number | ||||
| 		 * as the device that the root directory is on. | ||||
| 		 */ | ||||
| 		if (file_rdev && stat("/", &st_buf) == 0) { | ||||
| 			if (st_buf.st_dev == file_rdev) { | ||||
| 				*mount_flags = EXT2_MF_MOUNTED; | ||||
| 				if (mtpt) | ||||
| 					strncpy(mtpt, "/", mtlen); | ||||
| 				goto is_root; | ||||
| 			} | ||||
| 		} | ||||
| #endif  /* __GNU__ */ | ||||
| 		goto errout; | ||||
| 	} | ||||
| #ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ | ||||
| 	/* Validate the entry in case /etc/mtab is out of date */ | ||||
| 	/* | ||||
| 	 * We need to be paranoid, because some broken distributions | ||||
| 	 * (read: Slackware) don't initialize /etc/mtab before checking | ||||
| 	 * all of the non-root filesystems on the disk. | ||||
| 	 */ | ||||
| 	if (stat(mnt->mnt_dir, &st_buf) < 0) { | ||||
| 		retval = errno; | ||||
| 		if (retval == ENOENT) { | ||||
| #ifdef DEBUG | ||||
| 			printf("Bogus entry in %s!  (%s does not exist)\n", | ||||
| 			       mtab_file, mnt->mnt_dir); | ||||
| #endif /* DEBUG */ | ||||
| 			retval = 0; | ||||
| 		} | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (file_rdev && (st_buf.st_dev != file_rdev)) { | ||||
| #ifdef DEBUG | ||||
| 		printf("Bogus entry in %s!  (%s not mounted on %s)\n", | ||||
| 		       mtab_file, file, mnt->mnt_dir); | ||||
| #endif /* DEBUG */ | ||||
| 		goto errout; | ||||
| 	} | ||||
| #endif /* __GNU__ */ | ||||
| 	*mount_flags = EXT2_MF_MOUNTED; | ||||
|  | ||||
| #ifdef MNTOPT_RO | ||||
| 	/* Check to see if the ro option is set */ | ||||
| 	if (hasmntopt(mnt, MNTOPT_RO)) | ||||
| 		*mount_flags |= EXT2_MF_READONLY; | ||||
| #endif | ||||
|  | ||||
| 	if (mtpt) | ||||
| 		strncpy(mtpt, mnt->mnt_dir, mtlen); | ||||
| 	/* | ||||
| 	 * Check to see if we're referring to the root filesystem. | ||||
| 	 * If so, do a manual check to see if we can open /etc/mtab | ||||
| 	 * read/write, since if the root is mounted read/only, the | ||||
| 	 * contents of /etc/mtab may not be accurate. | ||||
| 	 */ | ||||
| 	if (LONE_CHAR(mnt->mnt_dir, '/')) { | ||||
| is_root: | ||||
| #define TEST_FILE "/.ismount-test-file" | ||||
| 		*mount_flags |= EXT2_MF_ISROOT; | ||||
| 		fd = open(TEST_FILE, O_RDWR|O_CREAT); | ||||
| 		if (fd < 0) { | ||||
| 			if (errno == EROFS) | ||||
| 				*mount_flags |= EXT2_MF_READONLY; | ||||
| 		} else | ||||
| 			close(fd); | ||||
| 		(void) unlink(TEST_FILE); | ||||
| 	} | ||||
| 	retval = 0; | ||||
| errout: | ||||
| 	endmntent (f); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static errcode_t check_mntent(const char *file, int *mount_flags, | ||||
| 			      char *mtpt, int mtlen) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| #ifdef DEBUG | ||||
| 	retval = check_mntent_file("/tmp/mtab", file, mount_flags, | ||||
| 				   mtpt, mtlen); | ||||
| 	if (retval == 0) | ||||
| 		return 0; | ||||
| #endif /* DEBUG */ | ||||
| #ifdef __linux__ | ||||
| 	retval = check_mntent_file("/proc/mounts", file, mount_flags, | ||||
| 				   mtpt, mtlen); | ||||
| 	if (retval == 0 && (*mount_flags != 0)) | ||||
| 		return 0; | ||||
| #endif /* __linux__ */ | ||||
| #if defined(MOUNTED) || defined(_PATH_MOUNTED) | ||||
| #ifndef MOUNTED | ||||
| #define MOUNTED _PATH_MOUNTED | ||||
| #endif /* MOUNTED */ | ||||
| 	retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); | ||||
| 	return retval; | ||||
| #else | ||||
| 	*mount_flags = 0; | ||||
| 	return 0; | ||||
| #endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */ | ||||
| } | ||||
|  | ||||
| #else | ||||
| #if defined(HAVE_GETMNTINFO) | ||||
|  | ||||
| static errcode_t check_getmntinfo(const char *file, int *mount_flags, | ||||
| 				  char *mtpt, int mtlen) | ||||
| { | ||||
| 	struct statfs *mp; | ||||
| 	int    len, n; | ||||
| 	const  char   *s1; | ||||
| 	char	*s2; | ||||
|  | ||||
| 	n = getmntinfo(&mp, MNT_NOWAIT); | ||||
| 	if (n == 0) | ||||
| 		return errno; | ||||
|  | ||||
| 	len = sizeof(_PATH_DEV) - 1; | ||||
| 	s1 = file; | ||||
| 	if (strncmp(_PATH_DEV, s1, len) == 0) | ||||
| 		s1 += len; | ||||
|  | ||||
| 	*mount_flags = 0; | ||||
| 	while (--n >= 0) { | ||||
| 		s2 = mp->f_mntfromname; | ||||
| 		if (strncmp(_PATH_DEV, s2, len) == 0) { | ||||
| 			s2 += len - 1; | ||||
| 			*s2 = 'r'; | ||||
| 		} | ||||
| 		if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { | ||||
| 			*mount_flags = EXT2_MF_MOUNTED; | ||||
| 			break; | ||||
| 		} | ||||
| 		++mp; | ||||
| 	} | ||||
| 	if (mtpt) | ||||
| 		strncpy(mtpt, mp->f_mntonname, mtlen); | ||||
| 	return 0; | ||||
| } | ||||
| #endif /* HAVE_GETMNTINFO */ | ||||
| #endif /* HAVE_MNTENT_H */ | ||||
|  | ||||
| /* | ||||
|  * Check to see if we're dealing with the swap device. | ||||
|  */ | ||||
| static int is_swap_device(const char *file) | ||||
| { | ||||
| 	FILE		*f; | ||||
| 	char		buf[1024], *cp; | ||||
| 	dev_t		file_dev; | ||||
| 	struct stat	st_buf; | ||||
| 	int		ret = 0; | ||||
|  | ||||
| 	file_dev = 0; | ||||
| #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ | ||||
| 	if ((stat(file, &st_buf) == 0) && | ||||
| 	    S_ISBLK(st_buf.st_mode)) | ||||
| 		file_dev = st_buf.st_rdev; | ||||
| #endif  /* __GNU__ */ | ||||
|  | ||||
| 	if (!(f = fopen_for_read("/proc/swaps"))) | ||||
| 		return 0; | ||||
| 	/* Skip the first line */ | ||||
| 	fgets(buf, sizeof(buf), f); | ||||
| 	while (!feof(f)) { | ||||
| 		if (!fgets(buf, sizeof(buf), f)) | ||||
| 			break; | ||||
| 		if ((cp = strchr(buf, ' ')) != NULL) | ||||
| 			*cp = 0; | ||||
| 		if ((cp = strchr(buf, '\t')) != NULL) | ||||
| 			*cp = 0; | ||||
| 		if (strcmp(buf, file) == 0) { | ||||
| 			ret++; | ||||
| 			break; | ||||
| 		} | ||||
| #ifndef __GNU__ | ||||
| 		if (file_dev && (stat(buf, &st_buf) == 0) && | ||||
| 		    S_ISBLK(st_buf.st_mode) && | ||||
| 		    file_dev == st_buf.st_rdev) { | ||||
| 			ret++; | ||||
| 			break; | ||||
| 		} | ||||
| #endif  /* __GNU__ */ | ||||
| 	} | ||||
| 	fclose(f); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * ext2fs_check_mount_point() returns 1 if the device is mounted, 0 | ||||
|  * otherwise.  If mtpt is non-NULL, the directory where the device is | ||||
|  * mounted is copied to where mtpt is pointing, up to mtlen | ||||
|  * characters. | ||||
|  */ | ||||
| #ifdef __TURBOC__ | ||||
| # pragma argsused | ||||
| #endif | ||||
| errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, | ||||
| 				  char *mtpt, int mtlen) | ||||
| { | ||||
| 	if (is_swap_device(device)) { | ||||
| 		*mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP; | ||||
| 		strncpy(mtpt, "<swap>", mtlen); | ||||
| 		return 0; | ||||
| 	} | ||||
| #ifdef HAVE_MNTENT_H | ||||
| 	return check_mntent(device, mount_flags, mtpt, mtlen); | ||||
| #else | ||||
| #ifdef HAVE_GETMNTINFO | ||||
| 	return check_getmntinfo(device, mount_flags, mtpt, mtlen); | ||||
| #else | ||||
| #ifdef __GNUC__ | ||||
|  #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" | ||||
| #endif | ||||
| 	*mount_flags = 0; | ||||
| 	return 0; | ||||
| #endif /* HAVE_GETMNTINFO */ | ||||
| #endif /* HAVE_MNTENT_H */ | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED, | ||||
|  * EXT2_MF_READONLY, and EXT2_MF_ROOT | ||||
|  * | ||||
|  */ | ||||
| errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags) | ||||
| { | ||||
| 	return ext2fs_check_mount_point(file, mount_flags, NULL, 0); | ||||
| } | ||||
|  | ||||
| #ifdef DEBUG | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	int	retval, mount_flags; | ||||
| 	char	mntpt[80]; | ||||
|  | ||||
| 	if (argc < 2) { | ||||
| 		fprintf(stderr, "Usage: %s device\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	mntpt[0] = 0; | ||||
| 	retval = ext2fs_check_mount_point(argv[1], &mount_flags, | ||||
| 					  mntpt, sizeof(mntpt)); | ||||
| 	if (retval) { | ||||
| 		com_err(argv[0], retval, | ||||
| 			"while calling ext2fs_check_if_mounted"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	printf("Device %s reports flags %02x\n", argv[1], mount_flags); | ||||
| 	if (mount_flags & EXT2_MF_BUSY) | ||||
| 		printf("\t%s is apparently in use.\n", argv[1]); | ||||
| 	if (mount_flags & EXT2_MF_MOUNTED) | ||||
| 		printf("\t%s is mounted.\n", argv[1]); | ||||
| 	if (mount_flags & EXT2_MF_SWAP) | ||||
| 		printf("\t%s is a swap device.\n", argv[1]); | ||||
| 	if (mount_flags & EXT2_MF_READONLY) | ||||
| 		printf("\t%s is read-only.\n", argv[1]); | ||||
| 	if (mount_flags & EXT2_MF_ISROOT) | ||||
| 		printf("\t%s is the root filesystem.\n", argv[1]); | ||||
| 	if (mntpt[0]) | ||||
| 		printf("\t%s is mounted on %s.\n", argv[1], mntpt); | ||||
| 	exit(0); | ||||
| } | ||||
| #endif /* DEBUG */ | ||||
| @@ -1,63 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * jfs_dat.h --- stripped down header file which only contains the JFS | ||||
|  *	on-disk data structures | ||||
|  */ | ||||
|  | ||||
| #define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ | ||||
|  | ||||
| /* | ||||
|  * On-disk structures | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Descriptor block types: | ||||
|  */ | ||||
|  | ||||
| #define JFS_DESCRIPTOR_BLOCK	1 | ||||
| #define JFS_COMMIT_BLOCK	2 | ||||
| #define JFS_SUPERBLOCK		3 | ||||
|  | ||||
| /* | ||||
|  * Standard header for all descriptor blocks: | ||||
|  */ | ||||
| typedef struct journal_header_s | ||||
| { | ||||
| 	__u32		h_magic; | ||||
| 	__u32		h_blocktype; | ||||
| 	__u32		h_sequence; | ||||
| } journal_header_t; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * The block tag: used to describe a single buffer in the journal | ||||
|  */ | ||||
| typedef struct journal_block_tag_s | ||||
| { | ||||
| 	__u32		t_blocknr;	/* The on-disk block number */ | ||||
| 	__u32		t_flags;	/* See below */ | ||||
| } journal_block_tag_t; | ||||
|  | ||||
| /* Definitions for the journal tag flags word: */ | ||||
| #define JFS_FLAG_ESCAPE		1	/* on-disk block is escaped */ | ||||
| #define JFS_FLAG_SAME_UUID	2	/* block has same uuid as previous */ | ||||
| #define JFS_FLAG_DELETED	4	/* block deleted by this transaction */ | ||||
| #define JFS_FLAG_LAST_TAG	8	/* last tag in this descriptor block */ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * The journal superblock | ||||
|  */ | ||||
| typedef struct journal_superblock_s | ||||
| { | ||||
| 	journal_header_t s_header; | ||||
|  | ||||
| 	/* Static information describing the journal */ | ||||
| 	__u32		s_blocksize;	/* journal device blocksize */ | ||||
| 	__u32		s_maxlen;	/* total blocks in journal file */ | ||||
| 	__u32		s_first;	/* first block of log information */ | ||||
|  | ||||
| 	/* Dynamic information describing the current state of the log */ | ||||
| 	__u32		s_sequence;	/* first commit ID expected in log */ | ||||
| 	__u32		s_start;	/* blocknr of start of log */ | ||||
| } journal_superblock_t; | ||||
| @@ -1,235 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * linux/include/linux/jbd.h | ||||
|  * | ||||
|  * Written by Stephen C. Tweedie <sct@redhat.com> | ||||
|  * | ||||
|  * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved | ||||
|  * | ||||
|  * This file is part of the Linux kernel and is made available under | ||||
|  * the terms of the GNU General Public License, version 2, or at your | ||||
|  * option, any later version, incorporated herein by reference. | ||||
|  * | ||||
|  * Definitions for transaction data structures for the buffer cache | ||||
|  * filesystem journaling support. | ||||
|  */ | ||||
| #ifndef LINUX_JBD_H | ||||
| #define LINUX_JBD_H 1 | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <linux/types.h> | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| /* | ||||
|  * Standard header for all descriptor blocks: | ||||
|  */ | ||||
|  | ||||
| typedef struct journal_header_s | ||||
| { | ||||
| 	__u32		h_magic; | ||||
| 	__u32		h_blocktype; | ||||
| 	__u32		h_sequence; | ||||
| } journal_header_t; | ||||
|  | ||||
| /* | ||||
|  * This is the global e2fsck structure. | ||||
|  */ | ||||
| typedef struct e2fsck_struct *e2fsck_t; | ||||
|  | ||||
|  | ||||
| struct inode { | ||||
| 	e2fsck_t        i_ctx; | ||||
| 	ext2_ino_t      i_ino; | ||||
| 	struct ext2_inode i_ext2; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * The journal superblock.  All fields are in big-endian byte order. | ||||
|  */ | ||||
| typedef struct journal_superblock_s | ||||
| { | ||||
| /* 0x0000 */ | ||||
| 	journal_header_t s_header; | ||||
|  | ||||
| /* 0x000C */ | ||||
| 	/* Static information describing the journal */ | ||||
| 	__u32	s_blocksize;		/* journal device blocksize */ | ||||
| 	__u32	s_maxlen;		/* total blocks in journal file */ | ||||
| 	__u32	s_first;		/* first block of log information */ | ||||
|  | ||||
| /* 0x0018 */ | ||||
| 	/* Dynamic information describing the current state of the log */ | ||||
| 	__u32	s_sequence;		/* first commit ID expected in log */ | ||||
| 	__u32	s_start;		/* blocknr of start of log */ | ||||
|  | ||||
| /* 0x0020 */ | ||||
| 	/* Error value, as set by journal_abort(). */ | ||||
| 	__s32	s_errno; | ||||
|  | ||||
| /* 0x0024 */ | ||||
| 	/* Remaining fields are only valid in a version-2 superblock */ | ||||
| 	__u32	s_feature_compat;	/* compatible feature set */ | ||||
| 	__u32	s_feature_incompat;	/* incompatible feature set */ | ||||
| 	__u32	s_feature_ro_compat;	/* readonly-compatible feature set */ | ||||
| /* 0x0030 */ | ||||
| 	__u8	s_uuid[16];		/* 128-bit uuid for journal */ | ||||
|  | ||||
| /* 0x0040 */ | ||||
| 	__u32	s_nr_users;		/* Nr of filesystems sharing log */ | ||||
|  | ||||
| 	__u32	s_dynsuper;		/* Blocknr of dynamic superblock copy*/ | ||||
|  | ||||
| /* 0x0048 */ | ||||
| 	__u32	s_max_transaction;	/* Limit of journal blocks per trans.*/ | ||||
| 	__u32	s_max_trans_data;	/* Limit of data blocks per trans. */ | ||||
|  | ||||
| /* 0x0050 */ | ||||
| 	__u32	s_padding[44]; | ||||
|  | ||||
| /* 0x0100 */ | ||||
| 	__u8	s_users[16*48];		/* ids of all fs'es sharing the log */ | ||||
| /* 0x0400 */ | ||||
| } journal_superblock_t; | ||||
|  | ||||
|  | ||||
| extern int journal_blocks_per_page(struct inode *inode); | ||||
| extern int jbd_blocks_per_page(struct inode *inode); | ||||
|  | ||||
| #define JFS_MIN_JOURNAL_BLOCKS 1024 | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Internal structures used by the logging mechanism: | ||||
|  */ | ||||
|  | ||||
| #define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ | ||||
|  | ||||
| /* | ||||
|  * Descriptor block types: | ||||
|  */ | ||||
|  | ||||
| #define JFS_DESCRIPTOR_BLOCK	1 | ||||
| #define JFS_COMMIT_BLOCK	2 | ||||
| #define JFS_SUPERBLOCK_V1	3 | ||||
| #define JFS_SUPERBLOCK_V2	4 | ||||
| #define JFS_REVOKE_BLOCK	5 | ||||
|  | ||||
| /* | ||||
|  * The block tag: used to describe a single buffer in the journal | ||||
|  */ | ||||
| typedef struct journal_block_tag_s | ||||
| { | ||||
| 	__u32		t_blocknr;	/* The on-disk block number */ | ||||
| 	__u32		t_flags;	/* See below */ | ||||
| } journal_block_tag_t; | ||||
|  | ||||
| /* | ||||
|  * The revoke descriptor: used on disk to describe a series of blocks to | ||||
|  * be revoked from the log | ||||
|  */ | ||||
| typedef struct journal_revoke_header_s | ||||
| { | ||||
| 	journal_header_t r_header; | ||||
| 	int		 r_count;	/* Count of bytes used in the block */ | ||||
| } journal_revoke_header_t; | ||||
|  | ||||
|  | ||||
| /* Definitions for the journal tag flags word: */ | ||||
| #define JFS_FLAG_ESCAPE		1	/* on-disk block is escaped */ | ||||
| #define JFS_FLAG_SAME_UUID	2	/* block has same uuid as previous */ | ||||
| #define JFS_FLAG_DELETED	4	/* block deleted by this transaction */ | ||||
| #define JFS_FLAG_LAST_TAG	8	/* last tag in this descriptor block */ | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #define JFS_HAS_COMPAT_FEATURE(j,mask)					\ | ||||
| 	((j)->j_format_version >= 2 &&					\ | ||||
| 	 ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask)))) | ||||
| #define JFS_HAS_RO_COMPAT_FEATURE(j,mask)				\ | ||||
| 	((j)->j_format_version >= 2 &&					\ | ||||
| 	 ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask)))) | ||||
| #define JFS_HAS_INCOMPAT_FEATURE(j,mask)				\ | ||||
| 	((j)->j_format_version >= 2 &&					\ | ||||
| 	 ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) | ||||
|  | ||||
| #define JFS_FEATURE_INCOMPAT_REVOKE	0x00000001 | ||||
|  | ||||
| /* Features known to this kernel version: */ | ||||
| #define JFS_KNOWN_COMPAT_FEATURES	0 | ||||
| #define JFS_KNOWN_ROCOMPAT_FEATURES	0 | ||||
| #define JFS_KNOWN_INCOMPAT_FEATURES	JFS_FEATURE_INCOMPAT_REVOKE | ||||
|  | ||||
| /* Comparison functions for transaction IDs: perform comparisons using | ||||
|  * modulo arithmetic so that they work over sequence number wraps. */ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Definitions which augment the buffer_head layer | ||||
|  */ | ||||
|  | ||||
| /* journaling buffer types */ | ||||
| #define BJ_None		0	/* Not journaled */ | ||||
| #define BJ_SyncData	1	/* Normal data: flush before commit */ | ||||
| #define BJ_AsyncData	2	/* writepage data: wait on it before commit */ | ||||
| #define BJ_Metadata	3	/* Normal journaled metadata */ | ||||
| #define BJ_Forget	4	/* Buffer superceded by this transaction */ | ||||
| #define BJ_IO		5	/* Buffer is for temporary IO use */ | ||||
| #define BJ_Shadow	6	/* Buffer contents being shadowed to the log */ | ||||
| #define BJ_LogCtl	7	/* Buffer contains log descriptors */ | ||||
| #define BJ_Reserved	8	/* Buffer is reserved for access by journal */ | ||||
| #define BJ_Types	9 | ||||
|  | ||||
|  | ||||
| struct kdev_s { | ||||
| 	e2fsck_t        k_ctx; | ||||
| 	int             k_dev; | ||||
| }; | ||||
|  | ||||
| typedef struct kdev_s *kdev_t; | ||||
| typedef unsigned int tid_t; | ||||
|  | ||||
| struct journal_s | ||||
| { | ||||
| 	unsigned long		j_flags; | ||||
| 	int			j_errno; | ||||
| 	struct buffer_head *	j_sb_buffer; | ||||
| 	struct journal_superblock_s *j_superblock; | ||||
| 	int			j_format_version; | ||||
| 	unsigned long		j_head; | ||||
| 	unsigned long		j_tail; | ||||
| 	unsigned long		j_free; | ||||
| 	unsigned long		j_first, j_last; | ||||
| 	kdev_t			j_dev; | ||||
| 	kdev_t			j_fs_dev; | ||||
| 	int			j_blocksize; | ||||
| 	unsigned int		j_blk_offset; | ||||
| 	unsigned int		j_maxlen; | ||||
| 	struct inode *		j_inode; | ||||
| 	tid_t			j_tail_sequence; | ||||
| 	tid_t			j_transaction_sequence; | ||||
| 	__u8			j_uuid[16]; | ||||
| 	struct jbd_revoke_table_s *j_revoke; | ||||
| }; | ||||
|  | ||||
| typedef struct journal_s journal_t; | ||||
|  | ||||
| extern int	   journal_recover    (journal_t *journal); | ||||
| extern int	   journal_skip_recovery (journal_t *); | ||||
|  | ||||
| /* Primary revoke support */ | ||||
| extern int	   journal_init_revoke(journal_t *, int); | ||||
| extern void	   journal_destroy_revoke_caches(void); | ||||
| extern int	   journal_init_revoke_caches(void); | ||||
|  | ||||
| /* Recovery revoke support */ | ||||
| extern int	   journal_set_revoke(journal_t *, unsigned long, tid_t); | ||||
| extern int	   journal_test_revoke(journal_t *, unsigned long, tid_t); | ||||
| extern void	   journal_clear_revoke(journal_t *); | ||||
| extern void	   journal_brelse_array(struct buffer_head *b[], int n); | ||||
|  | ||||
| extern void	   journal_destroy_revoke(journal_t *); | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -1,113 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| #ifndef LINUX_LIST_H | ||||
| #define LINUX_LIST_H 1 | ||||
|  | ||||
| /* | ||||
|  * Simple doubly linked list implementation. | ||||
|  * | ||||
|  * Some of the internal functions ("__xxx") are useful when | ||||
|  * manipulating whole lists rather than single entries, as | ||||
|  * sometimes we already know the next/prev entries and we can | ||||
|  * generate better code by using them directly rather than | ||||
|  * using the generic single-entry routines. | ||||
|  */ | ||||
|  | ||||
| struct list_head { | ||||
| 	struct list_head *next, *prev; | ||||
| }; | ||||
|  | ||||
| #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||||
|  | ||||
| #define LIST_HEAD(name) \ | ||||
| 	struct list_head name = { &name, &name } | ||||
|  | ||||
| #define INIT_LIST_HEAD(ptr) do { \ | ||||
| 	(ptr)->next = (ptr); (ptr)->prev = (ptr); \ | ||||
| } while (0) | ||||
|  | ||||
| #if (!defined(__GNUC__) && !defined(__WATCOMC__)) | ||||
| #define __inline__ | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Insert a new entry between two known consecutive entries. | ||||
|  * | ||||
|  * This is only for internal list manipulation where we know | ||||
|  * the prev/next entries already! | ||||
|  */ | ||||
| static __inline__ void __list_add(struct list_head * new, | ||||
| 	struct list_head * prev, | ||||
| 	struct list_head * next) | ||||
| { | ||||
| 	next->prev = new; | ||||
| 	new->next = next; | ||||
| 	new->prev = prev; | ||||
| 	prev->next = new; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert a new entry after the specified head.. | ||||
|  */ | ||||
| static __inline__ void list_add(struct list_head *new, struct list_head *head) | ||||
| { | ||||
| 	__list_add(new, head, head->next); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Insert a new entry at the tail | ||||
|  */ | ||||
| static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) | ||||
| { | ||||
| 	__list_add(new, head->prev, head); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Delete a list entry by making the prev/next entries | ||||
|  * point to each other. | ||||
|  * | ||||
|  * This is only for internal list manipulation where we know | ||||
|  * the prev/next entries already! | ||||
|  */ | ||||
| static __inline__ void __list_del(struct list_head * prev, | ||||
| 				  struct list_head * next) | ||||
| { | ||||
| 	next->prev = prev; | ||||
| 	prev->next = next; | ||||
| } | ||||
|  | ||||
| static __inline__ void list_del(struct list_head *entry) | ||||
| { | ||||
| 	__list_del(entry->prev, entry->next); | ||||
| } | ||||
|  | ||||
| static __inline__ int list_empty(struct list_head *head) | ||||
| { | ||||
| 	return head->next == head; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Splice in "list" into "head" | ||||
|  */ | ||||
| static __inline__ void list_splice(struct list_head *list, struct list_head *head) | ||||
| { | ||||
| 	struct list_head *first = list->next; | ||||
|  | ||||
| 	if (first != list) { | ||||
| 		struct list_head *last = list->prev; | ||||
| 		struct list_head *at = head->next; | ||||
|  | ||||
| 		first->prev = head; | ||||
| 		head->next = first; | ||||
|  | ||||
| 		last->next = at; | ||||
| 		at->prev = last; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #define list_entry(ptr, type, member) \ | ||||
| 	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) | ||||
|  | ||||
| #define list_for_each(pos, head) \ | ||||
| 	for (pos = (head)->next; pos != (head); pos = pos->next) | ||||
|  | ||||
| #endif | ||||
| @@ -1,135 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * link.c --- create links in a ext2fs directory | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct link_struct  { | ||||
| 	const char	*name; | ||||
| 	int		namelen; | ||||
| 	ext2_ino_t	inode; | ||||
| 	int		flags; | ||||
| 	int		done; | ||||
| 	struct ext2_super_block *sb; | ||||
| }; | ||||
|  | ||||
| static int link_proc(struct ext2_dir_entry *dirent, | ||||
| 		     int	offset, | ||||
| 		     int	blocksize, | ||||
| 		     char	*buf, | ||||
| 		     void	*priv_data) | ||||
| { | ||||
| 	struct link_struct *ls = (struct link_struct *) priv_data; | ||||
| 	struct ext2_dir_entry *next; | ||||
| 	int rec_len, min_rec_len; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	rec_len = EXT2_DIR_REC_LEN(ls->namelen); | ||||
|  | ||||
| 	/* | ||||
| 	 * See if the following directory entry (if any) is unused; | ||||
| 	 * if so, absorb it into this one. | ||||
| 	 */ | ||||
| 	next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len); | ||||
| 	if ((offset + dirent->rec_len < blocksize - 8) && | ||||
| 	    (next->inode == 0) && | ||||
| 	    (offset + dirent->rec_len + next->rec_len <= blocksize)) { | ||||
| 		dirent->rec_len += next->rec_len; | ||||
| 		ret = DIRENT_CHANGED; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If the directory entry is used, see if we can split the | ||||
| 	 * directory entry to make room for the new name.  If so, | ||||
| 	 * truncate it and return. | ||||
| 	 */ | ||||
| 	if (dirent->inode) { | ||||
| 		min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF); | ||||
| 		if (dirent->rec_len < (min_rec_len + rec_len)) | ||||
| 			return ret; | ||||
| 		rec_len = dirent->rec_len - min_rec_len; | ||||
| 		dirent->rec_len = min_rec_len; | ||||
| 		next = (struct ext2_dir_entry *) (buf + offset + | ||||
| 						  dirent->rec_len); | ||||
| 		next->inode = 0; | ||||
| 		next->name_len = 0; | ||||
| 		next->rec_len = rec_len; | ||||
| 		return DIRENT_CHANGED; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If we get this far, then the directory entry is not used. | ||||
| 	 * See if we can fit the request entry in.  If so, do it. | ||||
| 	 */ | ||||
| 	if (dirent->rec_len < rec_len) | ||||
| 		return ret; | ||||
| 	dirent->inode = ls->inode; | ||||
| 	dirent->name_len = ls->namelen; | ||||
| 	strncpy(dirent->name, ls->name, ls->namelen); | ||||
| 	if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) | ||||
| 		dirent->name_len |= (ls->flags & 0x7) << 8; | ||||
|  | ||||
| 	ls->done++; | ||||
| 	return DIRENT_ABORT|DIRENT_CHANGED; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Note: the low 3 bits of the flags field are used as the directory | ||||
|  * entry filetype. | ||||
|  */ | ||||
| #ifdef __TURBOC__ | ||||
| # pragma argsused | ||||
| #endif | ||||
| errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||||
| 		      ext2_ino_t ino, int flags) | ||||
| { | ||||
| 	errcode_t		retval; | ||||
| 	struct link_struct	ls; | ||||
| 	struct ext2_inode	inode; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	if (!(fs->flags & EXT2_FLAG_RW)) | ||||
| 		return EXT2_ET_RO_FILSYS; | ||||
|  | ||||
| 	ls.name = name; | ||||
| 	ls.namelen = name ? strlen(name) : 0; | ||||
| 	ls.inode = ino; | ||||
| 	ls.flags = flags; | ||||
| 	ls.done = 0; | ||||
| 	ls.sb = fs->super; | ||||
|  | ||||
| 	retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, | ||||
| 				    0, link_proc, &ls); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	if (!ls.done) | ||||
| 		return EXT2_ET_DIR_NO_SPACE; | ||||
|  | ||||
| 	if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0) | ||||
| 		return retval; | ||||
|  | ||||
| 	if (inode.i_flags & EXT2_INDEX_FL) { | ||||
| 		inode.i_flags &= ~EXT2_INDEX_FL; | ||||
| 		if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,68 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * lookup.c --- ext2fs directory lookup operations | ||||
|  * | ||||
|  * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| struct lookup_struct  { | ||||
| 	const char	*name; | ||||
| 	int		len; | ||||
| 	ext2_ino_t	*inode; | ||||
| 	int		found; | ||||
| }; | ||||
|  | ||||
| #ifdef __TURBOC__ | ||||
| # pragma argsused | ||||
| #endif | ||||
| static int lookup_proc(struct ext2_dir_entry *dirent, | ||||
| 		       int	offset EXT2FS_ATTR((unused)), | ||||
| 		       int	blocksize EXT2FS_ATTR((unused)), | ||||
| 		       char	*buf EXT2FS_ATTR((unused)), | ||||
| 		       void	*priv_data) | ||||
| { | ||||
| 	struct lookup_struct *ls = (struct lookup_struct *) priv_data; | ||||
|  | ||||
| 	if (ls->len != (dirent->name_len & 0xFF)) | ||||
| 		return 0; | ||||
| 	if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF))) | ||||
| 		return 0; | ||||
| 	*ls->inode = dirent->inode; | ||||
| 	ls->found++; | ||||
| 	return DIRENT_ABORT; | ||||
| } | ||||
|  | ||||
|  | ||||
| errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||||
| 			int namelen, char *buf, ext2_ino_t *inode) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	struct lookup_struct ls; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	ls.name = name; | ||||
| 	ls.len = namelen; | ||||
| 	ls.inode = inode; | ||||
| 	ls.found = 0; | ||||
|  | ||||
| 	retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND; | ||||
| } | ||||
| @@ -1,139 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * mkdir.c --- make a directory in the filesystem | ||||
|  * | ||||
|  * Copyright (C) 1994, 1995 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "ext2fs.h" | ||||
|  | ||||
| #ifndef EXT2_FT_DIR | ||||
| #define EXT2_FT_DIR		2 | ||||
| #endif | ||||
|  | ||||
| errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, | ||||
| 		       const char *name) | ||||
| { | ||||
| 	errcode_t		retval; | ||||
| 	struct ext2_inode	parent_inode, inode; | ||||
| 	ext2_ino_t		ino = inum; | ||||
| 	ext2_ino_t		scratch_ino; | ||||
| 	blk_t			blk; | ||||
| 	char			*block = NULL; | ||||
|  | ||||
| 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate an inode, if necessary | ||||
| 	 */ | ||||
| 	if (!ino) { | ||||
| 		retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, | ||||
| 					  0, &ino); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate a data block for the directory | ||||
| 	 */ | ||||
| 	retval = ext2fs_new_block(fs, 0, 0, &blk); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	/* | ||||
| 	 * Create a scratch template for the directory | ||||
| 	 */ | ||||
| 	retval = ext2fs_new_dir_block(fs, ino, parent, &block); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	/* | ||||
| 	 * Get the parent's inode, if necessary | ||||
| 	 */ | ||||
| 	if (parent != ino) { | ||||
| 		retval = ext2fs_read_inode(fs, parent, &parent_inode); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 	} else | ||||
| 		memset(&parent_inode, 0, sizeof(parent_inode)); | ||||
|  | ||||
| 	/* | ||||
| 	 * Create the inode structure.... | ||||
| 	 */ | ||||
| 	memset(&inode, 0, sizeof(struct ext2_inode)); | ||||
| 	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); | ||||
| 	inode.i_uid = inode.i_gid = 0; | ||||
| 	inode.i_blocks = fs->blocksize / 512; | ||||
| 	inode.i_block[0] = blk; | ||||
| 	inode.i_links_count = 2; | ||||
| 	inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL); | ||||
| 	inode.i_size = fs->blocksize; | ||||
|  | ||||
| 	/* | ||||
| 	 * Write out the inode and inode data block | ||||
| 	 */ | ||||
| 	retval = ext2fs_write_dir_block(fs, blk, block); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
| 	retval = ext2fs_write_new_inode(fs, ino, &inode); | ||||
| 	if (retval) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	/* | ||||
| 	 * Link the directory into the filesystem hierarchy | ||||
| 	 */ | ||||
| 	if (name) { | ||||
| 		retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, | ||||
| 				       &scratch_ino); | ||||
| 		if (!retval) { | ||||
| 			retval = EXT2_ET_DIR_EXISTS; | ||||
| 			name = 0; | ||||
| 			goto cleanup; | ||||
| 		} | ||||
| 		if (retval != EXT2_ET_FILE_NOT_FOUND) | ||||
| 			goto cleanup; | ||||
| 		retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Update parent inode's counts | ||||
| 	 */ | ||||
| 	if (parent != ino) { | ||||
| 		parent_inode.i_links_count++; | ||||
| 		retval = ext2fs_write_inode(fs, parent, &parent_inode); | ||||
| 		if (retval) | ||||
| 			goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Update accounting.... | ||||
| 	 */ | ||||
| 	ext2fs_block_alloc_stats(fs, blk, +1); | ||||
| 	ext2fs_inode_alloc_stats2(fs, ino, +1, 1); | ||||
|  | ||||
| cleanup: | ||||
| 	ext2fs_free_mem(&block); | ||||
| 	return retval; | ||||
| } | ||||
| @@ -1,426 +0,0 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * mkjournal.c --- make a journal for a filesystem | ||||
|  * | ||||
|  * Copyright (C) 2000 Theodore Ts'o. | ||||
|  * | ||||
|  * %Begin-Header% | ||||
|  * This file may be redistributed under the terms of the GNU Public | ||||
|  * License. | ||||
|  * %End-Header% | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #if HAVE_ERRNO_H | ||||
| #include <errno.h> | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <time.h> | ||||
| #if HAVE_SYS_STAT_H | ||||
| #include <sys/stat.h> | ||||
| #endif | ||||
| #if HAVE_SYS_TYPES_H | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
| #if HAVE_SYS_IOCTL_H | ||||
| #include <sys/ioctl.h> | ||||
| #endif | ||||
| #if HAVE_NETINET_IN_H | ||||
| #include <netinet/in.h> | ||||
| #endif | ||||
|  | ||||
| #include "ext2_fs.h" | ||||
| #include "../e2p/e2p.h" | ||||
| #include "../e2fsck.h" | ||||
| #include "ext2fs.h" | ||||
| #include "kernel-jbd.h" | ||||
|  | ||||
| /* | ||||
|  * This function automatically sets up the journal superblock and | ||||
|  * returns it as an allocated block. | ||||
|  */ | ||||
| errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, | ||||
| 					   __u32 size, int flags, | ||||
| 					   char  **ret_jsb) | ||||
| { | ||||
| 	errcode_t		retval; | ||||
| 	journal_superblock_t	*jsb; | ||||
|  | ||||
| 	if (size < 1024) | ||||
| 		return EXT2_ET_JOURNAL_TOO_SMALL; | ||||
|  | ||||
| 	if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) | ||||
| 		return retval; | ||||
|  | ||||
| 	memset (jsb, 0, fs->blocksize); | ||||
|  | ||||
| 	jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); | ||||
| 	if (flags & EXT2_MKJOURNAL_V1_SUPER) | ||||
| 		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); | ||||
| 	else | ||||
| 		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); | ||||
| 	jsb->s_blocksize = htonl(fs->blocksize); | ||||
| 	jsb->s_maxlen = htonl(size); | ||||
| 	jsb->s_nr_users = htonl(1); | ||||
| 	jsb->s_first = htonl(1); | ||||
| 	jsb->s_sequence = htonl(1); | ||||
| 	memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid)); | ||||
| 	/* | ||||
| 	 * If we're creating an external journal device, we need to | ||||
| 	 * adjust these fields. | ||||
| 	 */ | ||||
| 	if (fs->super->s_feature_incompat & | ||||
| 	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { | ||||
| 		jsb->s_nr_users = 0; | ||||
| 		if (fs->blocksize == 1024) | ||||
| 			jsb->s_first = htonl(3); | ||||
| 		else | ||||
| 			jsb->s_first = htonl(2); | ||||
| 	} | ||||
|  | ||||
| 	*ret_jsb = (char *) jsb; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function writes a journal using POSIX routines.  It is used | ||||
|  * for creating external journals and creating journals on live | ||||
|  * filesystems. | ||||
|  */ | ||||
| static errcode_t write_journal_file(ext2_filsys fs, char *filename, | ||||
| 				    blk_t size, int flags) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	char		*buf = NULL; | ||||
| 	int		fd, ret_size; | ||||
| 	blk_t		i; | ||||
|  | ||||
| 	if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) | ||||
| 		return retval; | ||||
|  | ||||
| 	/* Open the device or journal file */ | ||||
| 	if ((fd = open(filename, O_WRONLY)) < 0) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	/* Write the superblock out */ | ||||
| 	retval = EXT2_ET_SHORT_WRITE; | ||||
| 	ret_size = write(fd, buf, fs->blocksize); | ||||
| 	if (ret_size < 0) { | ||||
| 		retval = errno; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	if (ret_size != (int) fs->blocksize) | ||||
| 		goto errout; | ||||
| 	memset(buf, 0, fs->blocksize); | ||||
|  | ||||
| 	for (i = 1; i < size; i++) { | ||||
| 		ret_size = write(fd, buf, fs->blocksize); | ||||
| 		if (ret_size < 0) { | ||||
| 			retval = errno; | ||||
| 			goto errout; | ||||
| 		} | ||||
| 		if (ret_size != (int) fs->blocksize) | ||||
| 			goto errout; | ||||
| 	} | ||||
| 	close(fd); | ||||
|  | ||||
| 	retval = 0; | ||||
| errout: | ||||
| 	ext2fs_free_mem(&buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Helper function for creating the journal using direct I/O routines | ||||
|  */ | ||||
| struct mkjournal_struct { | ||||
| 	int		num_blocks; | ||||
| 	int		newblocks; | ||||
| 	char		*buf; | ||||
| 	errcode_t	err; | ||||
| }; | ||||
|  | ||||
| static int mkjournal_proc(ext2_filsys	fs, | ||||
| 			   blk_t	*blocknr, | ||||
| 			   e2_blkcnt_t	blockcnt, | ||||
| 			   blk_t	ref_block EXT2FS_ATTR((unused)), | ||||
| 			   int		ref_offset EXT2FS_ATTR((unused)), | ||||
| 			   void		*priv_data) | ||||
| { | ||||
| 	struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; | ||||
| 	blk_t	new_blk; | ||||
| 	static blk_t	last_blk = 0; | ||||
| 	errcode_t	retval; | ||||
|  | ||||
| 	if (*blocknr) { | ||||
| 		last_blk = *blocknr; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); | ||||
| 	if (retval) { | ||||
| 		es->err = retval; | ||||
| 		return BLOCK_ABORT; | ||||
| 	} | ||||
| 	if (blockcnt > 0) | ||||
| 		es->num_blocks--; | ||||
|  | ||||
| 	es->newblocks++; | ||||
| 	retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); | ||||
|  | ||||
| 	if (blockcnt == 0) | ||||
| 		memset(es->buf, 0, fs->blocksize); | ||||
|  | ||||
| 	if (retval) { | ||||
| 		es->err = retval; | ||||
| 		return BLOCK_ABORT; | ||||
| 	} | ||||
| 	*blocknr = new_blk; | ||||
| 	last_blk = new_blk; | ||||
| 	ext2fs_block_alloc_stats(fs, new_blk, +1); | ||||
|  | ||||
| 	if (es->num_blocks == 0) | ||||
| 		return (BLOCK_CHANGED | BLOCK_ABORT); | ||||
| 	else | ||||
| 		return BLOCK_CHANGED; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function creates a journal using direct I/O routines. | ||||
|  */ | ||||
| static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, | ||||
| 				     blk_t size, int flags) | ||||
| { | ||||
| 	char			*buf; | ||||
| 	errcode_t		retval; | ||||
| 	struct ext2_inode	inode; | ||||
| 	struct mkjournal_struct	es; | ||||
|  | ||||
| 	if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) | ||||
| 		return retval; | ||||
|  | ||||
| 	if ((retval = ext2fs_read_bitmaps(fs))) | ||||
| 		return retval; | ||||
|  | ||||
| 	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) | ||||
| 		return retval; | ||||
|  | ||||
| 	if (inode.i_blocks > 0) | ||||
| 		return EEXIST; | ||||
|  | ||||
| 	es.num_blocks = size; | ||||
| 	es.newblocks = 0; | ||||
| 	es.buf = buf; | ||||
| 	es.err = 0; | ||||
|  | ||||
| 	retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND, | ||||
| 				       0, mkjournal_proc, &es); | ||||
| 	if (es.err) { | ||||
| 		retval = es.err; | ||||
| 		goto errout; | ||||
| 	} | ||||
|  | ||||
| 	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) | ||||
| 		goto errout; | ||||
|  | ||||
| 	inode.i_size += fs->blocksize * size; | ||||
| 	inode.i_blocks += (fs->blocksize / 512) * es.newblocks; | ||||
| 	inode.i_mtime = inode.i_ctime = time(NULL); | ||||
| 	inode.i_links_count = 1; | ||||
| 	inode.i_mode = LINUX_S_IFREG | 0600; | ||||
|  | ||||
| 	if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) | ||||
| 		goto errout; | ||||
| 	retval = 0; | ||||
|  | ||||
| 	memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); | ||||
| 	fs->super->s_jnl_blocks[16] = inode.i_size; | ||||
| 	fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; | ||||
| 	ext2fs_mark_super_dirty(fs); | ||||
|  | ||||
| errout: | ||||
| 	ext2fs_free_mem(&buf); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function adds a journal device to a filesystem | ||||
|  */ | ||||
| errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) | ||||
| { | ||||
| 	struct stat	st; | ||||
| 	errcode_t	retval; | ||||
| 	char		buf[1024]; | ||||
| 	journal_superblock_t	*jsb; | ||||
| 	int		start; | ||||
| 	__u32		i, nr_users; | ||||
|  | ||||
| 	/* Make sure the device exists and is a block device */ | ||||
| 	if (stat(journal_dev->device_name, &st) < 0) | ||||
| 		return errno; | ||||
|  | ||||
| 	if (!S_ISBLK(st.st_mode)) | ||||
| 		return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */ | ||||
|  | ||||
| 	/* Get the journal superblock */ | ||||
| 	start = 1; | ||||
| 	if (journal_dev->blocksize == 1024) | ||||
| 		start++; | ||||
| 	if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf))) | ||||
| 		return retval; | ||||
|  | ||||
| 	jsb = (journal_superblock_t *) buf; | ||||
| 	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || | ||||
| 	    (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) | ||||
| 		return EXT2_ET_NO_JOURNAL_SB; | ||||
|  | ||||
| 	if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize) | ||||
| 		return EXT2_ET_UNEXPECTED_BLOCK_SIZE; | ||||
|  | ||||
| 	/* Check and see if this filesystem has already been added */ | ||||
| 	nr_users = ntohl(jsb->s_nr_users); | ||||
| 	for (i=0; i < nr_users; i++) { | ||||
| 		if (memcmp(fs->super->s_uuid, | ||||
| 			   &jsb->s_users[i*16], 16) == 0) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (i >= nr_users) { | ||||
| 		memcpy(&jsb->s_users[nr_users*16], | ||||
| 		       fs->super->s_uuid, 16); | ||||
| 		jsb->s_nr_users = htonl(nr_users+1); | ||||
| 	} | ||||
|  | ||||
| 	/* Writeback the journal superblock */ | ||||
| 	if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf))) | ||||
| 		return retval; | ||||
|  | ||||
| 	fs->super->s_journal_inum = 0; | ||||
| 	fs->super->s_journal_dev = st.st_rdev; | ||||
| 	memcpy(fs->super->s_journal_uuid, jsb->s_uuid, | ||||
| 	       sizeof(fs->super->s_journal_uuid)); | ||||
| 	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; | ||||
| 	ext2fs_mark_super_dirty(fs); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function adds a journal inode to a filesystem, using either | ||||
|  * POSIX routines if the filesystem is mounted, or using direct I/O | ||||
|  * functions if it is not. | ||||
|  */ | ||||
| errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) | ||||
| { | ||||
| 	errcode_t		retval; | ||||
| 	ext2_ino_t		journal_ino; | ||||
| 	struct stat		st; | ||||
| 	char			jfile[1024]; | ||||
| 	int			fd, mount_flags, f; | ||||
|  | ||||
| 	retval = ext2fs_check_mount_point(fs->device_name, &mount_flags, | ||||
| 					       jfile, sizeof(jfile)-10); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| 	if (mount_flags & EXT2_MF_MOUNTED) { | ||||
| 		strcat(jfile, "/.journal"); | ||||
|  | ||||
| 		/* | ||||
| 		 * If .../.journal already exists, make sure any | ||||
| 		 * immutable or append-only flags are cleared. | ||||
| 		 */ | ||||
| #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) | ||||
| 		(void) chflags (jfile, 0); | ||||
| #else | ||||
| #if HAVE_EXT2_IOCTLS | ||||
| 		fd = open(jfile, O_RDONLY); | ||||
| 		if (fd >= 0) { | ||||
| 			f = 0; | ||||
| 			ioctl(fd, EXT2_IOC_SETFLAGS, &f); | ||||
| 			close(fd); | ||||
| 		} | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| 		/* Create the journal file */ | ||||
| 		if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) | ||||
| 			return errno; | ||||
|  | ||||
| 		if ((retval = write_journal_file(fs, jfile, size, flags))) | ||||
| 			goto errout; | ||||
|  | ||||
| 		/* Get inode number of the journal file */ | ||||
| 		if (fstat(fd, &st) < 0) | ||||
| 			goto errout; | ||||
|  | ||||
| #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) | ||||
| 		retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE); | ||||
| #else | ||||
| #if HAVE_EXT2_IOCTLS | ||||
| 		f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; | ||||
| 		retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); | ||||
| #endif | ||||
| #endif | ||||
| 		if (retval) | ||||
| 			goto errout; | ||||
|  | ||||
| 		close(fd); | ||||
| 		journal_ino = st.st_ino; | ||||
| 	} else { | ||||
| 		journal_ino = EXT2_JOURNAL_INO; | ||||
| 		if ((retval = write_journal_inode(fs, journal_ino, | ||||
| 						  size, flags))) | ||||
| 			return retval; | ||||
| 	} | ||||
|  | ||||
| 	fs->super->s_journal_inum = journal_ino; | ||||
| 	fs->super->s_journal_dev = 0; | ||||
| 	memset(fs->super->s_journal_uuid, 0, | ||||
| 	       sizeof(fs->super->s_journal_uuid)); | ||||
| 	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; | ||||
|  | ||||
| 	ext2fs_mark_super_dirty(fs); | ||||
| 	return 0; | ||||
| errout: | ||||
| 	close(fd); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| #ifdef DEBUG | ||||
| main(int argc, char **argv) | ||||
| { | ||||
| 	errcode_t	retval; | ||||
| 	char		*device_name; | ||||
| 	ext2_filsys	fs; | ||||
|  | ||||
| 	if (argc < 2) { | ||||
| 		fprintf(stderr, "Usage: %s filesystem\n", argv[0]); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	device_name = argv[1]; | ||||
|  | ||||
| 	retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, | ||||
| 			      unix_io_manager, &fs); | ||||
| 	if (retval) { | ||||
| 		com_err(argv[0], retval, "while opening %s", device_name); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	retval = ext2fs_add_journal_inode(fs, 1024); | ||||
| 	if (retval) { | ||||
| 		com_err(argv[0], retval, "while adding journal to %s", | ||||
| 			device_name); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	retval = ext2fs_flush(fs); | ||||
| 	if (retval) { | ||||
| 		printf("Warning, had trouble writing out superblocks.\n"); | ||||
| 	} | ||||
| 	ext2fs_close(fs); | ||||
| 	exit(0); | ||||
| } | ||||
| #endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user