Remove old_e2fsprogs/*
No binary (build failed)
—
(log yok)
| @@ -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 <[email protected]> |
| - | # |
| - | # 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 <[email protected]> |
| - | # |
| - | # 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 <[email protected]> |
| - | * 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 |
| @@ -1,13516 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * e2fsck |
| - | * |
| - | * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. |
| - | * Copyright (C) 2006 Garrett Kajmowicz |
| - | * |
| - | * Dictionary Abstract Data Type |
| - | * Copyright (C) 1997 Kaz Kylheku <[email protected]> |
| - | * Free Software License: |
| - | * All rights are reserved by the author, with the following exceptions: |
| - | * Permission is granted to freely reproduce and distribute this software, |
| - | * possibly in exchange for a fee, provided that this copyright notice appears |
| - | * intact. Permission is also granted to adapt this software to produce |
| - | * derivative works, as long as the modified versions carry this copyright |
| - | * notice and additional notices stating that the work has been modified. |
| - | * This source code may be translated into executable form and incorporated |
| - | * into proprietary software; there is no requirement for such software to |
| - | * contain a copyright notice related to this source. |
| - | * |
| - | * linux/fs/recovery and linux/fs/revoke |
| - | * Written by Stephen C. Tweedie <[email protected]>, 1999 |
| - | * |
| - | * Copyright 1999-2000 Red Hat Software --- All Rights Reserved |
| - | * |
| - | * Journal recovery routines for the generic filesystem journaling code; |
| - | * part of the ext2fs journaling system. |
| - | * |
| - | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
| - | */ |
| - | |
| - | /* |
| - | //usage:#define e2fsck_trivial_usage |
| - | //usage: "[-panyrcdfvstDFSV] [-b superblock] [-B blocksize] " |
| - | //usage: "[-I inode_buffer_blocks] [-P process_inode_size] " |
| - | //usage: "[-l|-L bad_blocks_file] [-C fd] [-j external_journal] " |
| - | //usage: "[-E extended-options] device" |
| - | //usage:#define e2fsck_full_usage "\n\n" |
| - | //usage: "Check ext2/ext3 file system\n" |
| - | //usage: "\n -p Automatic repair (no questions)" |
| - | //usage: "\n -n Make no changes to the filesystem" |
| - | //usage: "\n -y Assume 'yes' to all questions" |
| - | //usage: "\n -c Check for bad blocks and add them to the badblock list" |
| - | //usage: "\n -f Force checking even if filesystem is marked clean" |
| - | //usage: "\n -v Verbose" |
| - | //usage: "\n -b superblock Use alternative superblock" |
| - | //usage: "\n -B blocksize Force blocksize when looking for superblock" |
| - | //usage: "\n -j journal Set location of the external journal" |
| - | //usage: "\n -l file Add to badblocks list" |
| - | //usage: "\n -L file Set badblocks list" |
| - | */ |
| - | |
| - | #include "e2fsck.h" /*Put all of our defines here to clean things up*/ |
| - | |
| - | #define _(x) x |
| - | #define N_(x) x |
| - | |
| - | /* |
| - | * Procedure declarations |
| - | */ |
| - | |
| - | static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf); |
| - | |
| - | /* pass1.c */ |
| - | static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool); |
| - | |
| - | /* pass2.c */ |
| - | static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, |
| - | ext2_ino_t ino, char *buf); |
| - | |
| - | /* pass3.c */ |
| - | static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode); |
| - | static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, |
| - | int num, int gauranteed_size); |
| - | static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix); |
| - | static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, |
| - | int adj); |
| - | |
| - | /* rehash.c */ |
| - | static void e2fsck_rehash_directories(e2fsck_t ctx); |
| - | |
| - | /* util.c */ |
| - | static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, |
| - | const char *description); |
| - | static int ask(e2fsck_t ctx, const char * string, int def); |
| - | static void e2fsck_read_bitmaps(e2fsck_t ctx); |
| - | static void preenhalt(e2fsck_t ctx); |
| - | static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino, |
| - | struct ext2_inode * inode, const char * proc); |
| - | static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino, |
| - | struct ext2_inode * inode, const char * proc); |
| - | static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, |
| - | const char *name, io_manager manager); |
| - | |
| - | /* unix.c */ |
| - | static void e2fsck_clear_progbar(e2fsck_t ctx); |
| - | static int e2fsck_simple_progress(e2fsck_t ctx, const char *label, |
| - | float percent, unsigned int dpynum); |
| - | |
| - | |
| - | /* |
| - | * problem.h --- e2fsck problem error codes |
| - | */ |
| - | |
| - | typedef __u32 problem_t; |
| - | |
| - | struct problem_context { |
| - | errcode_t errcode; |
| - | ext2_ino_t ino, ino2, dir; |
| - | struct ext2_inode *inode; |
| - | struct ext2_dir_entry *dirent; |
| - | blk_t blk, blk2; |
| - | e2_blkcnt_t blkcount; |
| - | int group; |
| - | __u64 num; |
| - | const char *str; |
| - | }; |
| - | |
| - | |
| - | /* |
| - | * Function declarations |
| - | */ |
| - | static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx); |
| - | static int end_problem_latch(e2fsck_t ctx, int mask); |
| - | static int set_latch_flags(int mask, int setflags, int clearflags); |
| - | static void clear_problem_context(struct problem_context *ctx); |
| - | |
| - | /* |
| - | * Dictionary Abstract Data Type |
| - | * Copyright (C) 1997 Kaz Kylheku <[email protected]> |
| - | * |
| - | * dict.h v 1.22.2.6 2000/11/13 01:36:44 kaz |
| - | * kazlib_1_20 |
| - | */ |
| - | |
| - | #ifndef DICT_H |
| - | #define DICT_H |
| - | |
| - | /* |
| - | * Blurb for inclusion into C++ translation units |
| - | */ |
| - | |
| - | typedef unsigned long dictcount_t; |
| - | #define DICTCOUNT_T_MAX ULONG_MAX |
| - | |
| - | /* |
| - | * The dictionary is implemented as a red-black tree |
| - | */ |
| - | |
| - | typedef enum { dnode_red, dnode_black } dnode_color_t; |
| - | |
| - | typedef struct dnode_t { |
| - | struct dnode_t *dict_left; |
| - | struct dnode_t *dict_right; |
| - | struct dnode_t *dict_parent; |
| - | dnode_color_t dict_color; |
| - | const void *dict_key; |
| - | void *dict_data; |
| - | } dnode_t; |
| - | |
| - | typedef int (*dict_comp_t)(const void *, const void *); |
| - | typedef void (*dnode_free_t)(dnode_t *); |
| - | |
| - | typedef struct dict_t { |
| - | dnode_t dict_nilnode; |
| - | dictcount_t dict_nodecount; |
| - | dictcount_t dict_maxcount; |
| - | dict_comp_t dict_compare; |
| - | dnode_free_t dict_freenode; |
| - | int dict_dupes; |
| - | } dict_t; |
| - | |
| - | typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); |
| - | |
| - | typedef struct dict_load_t { |
| - | dict_t *dict_dictptr; |
| - | dnode_t dict_nilnode; |
| - | } dict_load_t; |
| - | |
| - | #define dict_count(D) ((D)->dict_nodecount) |
| - | #define dnode_get(N) ((N)->dict_data) |
| - | #define dnode_getkey(N) ((N)->dict_key) |
| - | |
| - | #endif |
| - | |
| - | /* |
| - | * Compatibility header file for e2fsck which should be included |
| - | * instead of linux/jfs.h |
| - | * |
| - | * Copyright (C) 2000 Stephen C. Tweedie |
| - | */ |
| - | |
| - | /* |
| - | * Pull in the definition of the e2fsck context structure |
| - | */ |
| - | |
| - | struct buffer_head { |
| - | char b_data[8192]; |
| - | e2fsck_t b_ctx; |
| - | io_channel b_io; |
| - | int b_size; |
| - | blk_t b_blocknr; |
| - | int b_dirty; |
| - | int b_uptodate; |
| - | int b_err; |
| - | }; |
| - | |
| - | |
| - | #define K_DEV_FS 1 |
| - | #define K_DEV_JOURNAL 2 |
| - | |
| - | #define lock_buffer(bh) do {} while (0) |
| - | #define unlock_buffer(bh) do {} while (0) |
| - | #define buffer_req(bh) 1 |
| - | #define do_readahead(journal, start) do {} while (0) |
| - | |
| - | static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ |
| - | |
| - | typedef struct { |
| - | int object_length; |
| - | } kmem_cache_t; |
| - | |
| - | #define kmem_cache_alloc(cache,flags) malloc((cache)->object_length) |
| - | |
| - | /* |
| - | * We use the standard libext2fs portability tricks for inline |
| - | * functions. |
| - | */ |
| - | |
| - | static kmem_cache_t * do_cache_create(int len) |
| - | { |
| - | kmem_cache_t *new_cache; |
| - | |
| - | new_cache = xmalloc(sizeof(*new_cache)); |
| - | new_cache->object_length = len; |
| - | return new_cache; |
| - | } |
| - | |
| - | static void do_cache_destroy(kmem_cache_t *cache) |
| - | { |
| - | free(cache); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Dictionary Abstract Data Type |
| - | */ |
| - | |
| - | |
| - | /* |
| - | * These macros provide short convenient names for structure members, |
| - | * which are embellished with dict_ prefixes so that they are |
| - | * properly confined to the documented namespace. It's legal for a |
| - | * program which uses dict to define, for instance, a macro called ``parent''. |
| - | * Such a macro would interfere with the dnode_t struct definition. |
| - | * In general, highly portable and reusable C modules which expose their |
| - | * structures need to confine structure member names to well-defined spaces. |
| - | * The resulting identifiers aren't necessarily convenient to use, nor |
| - | * readable, in the implementation, however! |
| - | */ |
| - | |
| - | #define left dict_left |
| - | #define right dict_right |
| - | #define parent dict_parent |
| - | #define color dict_color |
| - | #define key dict_key |
| - | #define data dict_data |
| - | |
| - | #define nilnode dict_nilnode |
| - | #define maxcount dict_maxcount |
| - | #define compare dict_compare |
| - | #define dupes dict_dupes |
| - | |
| - | #define dict_root(D) ((D)->nilnode.left) |
| - | #define dict_nil(D) (&(D)->nilnode) |
| - | |
| - | static void dnode_free(dnode_t *node); |
| - | |
| - | /* |
| - | * Perform a ``left rotation'' adjustment on the tree. The given node P and |
| - | * its right child C are rearranged so that the P instead becomes the left |
| - | * child of C. The left subtree of C is inherited as the new right subtree |
| - | * for P. The ordering of the keys within the tree is thus preserved. |
| - | */ |
| - | |
| - | static void rotate_left(dnode_t *upper) |
| - | { |
| - | dnode_t *lower, *lowleft, *upparent; |
| - | |
| - | lower = upper->right; |
| - | upper->right = lowleft = lower->left; |
| - | lowleft->parent = upper; |
| - | |
| - | lower->parent = upparent = upper->parent; |
| - | |
| - | /* don't need to check for root node here because root->parent is |
| - | the sentinel nil node, and root->parent->left points back to root */ |
| - | |
| - | if (upper == upparent->left) { |
| - | upparent->left = lower; |
| - | } else { |
| - | assert (upper == upparent->right); |
| - | upparent->right = lower; |
| - | } |
| - | |
| - | lower->left = upper; |
| - | upper->parent = lower; |
| - | } |
| - | |
| - | /* |
| - | * This operation is the ``mirror'' image of rotate_left. It is |
| - | * the same procedure, but with left and right interchanged. |
| - | */ |
| - | |
| - | static void rotate_right(dnode_t *upper) |
| - | { |
| - | dnode_t *lower, *lowright, *upparent; |
| - | |
| - | lower = upper->left; |
| - | upper->left = lowright = lower->right; |
| - | lowright->parent = upper; |
| - | |
| - | lower->parent = upparent = upper->parent; |
| - | |
| - | if (upper == upparent->right) { |
| - | upparent->right = lower; |
| - | } else { |
| - | assert (upper == upparent->left); |
| - | upparent->left = lower; |
| - | } |
| - | |
| - | lower->right = upper; |
| - | upper->parent = lower; |
| - | } |
| - | |
| - | /* |
| - | * Do a postorder traversal of the tree rooted at the specified |
| - | * node and free everything under it. Used by dict_free(). |
| - | */ |
| - | |
| - | static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) |
| - | { |
| - | if (node == nil) |
| - | return; |
| - | free_nodes(dict, node->left, nil); |
| - | free_nodes(dict, node->right, nil); |
| - | dict->dict_freenode(node); |
| - | } |
| - | |
| - | /* |
| - | * Verify that the tree contains the given node. This is done by |
| - | * traversing all of the nodes and comparing their pointers to the |
| - | * given pointer. Returns 1 if the node is found, otherwise |
| - | * returns zero. It is intended for debugging purposes. |
| - | */ |
| - | |
| - | static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) |
| - | { |
| - | if (root != nil) { |
| - | return root == node |
| - | || verify_dict_has_node(nil, root->left, node) |
| - | || verify_dict_has_node(nil, root->right, node); |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Select a different set of node allocator routines. |
| - | */ |
| - | |
| - | static void dict_set_allocator(dict_t *dict, dnode_free_t fr) |
| - | { |
| - | assert(dict_count(dict) == 0); |
| - | dict->dict_freenode = fr; |
| - | } |
| - | |
| - | /* |
| - | * Free all the nodes in the dictionary by using the dictionary's |
| - | * installed free routine. The dictionary is emptied. |
| - | */ |
| - | |
| - | static void dict_free_nodes(dict_t *dict) |
| - | { |
| - | dnode_t *nil = dict_nil(dict), *root = dict_root(dict); |
| - | free_nodes(dict, root, nil); |
| - | dict->dict_nodecount = 0; |
| - | dict->nilnode.left = &dict->nilnode; |
| - | dict->nilnode.right = &dict->nilnode; |
| - | } |
| - | |
| - | /* |
| - | * Initialize a user-supplied dictionary object. |
| - | */ |
| - | |
| - | static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) |
| - | { |
| - | dict->compare = comp; |
| - | dict->dict_freenode = dnode_free; |
| - | dict->dict_nodecount = 0; |
| - | dict->maxcount = maxcount; |
| - | dict->nilnode.left = &dict->nilnode; |
| - | dict->nilnode.right = &dict->nilnode; |
| - | dict->nilnode.parent = &dict->nilnode; |
| - | dict->nilnode.color = dnode_black; |
| - | dict->dupes = 0; |
| - | return dict; |
| - | } |
| - | |
| - | /* |
| - | * Locate a node in the dictionary having the given key. |
| - | * If the node is not found, a null a pointer is returned (rather than |
| - | * a pointer that dictionary's nil sentinel node), otherwise a pointer to the |
| - | * located node is returned. |
| - | */ |
| - | |
| - | static dnode_t *dict_lookup(dict_t *dict, const void *key) |
| - | { |
| - | dnode_t *root = dict_root(dict); |
| - | dnode_t *nil = dict_nil(dict); |
| - | dnode_t *saved; |
| - | int result; |
| - | |
| - | /* simple binary search adapted for trees that contain duplicate keys */ |
| - | |
| - | while (root != nil) { |
| - | result = dict->compare(key, root->key); |
| - | if (result < 0) |
| - | root = root->left; |
| - | else if (result > 0) |
| - | root = root->right; |
| - | else { |
| - | if (!dict->dupes) { /* no duplicates, return match */ |
| - | return root; |
| - | } else { /* could be dupes, find leftmost one */ |
| - | do { |
| - | saved = root; |
| - | root = root->left; |
| - | while (root != nil && dict->compare(key, root->key)) |
| - | root = root->right; |
| - | } while (root != nil); |
| - | return saved; |
| - | } |
| - | } |
| - | } |
| - | |
| - | return NULL; |
| - | } |
| - | |
| - | /* |
| - | * Insert a node into the dictionary. The node should have been |
| - | * initialized with a data field. All other fields are ignored. |
| - | * The behavior is undefined if the user attempts to insert into |
| - | * a dictionary that is already full (for which the dict_isfull() |
| - | * function returns true). |
| - | */ |
| - | |
| - | static void dict_insert(dict_t *dict, dnode_t *node, const void *key) |
| - | { |
| - | dnode_t *where = dict_root(dict), *nil = dict_nil(dict); |
| - | dnode_t *parent = nil, *uncle, *grandpa; |
| - | int result = -1; |
| - | |
| - | node->key = key; |
| - | |
| - | /* basic binary tree insert */ |
| - | |
| - | while (where != nil) { |
| - | parent = where; |
| - | result = dict->compare(key, where->key); |
| - | /* trap attempts at duplicate key insertion unless it's explicitly allowed */ |
| - | assert(dict->dupes || result != 0); |
| - | if (result < 0) |
| - | where = where->left; |
| - | else |
| - | where = where->right; |
| - | } |
| - | |
| - | assert(where == nil); |
| - | |
| - | if (result < 0) |
| - | parent->left = node; |
| - | else |
| - | parent->right = node; |
| - | |
| - | node->parent = parent; |
| - | node->left = nil; |
| - | node->right = nil; |
| - | |
| - | dict->dict_nodecount++; |
| - | |
| - | /* red black adjustments */ |
| - | |
| - | node->color = dnode_red; |
| - | |
| - | while (parent->color == dnode_red) { |
| - | grandpa = parent->parent; |
| - | if (parent == grandpa->left) { |
| - | uncle = grandpa->right; |
| - | if (uncle->color == dnode_red) { /* red parent, red uncle */ |
| - | parent->color = dnode_black; |
| - | uncle->color = dnode_black; |
| - | grandpa->color = dnode_red; |
| - | node = grandpa; |
| - | parent = grandpa->parent; |
| - | } else { /* red parent, black uncle */ |
| - | if (node == parent->right) { |
| - | rotate_left(parent); |
| - | parent = node; |
| - | assert (grandpa == parent->parent); |
| - | /* rotation between parent and child preserves grandpa */ |
| - | } |
| - | parent->color = dnode_black; |
| - | grandpa->color = dnode_red; |
| - | rotate_right(grandpa); |
| - | break; |
| - | } |
| - | } else { /* symmetric cases: parent == parent->parent->right */ |
| - | uncle = grandpa->left; |
| - | if (uncle->color == dnode_red) { |
| - | parent->color = dnode_black; |
| - | uncle->color = dnode_black; |
| - | grandpa->color = dnode_red; |
| - | node = grandpa; |
| - | parent = grandpa->parent; |
| - | } else { |
| - | if (node == parent->left) { |
| - | rotate_right(parent); |
| - | parent = node; |
| - | assert (grandpa == parent->parent); |
| - | } |
| - | parent->color = dnode_black; |
| - | grandpa->color = dnode_red; |
| - | rotate_left(grandpa); |
| - | break; |
| - | } |
| - | } |
| - | } |
| - | |
| - | dict_root(dict)->color = dnode_black; |
| - | } |
| - | |
| - | /* |
| - | * Allocate a node using the dictionary's allocator routine, give it |
| - | * the data item. |
| - | */ |
| - | |
| - | static dnode_t *dnode_init(dnode_t *dnode, void *data) |
| - | { |
| - | dnode->data = data; |
| - | dnode->parent = NULL; |
| - | dnode->left = NULL; |
| - | dnode->right = NULL; |
| - | return dnode; |
| - | } |
| - | |
| - | static int dict_alloc_insert(dict_t *dict, const void *key, void *data) |
| - | { |
| - | dnode_t *node = xmalloc(sizeof(dnode_t)); |
| - | |
| - | dnode_init(node, data); |
| - | dict_insert(dict, node, key); |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * Return the node with the lowest (leftmost) key. If the dictionary is empty |
| - | * (that is, dict_isempty(dict) returns 1) a null pointer is returned. |
| - | */ |
| - | |
| - | static dnode_t *dict_first(dict_t *dict) |
| - | { |
| - | dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; |
| - | |
| - | if (root != nil) |
| - | while ((left = root->left) != nil) |
| - | root = left; |
| - | |
| - | return (root == nil) ? NULL : root; |
| - | } |
| - | |
| - | /* |
| - | * Return the given node's successor node---the node which has the |
| - | * next key in the left to right ordering. If the node has |
| - | * no successor, a null pointer is returned rather than a pointer to |
| - | * the nil node. |
| - | */ |
| - | |
| - | static dnode_t *dict_next(dict_t *dict, dnode_t *curr) |
| - | { |
| - | dnode_t *nil = dict_nil(dict), *parent, *left; |
| - | |
| - | if (curr->right != nil) { |
| - | curr = curr->right; |
| - | while ((left = curr->left) != nil) |
| - | curr = left; |
| - | return curr; |
| - | } |
| - | |
| - | parent = curr->parent; |
| - | |
| - | while (parent != nil && curr == parent->right) { |
| - | curr = parent; |
| - | parent = curr->parent; |
| - | } |
| - | |
| - | return (parent == nil) ? NULL : parent; |
| - | } |
| - | |
| - | |
| - | static void dnode_free(dnode_t *node) |
| - | { |
| - | free(node); |
| - | } |
| - | |
| - | |
| - | #undef left |
| - | #undef right |
| - | #undef parent |
| - | #undef color |
| - | #undef key |
| - | #undef data |
| - | |
| - | #undef nilnode |
| - | #undef maxcount |
| - | #undef compare |
| - | #undef dupes |
| - | |
| - | |
| - | /* |
| - | * dirinfo.c --- maintains the directory information table for e2fsck. |
| - | */ |
| - | |
| - | /* |
| - | * This subroutine is called during pass1 to create a directory info |
| - | * entry. During pass1, the passed-in parent is 0; it will get filled |
| - | * in during pass2. |
| - | */ |
| - | static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent) |
| - | { |
| - | struct dir_info *dir; |
| - | int i, j; |
| - | ext2_ino_t num_dirs; |
| - | errcode_t retval; |
| - | unsigned long old_size; |
| - | |
| - | if (!ctx->dir_info) { |
| - | ctx->dir_info_count = 0; |
| - | retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs); |
| - | if (retval) |
| - | num_dirs = 1024; /* Guess */ |
| - | ctx->dir_info_size = num_dirs + 10; |
| - | ctx->dir_info = (struct dir_info *) |
| - | e2fsck_allocate_memory(ctx, ctx->dir_info_size |
| - | * sizeof (struct dir_info), |
| - | "directory map"); |
| - | } |
| - | |
| - | if (ctx->dir_info_count >= ctx->dir_info_size) { |
| - | old_size = ctx->dir_info_size * sizeof(struct dir_info); |
| - | ctx->dir_info_size += 10; |
| - | retval = ext2fs_resize_mem(old_size, ctx->dir_info_size * |
| - | sizeof(struct dir_info), |
| - | &ctx->dir_info); |
| - | if (retval) { |
| - | ctx->dir_info_size -= 10; |
| - | return; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Normally, add_dir_info is called with each inode in |
| - | * sequential order; but once in a while (like when pass 3 |
| - | * needs to recreate the root directory or lost+found |
| - | * directory) it is called out of order. In those cases, we |
| - | * need to move the dir_info entries down to make room, since |
| - | * the dir_info array needs to be sorted by inode number for |
| - | * get_dir_info()'s sake. |
| - | */ |
| - | if (ctx->dir_info_count && |
| - | ctx->dir_info[ctx->dir_info_count-1].ino >= ino) { |
| - | for (i = ctx->dir_info_count-1; i > 0; i--) |
| - | if (ctx->dir_info[i-1].ino < ino) |
| - | break; |
| - | dir = &ctx->dir_info[i]; |
| - | if (dir->ino != ino) |
| - | for (j = ctx->dir_info_count++; j > i; j--) |
| - | ctx->dir_info[j] = ctx->dir_info[j-1]; |
| - | } else |
| - | dir = &ctx->dir_info[ctx->dir_info_count++]; |
| - | |
| - | dir->ino = ino; |
| - | dir->dotdot = parent; |
| - | dir->parent = parent; |
| - | } |
| - | |
| - | /* |
| - | * get_dir_info() --- given an inode number, try to find the directory |
| - | * information entry for it. |
| - | */ |
| - | static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino) |
| - | { |
| - | int low, high, mid; |
| - | |
| - | low = 0; |
| - | high = ctx->dir_info_count-1; |
| - | if (!ctx->dir_info) |
| - | return 0; |
| - | if (ino == ctx->dir_info[low].ino) |
| - | return &ctx->dir_info[low]; |
| - | if (ino == ctx->dir_info[high].ino) |
| - | return &ctx->dir_info[high]; |
| - | |
| - | while (low < high) { |
| - | mid = (low+high)/2; |
| - | if (mid == low || mid == high) |
| - | break; |
| - | if (ino == ctx->dir_info[mid].ino) |
| - | return &ctx->dir_info[mid]; |
| - | if (ino < ctx->dir_info[mid].ino) |
| - | high = mid; |
| - | else |
| - | low = mid; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Free the dir_info structure when it isn't needed any more. |
| - | */ |
| - | static void e2fsck_free_dir_info(e2fsck_t ctx) |
| - | { |
| - | ext2fs_free_mem(&ctx->dir_info); |
| - | ctx->dir_info_size = 0; |
| - | ctx->dir_info_count = 0; |
| - | } |
| - | |
| - | /* |
| - | * Return the count of number of directories in the dir_info structure |
| - | */ |
| - | static int e2fsck_get_num_dirinfo(e2fsck_t ctx) |
| - | { |
| - | return ctx->dir_info_count; |
| - | } |
| - | |
| - | /* |
| - | * A simple interator function |
| - | */ |
| - | static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control) |
| - | { |
| - | if (*control >= ctx->dir_info_count) |
| - | return 0; |
| - | |
| - | return ctx->dir_info + (*control)++; |
| - | } |
| - | |
| - | /* |
| - | * dirinfo.c --- maintains the directory information table for e2fsck. |
| - | * |
| - | */ |
| - | |
| - | #ifdef ENABLE_HTREE |
| - | |
| - | /* |
| - | * This subroutine is called during pass1 to create a directory info |
| - | * entry. During pass1, the passed-in parent is 0; it will get filled |
| - | * in during pass2. |
| - | */ |
| - | static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks) |
| - | { |
| - | struct dx_dir_info *dir; |
| - | int i, j; |
| - | errcode_t retval; |
| - | unsigned long old_size; |
| - | |
| - | if (!ctx->dx_dir_info) { |
| - | ctx->dx_dir_info_count = 0; |
| - | ctx->dx_dir_info_size = 100; /* Guess */ |
| - | ctx->dx_dir_info = (struct dx_dir_info *) |
| - | e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size |
| - | * sizeof (struct dx_dir_info), |
| - | "directory map"); |
| - | } |
| - | |
| - | if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) { |
| - | old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info); |
| - | ctx->dx_dir_info_size += 10; |
| - | retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size * |
| - | sizeof(struct dx_dir_info), |
| - | &ctx->dx_dir_info); |
| - | if (retval) { |
| - | ctx->dx_dir_info_size -= 10; |
| - | return; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Normally, add_dx_dir_info is called with each inode in |
| - | * sequential order; but once in a while (like when pass 3 |
| - | * needs to recreate the root directory or lost+found |
| - | * directory) it is called out of order. In those cases, we |
| - | * need to move the dx_dir_info entries down to make room, since |
| - | * the dx_dir_info array needs to be sorted by inode number for |
| - | * get_dx_dir_info()'s sake. |
| - | */ |
| - | if (ctx->dx_dir_info_count && |
| - | ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) { |
| - | for (i = ctx->dx_dir_info_count-1; i > 0; i--) |
| - | if (ctx->dx_dir_info[i-1].ino < ino) |
| - | break; |
| - | dir = &ctx->dx_dir_info[i]; |
| - | if (dir->ino != ino) |
| - | for (j = ctx->dx_dir_info_count++; j > i; j--) |
| - | ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1]; |
| - | } else |
| - | dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++]; |
| - | |
| - | dir->ino = ino; |
| - | dir->numblocks = num_blocks; |
| - | dir->hashversion = 0; |
| - | dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks |
| - | * sizeof (struct dx_dirblock_info), |
| - | "dx_block info array"); |
| - | } |
| - | |
| - | /* |
| - | * get_dx_dir_info() --- given an inode number, try to find the directory |
| - | * information entry for it. |
| - | */ |
| - | static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino) |
| - | { |
| - | int low, high, mid; |
| - | |
| - | low = 0; |
| - | high = ctx->dx_dir_info_count-1; |
| - | if (!ctx->dx_dir_info) |
| - | return 0; |
| - | if (ino == ctx->dx_dir_info[low].ino) |
| - | return &ctx->dx_dir_info[low]; |
| - | if (ino == ctx->dx_dir_info[high].ino) |
| - | return &ctx->dx_dir_info[high]; |
| - | |
| - | while (low < high) { |
| - | mid = (low+high)/2; |
| - | if (mid == low || mid == high) |
| - | break; |
| - | if (ino == ctx->dx_dir_info[mid].ino) |
| - | return &ctx->dx_dir_info[mid]; |
| - | if (ino < ctx->dx_dir_info[mid].ino) |
| - | high = mid; |
| - | else |
| - | low = mid; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Free the dx_dir_info structure when it isn't needed any more. |
| - | */ |
| - | static void e2fsck_free_dx_dir_info(e2fsck_t ctx) |
| - | { |
| - | int i; |
| - | struct dx_dir_info *dir; |
| - | |
| - | if (ctx->dx_dir_info) { |
| - | dir = ctx->dx_dir_info; |
| - | for (i=0; i < ctx->dx_dir_info_count; i++) { |
| - | ext2fs_free_mem(&dir->dx_block); |
| - | } |
| - | ext2fs_free_mem(&ctx->dx_dir_info); |
| - | } |
| - | ctx->dx_dir_info_size = 0; |
| - | ctx->dx_dir_info_count = 0; |
| - | } |
| - | |
| - | /* |
| - | * A simple interator function |
| - | */ |
| - | static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control) |
| - | { |
| - | if (*control >= ctx->dx_dir_info_count) |
| - | return 0; |
| - | |
| - | return ctx->dx_dir_info + (*control)++; |
| - | } |
| - | |
| - | #endif /* ENABLE_HTREE */ |
| - | /* |
| - | * e2fsck.c - a consistency checker for the new extended file system. |
| - | * |
| - | */ |
| - | |
| - | /* |
| - | * This function allocates an e2fsck context |
| - | */ |
| - | static errcode_t e2fsck_allocate_context(e2fsck_t *ret) |
| - | { |
| - | e2fsck_t context; |
| - | errcode_t retval; |
| - | |
| - | retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | memset(context, 0, sizeof(struct e2fsck_struct)); |
| - | |
| - | context->process_inode_size = 256; |
| - | context->ext_attr_ver = 2; |
| - | |
| - | *ret = context; |
| - | return 0; |
| - | } |
| - | |
| - | struct ea_refcount_el { |
| - | blk_t ea_blk; |
| - | int ea_count; |
| - | }; |
| - | |
| - | struct ea_refcount { |
| - | blk_t count; |
| - | blk_t size; |
| - | blk_t cursor; |
| - | struct ea_refcount_el *list; |
| - | }; |
| - | |
| - | static void ea_refcount_free(ext2_refcount_t refcount) |
| - | { |
| - | if (!refcount) |
| - | return; |
| - | |
| - | ext2fs_free_mem(&refcount->list); |
| - | ext2fs_free_mem(&refcount); |
| - | } |
| - | |
| - | /* |
| - | * This function resets an e2fsck context; it is called when e2fsck |
| - | * needs to be restarted. |
| - | */ |
| - | static errcode_t e2fsck_reset_context(e2fsck_t ctx) |
| - | { |
| - | ctx->flags = 0; |
| - | ctx->lost_and_found = 0; |
| - | ctx->bad_lost_and_found = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_used_map); |
| - | ctx->inode_used_map = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_dir_map); |
| - | ctx->inode_dir_map = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_reg_map); |
| - | ctx->inode_reg_map = 0; |
| - | ext2fs_free_block_bitmap(ctx->block_found_map); |
| - | ctx->block_found_map = 0; |
| - | ext2fs_free_icount(ctx->inode_link_info); |
| - | ctx->inode_link_info = 0; |
| - | if (ctx->journal_io) { |
| - | if (ctx->fs && ctx->fs->io != ctx->journal_io) |
| - | io_channel_close(ctx->journal_io); |
| - | ctx->journal_io = 0; |
| - | } |
| - | if (ctx->fs) { |
| - | ext2fs_free_dblist(ctx->fs->dblist); |
| - | ctx->fs->dblist = 0; |
| - | } |
| - | e2fsck_free_dir_info(ctx); |
| - | #ifdef ENABLE_HTREE |
| - | e2fsck_free_dx_dir_info(ctx); |
| - | #endif |
| - | ea_refcount_free(ctx->refcount); |
| - | ctx->refcount = 0; |
| - | ea_refcount_free(ctx->refcount_extra); |
| - | ctx->refcount_extra = 0; |
| - | ext2fs_free_block_bitmap(ctx->block_dup_map); |
| - | ctx->block_dup_map = 0; |
| - | ext2fs_free_block_bitmap(ctx->block_ea_map); |
| - | ctx->block_ea_map = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_bad_map); |
| - | ctx->inode_bad_map = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_imagic_map); |
| - | ctx->inode_imagic_map = 0; |
| - | ext2fs_u32_list_free(ctx->dirs_to_hash); |
| - | ctx->dirs_to_hash = 0; |
| - | |
| - | /* |
| - | * Clear the array of invalid meta-data flags |
| - | */ |
| - | ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag); |
| - | ext2fs_free_mem(&ctx->invalid_block_bitmap_flag); |
| - | ext2fs_free_mem(&ctx->invalid_inode_table_flag); |
| - | |
| - | /* Clear statistic counters */ |
| - | ctx->fs_directory_count = 0; |
| - | ctx->fs_regular_count = 0; |
| - | ctx->fs_blockdev_count = 0; |
| - | ctx->fs_chardev_count = 0; |
| - | ctx->fs_links_count = 0; |
| - | ctx->fs_symlinks_count = 0; |
| - | ctx->fs_fast_symlinks_count = 0; |
| - | ctx->fs_fifo_count = 0; |
| - | ctx->fs_total_count = 0; |
| - | ctx->fs_sockets_count = 0; |
| - | ctx->fs_ind_count = 0; |
| - | ctx->fs_dind_count = 0; |
| - | ctx->fs_tind_count = 0; |
| - | ctx->fs_fragmented = 0; |
| - | ctx->large_files = 0; |
| - | |
| - | /* Reset the superblock to the user's requested value */ |
| - | ctx->superblock = ctx->use_superblock; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static void e2fsck_free_context(e2fsck_t ctx) |
| - | { |
| - | if (!ctx) |
| - | return; |
| - | |
| - | e2fsck_reset_context(ctx); |
| - | if (ctx->blkid) |
| - | blkid_put_cache(ctx->blkid); |
| - | |
| - | ext2fs_free_mem(&ctx); |
| - | } |
| - | |
| - | /* |
| - | * ea_refcount.c |
| - | */ |
| - | |
| - | /* |
| - | * The strategy we use for keeping track of EA refcounts is as |
| - | * follows. We keep a sorted array of first EA blocks and its |
| - | * reference counts. Once the refcount has dropped to zero, it is |
| - | * removed from the array to save memory space. Once the EA block is |
| - | * checked, its bit is set in the block_ea_map bitmap. |
| - | */ |
| - | |
| - | |
| - | static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret) |
| - | { |
| - | ext2_refcount_t refcount; |
| - | errcode_t retval; |
| - | size_t bytes; |
| - | |
| - | retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount); |
| - | if (retval) |
| - | return retval; |
| - | memset(refcount, 0, sizeof(struct ea_refcount)); |
| - | |
| - | if (!size) |
| - | size = 500; |
| - | refcount->size = size; |
| - | bytes = (size_t) (size * sizeof(struct ea_refcount_el)); |
| - | #ifdef DEBUG |
| - | printf("Refcount allocated %d entries, %lu bytes.\n", |
| - | refcount->size, bytes); |
| - | #endif |
| - | retval = ext2fs_get_mem(bytes, &refcount->list); |
| - | if (retval) |
| - | goto errout; |
| - | memset(refcount->list, 0, bytes); |
| - | |
| - | refcount->count = 0; |
| - | refcount->cursor = 0; |
| - | |
| - | *ret = refcount; |
| - | return 0; |
| - | |
| - | errout: |
| - | ea_refcount_free(refcount); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * collapse_refcount() --- go through the refcount array, and get rid |
| - | * of any count == zero entries |
| - | */ |
| - | static void refcount_collapse(ext2_refcount_t refcount) |
| - | { |
| - | unsigned int i, j; |
| - | struct ea_refcount_el *list; |
| - | |
| - | list = refcount->list; |
| - | for (i = 0, j = 0; i < refcount->count; i++) { |
| - | if (list[i].ea_count) { |
| - | if (i != j) |
| - | list[j] = list[i]; |
| - | j++; |
| - | } |
| - | } |
| - | #if defined(DEBUG) || defined(TEST_PROGRAM) |
| - | printf("Refcount_collapse: size was %d, now %d\n", |
| - | refcount->count, j); |
| - | #endif |
| - | refcount->count = j; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * insert_refcount_el() --- Insert a new entry into the sorted list at a |
| - | * specified position. |
| - | */ |
| - | static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount, |
| - | blk_t blk, int pos) |
| - | { |
| - | struct ea_refcount_el *el; |
| - | errcode_t retval; |
| - | blk_t new_size = 0; |
| - | int num; |
| - | |
| - | if (refcount->count >= refcount->size) { |
| - | new_size = refcount->size + 100; |
| - | #ifdef DEBUG |
| - | printf("Reallocating refcount %d entries...\n", new_size); |
| - | #endif |
| - | retval = ext2fs_resize_mem((size_t) refcount->size * |
| - | sizeof(struct ea_refcount_el), |
| - | (size_t) new_size * |
| - | sizeof(struct ea_refcount_el), |
| - | &refcount->list); |
| - | if (retval) |
| - | return 0; |
| - | refcount->size = new_size; |
| - | } |
| - | num = (int) refcount->count - pos; |
| - | if (num < 0) |
| - | return 0; /* should never happen */ |
| - | if (num) { |
| - | memmove(&refcount->list[pos+1], &refcount->list[pos], |
| - | sizeof(struct ea_refcount_el) * num); |
| - | } |
| - | refcount->count++; |
| - | el = &refcount->list[pos]; |
| - | el->ea_count = 0; |
| - | el->ea_blk = blk; |
| - | return el; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * get_refcount_el() --- given an block number, try to find refcount |
| - | * 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 ea_refcount_el *get_refcount_el(ext2_refcount_t refcount, |
| - | blk_t blk, int create) |
| - | { |
| - | float range; |
| - | int low, high, mid; |
| - | blk_t lowval, highval; |
| - | |
| - | if (!refcount || !refcount->list) |
| - | return 0; |
| - | retry: |
| - | low = 0; |
| - | high = (int) refcount->count-1; |
| - | if (create && ((refcount->count == 0) || |
| - | (blk > refcount->list[high].ea_blk))) { |
| - | if (refcount->count >= refcount->size) |
| - | refcount_collapse(refcount); |
| - | |
| - | return insert_refcount_el(refcount, blk, |
| - | (unsigned) refcount->count); |
| - | } |
| - | if (refcount->count == 0) |
| - | return 0; |
| - | |
| - | if (refcount->cursor >= refcount->count) |
| - | refcount->cursor = 0; |
| - | if (blk == refcount->list[refcount->cursor].ea_blk) |
| - | return &refcount->list[refcount->cursor++]; |
| - | #ifdef DEBUG |
| - | printf("Non-cursor get_refcount_el: %u\n", blk); |
| - | #endif |
| - | while (low <= high) { |
| - | if (low == high) |
| - | mid = low; |
| - | else { |
| - | /* Interpolate for efficiency */ |
| - | lowval = refcount->list[low].ea_blk; |
| - | highval = refcount->list[high].ea_blk; |
| - | |
| - | if (blk < lowval) |
| - | range = 0; |
| - | else if (blk > highval) |
| - | range = 1; |
| - | else |
| - | range = ((float) (blk - lowval)) / |
| - | (highval - lowval); |
| - | mid = low + ((int) (range * (high-low))); |
| - | } |
| - | |
| - | if (blk == refcount->list[mid].ea_blk) { |
| - | refcount->cursor = mid+1; |
| - | return &refcount->list[mid]; |
| - | } |
| - | if (blk < refcount->list[mid].ea_blk) |
| - | 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) { |
| - | if (refcount->count >= refcount->size) { |
| - | refcount_collapse(refcount); |
| - | if (refcount->count < refcount->size) |
| - | goto retry; |
| - | } |
| - | return insert_refcount_el(refcount, blk, low); |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t |
| - | ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret) |
| - | { |
| - | struct ea_refcount_el *el; |
| - | |
| - | el = get_refcount_el(refcount, blk, 1); |
| - | if (!el) |
| - | return EXT2_ET_NO_MEMORY; |
| - | el->ea_count++; |
| - | |
| - | if (ret) |
| - | *ret = el->ea_count; |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t |
| - | ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret) |
| - | { |
| - | struct ea_refcount_el *el; |
| - | |
| - | el = get_refcount_el(refcount, blk, 0); |
| - | if (!el || el->ea_count == 0) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | |
| - | el->ea_count--; |
| - | |
| - | if (ret) |
| - | *ret = el->ea_count; |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t |
| - | ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count) |
| - | { |
| - | struct ea_refcount_el *el; |
| - | |
| - | /* |
| - | * Get the refcount element |
| - | */ |
| - | el = get_refcount_el(refcount, blk, count ? 1 : 0); |
| - | if (!el) |
| - | return count ? EXT2_ET_NO_MEMORY : 0; |
| - | el->ea_count = count; |
| - | return 0; |
| - | } |
| - | |
| - | static inline void ea_refcount_intr_begin(ext2_refcount_t refcount) |
| - | { |
| - | refcount->cursor = 0; |
| - | } |
| - | |
| - | |
| - | static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret) |
| - | { |
| - | struct ea_refcount_el *list; |
| - | |
| - | while (1) { |
| - | if (refcount->cursor >= refcount->count) |
| - | return 0; |
| - | list = refcount->list; |
| - | if (list[refcount->cursor].ea_count) { |
| - | if (ret) |
| - | *ret = list[refcount->cursor].ea_count; |
| - | return list[refcount->cursor++].ea_blk; |
| - | } |
| - | refcount->cursor++; |
| - | } |
| - | } |
| - | |
| - | |
| - | /* |
| - | * ehandler.c --- handle bad block errors which come up during the |
| - | * course of an e2fsck session. |
| - | */ |
| - | |
| - | |
| - | static const char *operation; |
| - | |
| - | static errcode_t |
| - | e2fsck_handle_read_error(io_channel channel, unsigned long block, int count, |
| - | void *data, size_t size FSCK_ATTR((unused)), |
| - | int actual FSCK_ATTR((unused)), errcode_t error) |
| - | { |
| - | int i; |
| - | char *p; |
| - | ext2_filsys fs = (ext2_filsys) channel->app_data; |
| - | e2fsck_t ctx; |
| - | |
| - | ctx = (e2fsck_t) fs->priv_data; |
| - | |
| - | /* |
| - | * If more than one block was read, try reading each block |
| - | * separately. We could use the actual bytes read to figure |
| - | * out where to start, but we don't bother. |
| - | */ |
| - | if (count > 1) { |
| - | p = (char *) data; |
| - | for (i=0; i < count; i++, p += channel->block_size, block++) { |
| - | error = io_channel_read_blk(channel, block, |
| - | 1, p); |
| - | if (error) |
| - | return error; |
| - | } |
| - | return 0; |
| - | } |
| - | if (operation) |
| - | printf(_("Error reading block %lu (%s) while %s. "), block, |
| - | error_message(error), operation); |
| - | else |
| - | printf(_("Error reading block %lu (%s). "), block, |
| - | error_message(error)); |
| - | preenhalt(ctx); |
| - | if (ask(ctx, _("Ignore error"), 1)) { |
| - | if (ask(ctx, _("Force rewrite"), 1)) |
| - | io_channel_write_blk(channel, block, 1, data); |
| - | return 0; |
| - | } |
| - | |
| - | return error; |
| - | } |
| - | |
| - | static errcode_t |
| - | e2fsck_handle_write_error(io_channel channel, unsigned long block, int count, |
| - | const void *data, size_t size FSCK_ATTR((unused)), |
| - | int actual FSCK_ATTR((unused)), errcode_t error) |
| - | { |
| - | int i; |
| - | const char *p; |
| - | ext2_filsys fs = (ext2_filsys) channel->app_data; |
| - | e2fsck_t ctx; |
| - | |
| - | ctx = (e2fsck_t) fs->priv_data; |
| - | |
| - | /* |
| - | * If more than one block was written, try writing each block |
| - | * separately. We could use the actual bytes read to figure |
| - | * out where to start, but we don't bother. |
| - | */ |
| - | if (count > 1) { |
| - | p = (const char *) data; |
| - | for (i=0; i < count; i++, p += channel->block_size, block++) { |
| - | error = io_channel_write_blk(channel, block, |
| - | 1, p); |
| - | if (error) |
| - | return error; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | if (operation) |
| - | printf(_("Error writing block %lu (%s) while %s. "), block, |
| - | error_message(error), operation); |
| - | else |
| - | printf(_("Error writing block %lu (%s). "), block, |
| - | error_message(error)); |
| - | preenhalt(ctx); |
| - | if (ask(ctx, _("Ignore error"), 1)) |
| - | return 0; |
| - | |
| - | return error; |
| - | } |
| - | |
| - | static const char *ehandler_operation(const char *op) |
| - | { |
| - | const char *ret = operation; |
| - | |
| - | operation = op; |
| - | return ret; |
| - | } |
| - | |
| - | static void ehandler_init(io_channel channel) |
| - | { |
| - | channel->read_error = e2fsck_handle_read_error; |
| - | channel->write_error = e2fsck_handle_write_error; |
| - | } |
| - | |
| - | /* |
| - | * journal.c --- code for handling the "ext3" journal |
| - | * |
| - | * Copyright (C) 2000 Andreas Dilger |
| - | * Copyright (C) 2000 Theodore Ts'o |
| - | * |
| - | * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie |
| - | * Copyright (C) 1999 Red Hat Software |
| - | * |
| - | * This file may be redistributed under the terms of the |
| - | * GNU General Public License version 2 or at your discretion |
| - | * any later version. |
| - | */ |
| - | |
| - | /* |
| - | * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths. |
| - | * This creates a larger static binary, and a smaller binary using |
| - | * shared libraries. It's also probably slightly less CPU-efficient, |
| - | * which is why it's not on by default. But, it's a good way of |
| - | * testing the functions in inode_io.c and fileio.c. |
| - | */ |
| - | #undef USE_INODE_IO |
| - | |
| - | /* Kernel compatibility functions for handling the journal. These allow us |
| - | * to use the recovery.c file virtually unchanged from the kernel, so we |
| - | * don't have to do much to keep kernel and user recovery in sync. |
| - | */ |
| - | static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys) |
| - | { |
| - | #ifdef USE_INODE_IO |
| - | *phys = block; |
| - | return 0; |
| - | #else |
| - | struct inode *inode = journal->j_inode; |
| - | errcode_t retval; |
| - | blk_t pblk; |
| - | |
| - | if (!inode) { |
| - | *phys = block; |
| - | return 0; |
| - | } |
| - | |
| - | retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino, |
| - | &inode->i_ext2, NULL, 0, block, &pblk); |
| - | *phys = pblk; |
| - | return retval; |
| - | #endif |
| - | } |
| - | |
| - | static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize) |
| - | { |
| - | struct buffer_head *bh; |
| - | |
| - | bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer"); |
| - | if (!bh) |
| - | return NULL; |
| - | |
| - | bh->b_ctx = kdev->k_ctx; |
| - | if (kdev->k_dev == K_DEV_FS) |
| - | bh->b_io = kdev->k_ctx->fs->io; |
| - | else |
| - | bh->b_io = kdev->k_ctx->journal_io; |
| - | bh->b_size = blocksize; |
| - | bh->b_blocknr = blocknr; |
| - | |
| - | return bh; |
| - | } |
| - | |
| - | static void sync_blockdev(kdev_t kdev) |
| - | { |
| - | io_channel io; |
| - | |
| - | if (kdev->k_dev == K_DEV_FS) |
| - | io = kdev->k_ctx->fs->io; |
| - | else |
| - | io = kdev->k_ctx->journal_io; |
| - | |
| - | io_channel_flush(io); |
| - | } |
| - | |
| - | static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[]) |
| - | { |
| - | int retval; |
| - | struct buffer_head *bh; |
| - | |
| - | for (; nr > 0; --nr) { |
| - | bh = *bhp++; |
| - | if (rw == READ && !bh->b_uptodate) { |
| - | retval = io_channel_read_blk(bh->b_io, |
| - | bh->b_blocknr, |
| - | 1, bh->b_data); |
| - | if (retval) { |
| - | bb_error_msg("while reading block %lu", |
| - | (unsigned long) bh->b_blocknr); |
| - | bh->b_err = retval; |
| - | continue; |
| - | } |
| - | bh->b_uptodate = 1; |
| - | } else if (rw == WRITE && bh->b_dirty) { |
| - | retval = io_channel_write_blk(bh->b_io, |
| - | bh->b_blocknr, |
| - | 1, bh->b_data); |
| - | if (retval) { |
| - | bb_error_msg("while writing block %lu", |
| - | (unsigned long) bh->b_blocknr); |
| - | bh->b_err = retval; |
| - | continue; |
| - | } |
| - | bh->b_dirty = 0; |
| - | bh->b_uptodate = 1; |
| - | } |
| - | } |
| - | } |
| - | |
| - | static void mark_buffer_dirty(struct buffer_head *bh) |
| - | { |
| - | bh->b_dirty = 1; |
| - | } |
| - | |
| - | static inline void mark_buffer_clean(struct buffer_head * bh) |
| - | { |
| - | bh->b_dirty = 0; |
| - | } |
| - | |
| - | static void brelse(struct buffer_head *bh) |
| - | { |
| - | if (bh->b_dirty) |
| - | ll_rw_block(WRITE, 1, &bh); |
| - | ext2fs_free_mem(&bh); |
| - | } |
| - | |
| - | static int buffer_uptodate(struct buffer_head *bh) |
| - | { |
| - | return bh->b_uptodate; |
| - | } |
| - | |
| - | static inline void mark_buffer_uptodate(struct buffer_head *bh, int val) |
| - | { |
| - | bh->b_uptodate = val; |
| - | } |
| - | |
| - | static void wait_on_buffer(struct buffer_head *bh) |
| - | { |
| - | if (!bh->b_uptodate) |
| - | ll_rw_block(READ, 1, &bh); |
| - | } |
| - | |
| - | |
| - | static void e2fsck_clear_recover(e2fsck_t ctx, int error) |
| - | { |
| - | ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; |
| - | |
| - | /* if we had an error doing journal recovery, we need a full fsck */ |
| - | if (error) |
| - | ctx->fs->super->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(ctx->fs); |
| - | } |
| - | |
| - | static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | struct ext2_super_block jsuper; |
| - | struct problem_context pctx; |
| - | struct buffer_head *bh; |
| - | struct inode *j_inode = NULL; |
| - | struct kdev_s *dev_fs = NULL, *dev_journal; |
| - | const char *journal_name = NULL; |
| - | journal_t *journal = NULL; |
| - | errcode_t retval = 0; |
| - | io_manager io_ptr = 0; |
| - | unsigned long start = 0; |
| - | blk_t blk; |
| - | int ext_journal = 0; |
| - | int tried_backup_jnl = 0; |
| - | int i; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal"); |
| - | if (!journal) { |
| - | return EXT2_ET_NO_MEMORY; |
| - | } |
| - | |
| - | dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev"); |
| - | if (!dev_fs) { |
| - | retval = EXT2_ET_NO_MEMORY; |
| - | goto errout; |
| - | } |
| - | dev_journal = dev_fs+1; |
| - | |
| - | dev_fs->k_ctx = dev_journal->k_ctx = ctx; |
| - | dev_fs->k_dev = K_DEV_FS; |
| - | dev_journal->k_dev = K_DEV_JOURNAL; |
| - | |
| - | journal->j_dev = dev_journal; |
| - | journal->j_fs_dev = dev_fs; |
| - | journal->j_inode = NULL; |
| - | journal->j_blocksize = ctx->fs->blocksize; |
| - | |
| - | if (uuid_is_null(sb->s_journal_uuid)) { |
| - | if (!sb->s_journal_inum) |
| - | return EXT2_ET_BAD_INODE_NUM; |
| - | j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode), |
| - | "journal inode"); |
| - | if (!j_inode) { |
| - | retval = EXT2_ET_NO_MEMORY; |
| - | goto errout; |
| - | } |
| - | |
| - | j_inode->i_ctx = ctx; |
| - | j_inode->i_ino = sb->s_journal_inum; |
| - | |
| - | if ((retval = ext2fs_read_inode(ctx->fs, |
| - | sb->s_journal_inum, |
| - | &j_inode->i_ext2))) { |
| - | try_backup_journal: |
| - | if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || |
| - | tried_backup_jnl) |
| - | goto errout; |
| - | memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); |
| - | memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, |
| - | EXT2_N_BLOCKS*4); |
| - | j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; |
| - | j_inode->i_ext2.i_links_count = 1; |
| - | j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; |
| - | tried_backup_jnl++; |
| - | } |
| - | if (!j_inode->i_ext2.i_links_count || |
| - | !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { |
| - | retval = EXT2_ET_NO_JOURNAL; |
| - | goto try_backup_journal; |
| - | } |
| - | if (j_inode->i_ext2.i_size / journal->j_blocksize < |
| - | JFS_MIN_JOURNAL_BLOCKS) { |
| - | retval = EXT2_ET_JOURNAL_TOO_SMALL; |
| - | goto try_backup_journal; |
| - | } |
| - | for (i=0; i < EXT2_N_BLOCKS; i++) { |
| - | blk = j_inode->i_ext2.i_block[i]; |
| - | if (!blk) { |
| - | if (i < EXT2_NDIR_BLOCKS) { |
| - | retval = EXT2_ET_JOURNAL_TOO_SMALL; |
| - | goto try_backup_journal; |
| - | } |
| - | continue; |
| - | } |
| - | if (blk < sb->s_first_data_block || |
| - | blk >= sb->s_blocks_count) { |
| - | retval = EXT2_ET_BAD_BLOCK_NUM; |
| - | goto try_backup_journal; |
| - | } |
| - | } |
| - | journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize; |
| - | |
| - | #ifdef USE_INODE_IO |
| - | retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum, |
| - | &j_inode->i_ext2, |
| - | &journal_name); |
| - | if (retval) |
| - | goto errout; |
| - | |
| - | io_ptr = inode_io_manager; |
| - | #else |
| - | journal->j_inode = j_inode; |
| - | ctx->journal_io = ctx->fs->io; |
| - | if ((retval = journal_bmap(journal, 0, &start)) != 0) |
| - | goto errout; |
| - | #endif |
| - | } else { |
| - | ext_journal = 1; |
| - | if (!ctx->journal_name) { |
| - | char uuid[37]; |
| - | |
| - | uuid_unparse(sb->s_journal_uuid, uuid); |
| - | ctx->journal_name = blkid_get_devname(ctx->blkid, |
| - | "UUID", uuid); |
| - | if (!ctx->journal_name) |
| - | ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev); |
| - | } |
| - | journal_name = ctx->journal_name; |
| - | |
| - | if (!journal_name) { |
| - | fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx); |
| - | return EXT2_ET_LOAD_EXT_JOURNAL; |
| - | } |
| - | |
| - | io_ptr = unix_io_manager; |
| - | } |
| - | |
| - | #ifndef USE_INODE_IO |
| - | if (ext_journal) |
| - | #endif |
| - | retval = io_ptr->open(journal_name, IO_FLAG_RW, |
| - | &ctx->journal_io); |
| - | if (retval) |
| - | goto errout; |
| - | |
| - | io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize); |
| - | |
| - | if (ext_journal) { |
| - | if (ctx->fs->blocksize == 1024) |
| - | start = 1; |
| - | bh = getblk(dev_journal, start, ctx->fs->blocksize); |
| - | if (!bh) { |
| - | retval = EXT2_ET_NO_MEMORY; |
| - | goto errout; |
| - | } |
| - | ll_rw_block(READ, 1, &bh); |
| - | if ((retval = bh->b_err) != 0) |
| - | goto errout; |
| - | memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024, |
| - | sizeof(jsuper)); |
| - | brelse(bh); |
| - | #if BB_BIG_ENDIAN |
| - | if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) |
| - | ext2fs_swap_super(&jsuper); |
| - | #endif |
| - | if (jsuper.s_magic != EXT2_SUPER_MAGIC || |
| - | !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { |
| - | fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx); |
| - | retval = EXT2_ET_LOAD_EXT_JOURNAL; |
| - | goto errout; |
| - | } |
| - | /* Make sure the journal UUID is correct */ |
| - | if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid, |
| - | sizeof(jsuper.s_uuid))) { |
| - | fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx); |
| - | retval = EXT2_ET_LOAD_EXT_JOURNAL; |
| - | goto errout; |
| - | } |
| - | |
| - | journal->j_maxlen = jsuper.s_blocks_count; |
| - | start++; |
| - | } |
| - | |
| - | if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) { |
| - | retval = EXT2_ET_NO_MEMORY; |
| - | goto errout; |
| - | } |
| - | |
| - | journal->j_sb_buffer = bh; |
| - | journal->j_superblock = (journal_superblock_t *)bh->b_data; |
| - | |
| - | #ifdef USE_INODE_IO |
| - | ext2fs_free_mem(&j_inode); |
| - | #endif |
| - | |
| - | *ret_journal = journal; |
| - | return 0; |
| - | |
| - | errout: |
| - | ext2fs_free_mem(&dev_fs); |
| - | ext2fs_free_mem(&j_inode); |
| - | ext2fs_free_mem(&journal); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx, |
| - | struct problem_context *pctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | int recover = ctx->fs->super->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_RECOVER; |
| - | int has_journal = ctx->fs->super->s_feature_compat & |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | |
| - | if (has_journal || sb->s_journal_inum) { |
| - | /* The journal inode is bogus, remove and force full fsck */ |
| - | pctx->ino = sb->s_journal_inum; |
| - | if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) { |
| - | if (has_journal && sb->s_journal_inum) |
| - | printf("*** ext3 journal has been deleted - " |
| - | "filesystem is now ext2 only ***\n\n"); |
| - | sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | sb->s_journal_inum = 0; |
| - | ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */ |
| - | e2fsck_clear_recover(ctx, 1); |
| - | return 0; |
| - | } |
| - | return EXT2_ET_BAD_INODE_NUM; |
| - | } else if (recover) { |
| - | if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) { |
| - | e2fsck_clear_recover(ctx, 1); |
| - | return 0; |
| - | } |
| - | return EXT2_ET_UNSUPP_FEATURE; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | #define V1_SB_SIZE 0x0024 |
| - | static void clear_v2_journal_fields(journal_t *journal) |
| - | { |
| - | e2fsck_t ctx = journal->j_dev->k_ctx; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx)) |
| - | return; |
| - | |
| - | memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0, |
| - | ctx->fs->blocksize-V1_SB_SIZE); |
| - | mark_buffer_dirty(journal->j_sb_buffer); |
| - | } |
| - | |
| - | |
| - | static errcode_t e2fsck_journal_load(journal_t *journal) |
| - | { |
| - | e2fsck_t ctx = journal->j_dev->k_ctx; |
| - | journal_superblock_t *jsb; |
| - | struct buffer_head *jbh = journal->j_sb_buffer; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | ll_rw_block(READ, 1, &jbh); |
| - | if (jbh->b_err) { |
| - | bb_error_msg(_("reading journal superblock")); |
| - | return jbh->b_err; |
| - | } |
| - | |
| - | jsb = journal->j_superblock; |
| - | /* If we don't even have JFS_MAGIC, we probably have a wrong inode */ |
| - | if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER)) |
| - | return e2fsck_journal_fix_bad_inode(ctx, &pctx); |
| - | |
| - | switch (ntohl(jsb->s_header.h_blocktype)) { |
| - | case JFS_SUPERBLOCK_V1: |
| - | journal->j_format_version = 1; |
| - | if (jsb->s_feature_compat || |
| - | jsb->s_feature_incompat || |
| - | jsb->s_feature_ro_compat || |
| - | jsb->s_nr_users) |
| - | clear_v2_journal_fields(journal); |
| - | break; |
| - | |
| - | case JFS_SUPERBLOCK_V2: |
| - | journal->j_format_version = 2; |
| - | if (ntohl(jsb->s_nr_users) > 1 && |
| - | uuid_is_null(ctx->fs->super->s_journal_uuid)) |
| - | clear_v2_journal_fields(journal); |
| - | if (ntohl(jsb->s_nr_users) > 1) { |
| - | fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx); |
| - | return EXT2_ET_JOURNAL_UNSUPP_VERSION; |
| - | } |
| - | break; |
| - | |
| - | /* |
| - | * These should never appear in a journal super block, so if |
| - | * they do, the journal is badly corrupted. |
| - | */ |
| - | case JFS_DESCRIPTOR_BLOCK: |
| - | case JFS_COMMIT_BLOCK: |
| - | case JFS_REVOKE_BLOCK: |
| - | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | |
| - | /* If we don't understand the superblock major type, but there |
| - | * is a magic number, then it is likely to be a new format we |
| - | * just don't understand, so leave it alone. */ |
| - | default: |
| - | return EXT2_ET_JOURNAL_UNSUPP_VERSION; |
| - | } |
| - | |
| - | if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) |
| - | return EXT2_ET_UNSUPP_FEATURE; |
| - | |
| - | if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) |
| - | return EXT2_ET_RO_UNSUPP_FEATURE; |
| - | |
| - | /* We have now checked whether we know enough about the journal |
| - | * format to be able to proceed safely, so any other checks that |
| - | * fail we should attempt to recover from. */ |
| - | if (jsb->s_blocksize != htonl(journal->j_blocksize)) { |
| - | bb_error_msg(_("%s: no valid journal superblock found"), |
| - | ctx->device_name); |
| - | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | } |
| - | |
| - | if (ntohl(jsb->s_maxlen) < journal->j_maxlen) |
| - | journal->j_maxlen = ntohl(jsb->s_maxlen); |
| - | else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) { |
| - | bb_error_msg(_("%s: journal too short"), |
| - | ctx->device_name); |
| - | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | } |
| - | |
| - | journal->j_tail_sequence = ntohl(jsb->s_sequence); |
| - | journal->j_transaction_sequence = journal->j_tail_sequence; |
| - | journal->j_tail = ntohl(jsb->s_start); |
| - | journal->j_first = ntohl(jsb->s_first); |
| - | journal->j_last = ntohl(jsb->s_maxlen); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb, |
| - | journal_t *journal) |
| - | { |
| - | char *p; |
| - | union { |
| - | uuid_t uuid; |
| - | __u32 val[4]; |
| - | } u; |
| - | __u32 new_seq = 0; |
| - | int i; |
| - | |
| - | /* Leave a valid existing V1 superblock signature alone. |
| - | * Anything unrecognizable we overwrite with a new V2 |
| - | * signature. */ |
| - | |
| - | if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || |
| - | jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) { |
| - | jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); |
| - | jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); |
| - | } |
| - | |
| - | /* Zero out everything else beyond the superblock header */ |
| - | |
| - | p = ((char *) jsb) + sizeof(journal_header_t); |
| - | memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t)); |
| - | |
| - | jsb->s_blocksize = htonl(ctx->fs->blocksize); |
| - | jsb->s_maxlen = htonl(journal->j_maxlen); |
| - | jsb->s_first = htonl(1); |
| - | |
| - | /* Initialize the journal sequence number so that there is "no" |
| - | * chance we will find old "valid" transactions in the journal. |
| - | * This avoids the need to zero the whole journal (slow to do, |
| - | * and risky when we are just recovering the filesystem). |
| - | */ |
| - | uuid_generate(u.uuid); |
| - | for (i = 0; i < 4; i ++) |
| - | new_seq ^= u.val[i]; |
| - | jsb->s_sequence = htonl(new_seq); |
| - | |
| - | mark_buffer_dirty(journal->j_sb_buffer); |
| - | ll_rw_block(WRITE, 1, &journal->j_sb_buffer); |
| - | } |
| - | |
| - | static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx, |
| - | journal_t *journal, |
| - | struct problem_context *pctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | int recover = ctx->fs->super->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_RECOVER; |
| - | |
| - | if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { |
| - | if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) { |
| - | e2fsck_journal_reset_super(ctx, journal->j_superblock, |
| - | journal); |
| - | journal->j_transaction_sequence = 1; |
| - | e2fsck_clear_recover(ctx, recover); |
| - | return 0; |
| - | } |
| - | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | } else if (e2fsck_journal_fix_bad_inode(ctx, pctx)) |
| - | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal, |
| - | int reset, int drop) |
| - | { |
| - | journal_superblock_t *jsb; |
| - | |
| - | if (drop) |
| - | mark_buffer_clean(journal->j_sb_buffer); |
| - | else if (!(ctx->options & E2F_OPT_READONLY)) { |
| - | jsb = journal->j_superblock; |
| - | jsb->s_sequence = htonl(journal->j_transaction_sequence); |
| - | if (reset) |
| - | jsb->s_start = 0; /* this marks the journal as empty */ |
| - | mark_buffer_dirty(journal->j_sb_buffer); |
| - | } |
| - | brelse(journal->j_sb_buffer); |
| - | |
| - | if (ctx->journal_io) { |
| - | if (ctx->fs && ctx->fs->io != ctx->journal_io) |
| - | io_channel_close(ctx->journal_io); |
| - | ctx->journal_io = 0; |
| - | } |
| - | |
| - | #ifndef USE_INODE_IO |
| - | ext2fs_free_mem(&journal->j_inode); |
| - | #endif |
| - | ext2fs_free_mem(&journal->j_fs_dev); |
| - | ext2fs_free_mem(&journal); |
| - | } |
| - | |
| - | /* |
| - | * This function makes sure that the superblock fields regarding the |
| - | * journal are consistent. |
| - | */ |
| - | static int e2fsck_check_ext3_journal(e2fsck_t ctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | journal_t *journal; |
| - | int recover = ctx->fs->super->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_RECOVER; |
| - | struct problem_context pctx; |
| - | problem_t problem; |
| - | int reset = 0, force_fsck = 0; |
| - | int retval; |
| - | |
| - | /* If we don't have any journal features, don't do anything more */ |
| - | if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
| - | !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 && |
| - | uuid_is_null(sb->s_journal_uuid)) |
| - | return 0; |
| - | |
| - | clear_problem_context(&pctx); |
| - | pctx.num = sb->s_journal_inum; |
| - | |
| - | retval = e2fsck_get_journal(ctx, &journal); |
| - | if (retval) { |
| - | if ((retval == EXT2_ET_BAD_INODE_NUM) || |
| - | (retval == EXT2_ET_BAD_BLOCK_NUM) || |
| - | (retval == EXT2_ET_JOURNAL_TOO_SMALL) || |
| - | (retval == EXT2_ET_NO_JOURNAL)) |
| - | return e2fsck_journal_fix_bad_inode(ctx, &pctx); |
| - | return retval; |
| - | } |
| - | |
| - | retval = e2fsck_journal_load(journal); |
| - | if (retval) { |
| - | if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) || |
| - | ((retval == EXT2_ET_UNSUPP_FEATURE) && |
| - | (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT, |
| - | &pctx))) || |
| - | ((retval == EXT2_ET_RO_UNSUPP_FEATURE) && |
| - | (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT, |
| - | &pctx))) || |
| - | ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) && |
| - | (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx)))) |
| - | retval = e2fsck_journal_fix_corrupt_super(ctx, journal, |
| - | &pctx); |
| - | e2fsck_journal_release(ctx, journal, 0, 1); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * We want to make the flags consistent here. We will not leave with |
| - | * needs_recovery set but has_journal clear. We can't get in a loop |
| - | * with -y, -n, or -p, only if a user isn't making up their mind. |
| - | */ |
| - | no_has_journal: |
| - | if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { |
| - | recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; |
| - | pctx.str = "inode"; |
| - | if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) { |
| - | if (recover && |
| - | !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx)) |
| - | goto no_has_journal; |
| - | /* |
| - | * Need a full fsck if we are releasing a |
| - | * journal stored on a reserved inode. |
| - | */ |
| - | force_fsck = recover || |
| - | (sb->s_journal_inum < EXT2_FIRST_INODE(sb)); |
| - | /* Clear all of the journal fields */ |
| - | sb->s_journal_inum = 0; |
| - | sb->s_journal_dev = 0; |
| - | memset(sb->s_journal_uuid, 0, |
| - | sizeof(sb->s_journal_uuid)); |
| - | e2fsck_clear_recover(ctx, force_fsck); |
| - | } else if (!(ctx->options & E2F_OPT_READONLY)) { |
| - | sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | ext2fs_mark_super_dirty(ctx->fs); |
| - | } |
| - | } |
| - | |
| - | if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && |
| - | !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && |
| - | journal->j_superblock->s_start != 0) { |
| - | /* Print status information */ |
| - | fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx); |
| - | if (ctx->superblock) |
| - | problem = PR_0_JOURNAL_RUN_DEFAULT; |
| - | else |
| - | problem = PR_0_JOURNAL_RUN; |
| - | if (fix_problem(ctx, problem, &pctx)) { |
| - | ctx->options |= E2F_OPT_FORCE; |
| - | sb->s_feature_incompat |= |
| - | EXT3_FEATURE_INCOMPAT_RECOVER; |
| - | ext2fs_mark_super_dirty(ctx->fs); |
| - | } else if (fix_problem(ctx, |
| - | PR_0_JOURNAL_RESET_JOURNAL, &pctx)) { |
| - | reset = 1; |
| - | sb->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(ctx->fs); |
| - | } |
| - | /* |
| - | * If the user answers no to the above question, we |
| - | * ignore the fact that journal apparently has data; |
| - | * accidentally replaying over valid data would be far |
| - | * worse than skipping a questionable recovery. |
| - | * |
| - | * XXX should we abort with a fatal error here? What |
| - | * will the ext3 kernel code do if a filesystem with |
| - | * !NEEDS_RECOVERY but with a non-zero |
| - | * journal->j_superblock->s_start is mounted? |
| - | */ |
| - | } |
| - | |
| - | e2fsck_journal_release(ctx, journal, reset, 0); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t recover_ext3_journal(e2fsck_t ctx) |
| - | { |
| - | journal_t *journal; |
| - | int retval; |
| - | |
| - | journal_init_revoke_caches(); |
| - | retval = e2fsck_get_journal(ctx, &journal); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | retval = e2fsck_journal_load(journal); |
| - | if (retval) |
| - | goto errout; |
| - | |
| - | retval = journal_init_revoke(journal, 1024); |
| - | if (retval) |
| - | goto errout; |
| - | |
| - | retval = -journal_recover(journal); |
| - | if (retval) |
| - | goto errout; |
| - | |
| - | if (journal->j_superblock->s_errno) { |
| - | ctx->fs->super->s_state |= EXT2_ERROR_FS; |
| - | ext2fs_mark_super_dirty(ctx->fs); |
| - | journal->j_superblock->s_errno = 0; |
| - | mark_buffer_dirty(journal->j_sb_buffer); |
| - | } |
| - | |
| - | errout: |
| - | journal_destroy_revoke(journal); |
| - | journal_destroy_revoke_caches(); |
| - | e2fsck_journal_release(ctx, journal, 1, 0); |
| - | return retval; |
| - | } |
| - | |
| - | static int e2fsck_run_ext3_journal(e2fsck_t ctx) |
| - | { |
| - | io_manager io_ptr = ctx->fs->io->manager; |
| - | int blocksize = ctx->fs->blocksize; |
| - | errcode_t retval, recover_retval; |
| - | |
| - | printf(_("%s: recovering journal\n"), ctx->device_name); |
| - | if (ctx->options & E2F_OPT_READONLY) { |
| - | printf(_("%s: won't do journal recovery while read-only\n"), |
| - | ctx->device_name); |
| - | return EXT2_ET_FILE_RO; |
| - | } |
| - | |
| - | if (ctx->fs->flags & EXT2_FLAG_DIRTY) |
| - | ext2fs_flush(ctx->fs); /* Force out any modifications */ |
| - | |
| - | recover_retval = recover_ext3_journal(ctx); |
| - | |
| - | /* |
| - | * Reload the filesystem context to get up-to-date data from disk |
| - | * because journal recovery will change the filesystem under us. |
| - | */ |
| - | ext2fs_close(ctx->fs); |
| - | retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW, |
| - | ctx->superblock, blocksize, io_ptr, |
| - | &ctx->fs); |
| - | |
| - | if (retval) { |
| - | bb_error_msg(_("while trying to re-open %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | ctx->fs->priv_data = ctx; |
| - | |
| - | /* Set the superblock flags */ |
| - | e2fsck_clear_recover(ctx, recover_retval); |
| - | return recover_retval; |
| - | } |
| - | |
| - | /* |
| - | * This function will move the journal inode from a visible file in |
| - | * the filesystem directory hierarchy to the reserved inode if necessary. |
| - | */ |
| - | static const char *const journal_names[] = { |
| - | ".journal", "journal", ".journal.dat", "journal.dat", 0 }; |
| - | |
| - | static void e2fsck_move_ext3_journal(e2fsck_t ctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | struct problem_context pctx; |
| - | struct ext2_inode inode; |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t ino; |
| - | errcode_t retval; |
| - | const char *const * cpp; |
| - | int group, mount_flags; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | /* |
| - | * If the filesystem is opened read-only, or there is no |
| - | * journal, then do nothing. |
| - | */ |
| - | if ((ctx->options & E2F_OPT_READONLY) || |
| - | (sb->s_journal_inum == 0) || |
| - | !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) |
| - | return; |
| - | |
| - | /* |
| - | * Read in the journal inode |
| - | */ |
| - | if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0) |
| - | return; |
| - | |
| - | /* |
| - | * If it's necessary to backup the journal inode, do so. |
| - | */ |
| - | if ((sb->s_jnl_backup_type == 0) || |
| - | ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) && |
| - | memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) { |
| - | if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) { |
| - | memcpy(sb->s_jnl_blocks, inode.i_block, |
| - | EXT2_N_BLOCKS*4); |
| - | sb->s_jnl_blocks[16] = inode.i_size; |
| - | sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * If the journal is already the hidden inode, then do nothing |
| - | */ |
| - | if (sb->s_journal_inum == EXT2_JOURNAL_INO) |
| - | return; |
| - | |
| - | /* |
| - | * The journal inode had better have only one link and not be readable. |
| - | */ |
| - | if (inode.i_links_count != 1) |
| - | return; |
| - | |
| - | /* |
| - | * If the filesystem is mounted, or we can't tell whether |
| - | * or not it's mounted, do nothing. |
| - | */ |
| - | retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); |
| - | if (retval || (mount_flags & EXT2_MF_MOUNTED)) |
| - | return; |
| - | |
| - | /* |
| - | * If we can't find the name of the journal inode, then do |
| - | * nothing. |
| - | */ |
| - | for (cpp = journal_names; *cpp; cpp++) { |
| - | retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp, |
| - | strlen(*cpp), 0, &ino); |
| - | if ((retval == 0) && (ino == sb->s_journal_inum)) |
| - | break; |
| - | } |
| - | if (*cpp == 0) |
| - | return; |
| - | |
| - | /* We need the inode bitmap to be loaded */ |
| - | retval = ext2fs_read_bitmaps(fs); |
| - | if (retval) |
| - | return; |
| - | |
| - | pctx.str = *cpp; |
| - | if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx)) |
| - | return; |
| - | |
| - | /* |
| - | * OK, we've done all the checks, let's actually move the |
| - | * journal inode. Errors at this point mean we need to force |
| - | * an ext2 filesystem check. |
| - | */ |
| - | if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0) |
| - | goto err_out; |
| - | if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0) |
| - | goto err_out; |
| - | sb->s_journal_inum = EXT2_JOURNAL_INO; |
| - | ext2fs_mark_super_dirty(fs); |
| - | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
| - | inode.i_links_count = 0; |
| - | inode.i_dtime = time(NULL); |
| - | if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0) |
| - | goto err_out; |
| - | |
| - | group = ext2fs_group_of_ino(fs, ino); |
| - | ext2fs_unmark_inode_bitmap(fs->inode_map, ino); |
| - | ext2fs_mark_ib_dirty(fs); |
| - | fs->group_desc[group].bg_free_inodes_count++; |
| - | fs->super->s_free_inodes_count++; |
| - | return; |
| - | |
| - | err_out: |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx); |
| - | fs->super->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | /* |
| - | * message.c --- print e2fsck messages (with compression) |
| - | * |
| - | * print_e2fsck_message() prints a message to the user, using |
| - | * compression techniques and expansions of abbreviations. |
| - | * |
| - | * The following % expansions are supported: |
| - | * |
| - | * %b <blk> block number |
| - | * %B <blkcount> integer |
| - | * %c <blk2> block number |
| - | * %Di <dirent>->ino inode number |
| - | * %Dn <dirent>->name string |
| - | * %Dr <dirent>->rec_len |
| - | * %Dl <dirent>->name_len |
| - | * %Dt <dirent>->filetype |
| - | * %d <dir> inode number |
| - | * %g <group> integer |
| - | * %i <ino> inode number |
| - | * %Is <inode> -> i_size |
| - | * %IS <inode> -> i_extra_isize |
| - | * %Ib <inode> -> i_blocks |
| - | * %Il <inode> -> i_links_count |
| - | * %Im <inode> -> i_mode |
| - | * %IM <inode> -> i_mtime |
| - | * %IF <inode> -> i_faddr |
| - | * %If <inode> -> i_file_acl |
| - | * %Id <inode> -> i_dir_acl |
| - | * %Iu <inode> -> i_uid |
| - | * %Ig <inode> -> i_gid |
| - | * %j <ino2> inode number |
| - | * %m <com_err error message> |
| - | * %N <num> |
| - | * %p ext2fs_get_pathname of directory <ino> |
| - | * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as |
| - | * the containing directory. (If dirent is NULL |
| - | * then return the pathname of directory <ino2>) |
| - | * %q ext2fs_get_pathname of directory <dir> |
| - | * %Q ext2fs_get_pathname of directory <ino> with <dir> as |
| - | * the containing directory. |
| - | * %s <str> miscellaneous string |
| - | * %S backup superblock |
| - | * %X <num> hexadecimal format |
| - | * |
| - | * The following '@' expansions are supported: |
| - | * |
| - | * @a extended attribute |
| - | * @A error allocating |
| - | * @b block |
| - | * @B bitmap |
| - | * @c compress |
| - | * @C conflicts with some other fs block |
| - | * @D deleted |
| - | * @d directory |
| - | * @e entry |
| - | * @E Entry '%Dn' in %p (%i) |
| - | * @f filesystem |
| - | * @F for @i %i (%Q) is |
| - | * @g group |
| - | * @h HTREE directory inode |
| - | * @i inode |
| - | * @I illegal |
| - | * @j journal |
| - | * @l lost+found |
| - | * @L is a link |
| - | * @m multiply-claimed |
| - | * @n invalid |
| - | * @o orphaned |
| - | * @p problem in |
| - | * @r root inode |
| - | * @s should be |
| - | * @S superblock |
| - | * @u unattached |
| - | * @v device |
| - | * @z zero-length |
| - | */ |
| - | |
| - | |
| - | /* |
| - | * This structure defines the abbreviations used by the text strings |
| - | * below. The first character in the string is the index letter. An |
| - | * abbreviation of the form '@<i>' is expanded by looking up the index |
| - | * letter <i> in the table below. |
| - | */ |
| - | static const char *const abbrevs[] = { |
| - | N_("aextended attribute"), |
| - | N_("Aerror allocating"), |
| - | N_("bblock"), |
| - | N_("Bbitmap"), |
| - | N_("ccompress"), |
| - | N_("Cconflicts with some other fs @b"), |
| - | N_("iinode"), |
| - | N_("Iillegal"), |
| - | N_("jjournal"), |
| - | N_("Ddeleted"), |
| - | N_("ddirectory"), |
| - | N_("eentry"), |
| - | N_("E@e '%Dn' in %p (%i)"), |
| - | N_("ffilesystem"), |
| - | N_("Ffor @i %i (%Q) is"), |
| - | N_("ggroup"), |
| - | N_("hHTREE @d @i"), |
| - | N_("llost+found"), |
| - | N_("Lis a link"), |
| - | N_("mmultiply-claimed"), |
| - | N_("ninvalid"), |
| - | N_("oorphaned"), |
| - | N_("pproblem in"), |
| - | N_("rroot @i"), |
| - | N_("sshould be"), |
| - | N_("Ssuper@b"), |
| - | N_("uunattached"), |
| - | N_("vdevice"), |
| - | N_("zzero-length"), |
| - | "@@", |
| - | 0 |
| - | }; |
| - | |
| - | /* |
| - | * Give more user friendly names to the "special" inodes. |
| - | */ |
| - | #define num_special_inodes 11 |
| - | static const char *const special_inode_name[] = |
| - | { |
| - | N_("<The NULL inode>"), /* 0 */ |
| - | N_("<The bad blocks inode>"), /* 1 */ |
| - | "/", /* 2 */ |
| - | N_("<The ACL index inode>"), /* 3 */ |
| - | N_("<The ACL data inode>"), /* 4 */ |
| - | N_("<The boot loader inode>"), /* 5 */ |
| - | N_("<The undelete directory inode>"), /* 6 */ |
| - | N_("<The group descriptor inode>"), /* 7 */ |
| - | N_("<The journal inode>"), /* 8 */ |
| - | N_("<Reserved inode 9>"), /* 9 */ |
| - | N_("<Reserved inode 10>"), /* 10 */ |
| - | }; |
| - | |
| - | /* |
| - | * This function does "safe" printing. It will convert non-printable |
| - | * ASCII characters using '^' and M- notation. |
| - | */ |
| - | static void safe_print(const char *cp, int len) |
| - | { |
| - | unsigned char ch; |
| - | |
| - | if (len < 0) |
| - | len = strlen(cp); |
| - | |
| - | while (len--) { |
| - | ch = *cp++; |
| - | if (ch > 128) { |
| - | fputs("M-", stdout); |
| - | ch -= 128; |
| - | } |
| - | if ((ch < 32) || (ch == 0x7f)) { |
| - | bb_putchar('^'); |
| - | ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ |
| - | } |
| - | bb_putchar(ch); |
| - | } |
| - | } |
| - | |
| - | |
| - | /* |
| - | * This function prints a pathname, using the ext2fs_get_pathname |
| - | * function |
| - | */ |
| - | static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino) |
| - | { |
| - | errcode_t retval; |
| - | char *path; |
| - | |
| - | if (!dir && (ino < num_special_inodes)) { |
| - | fputs(_(special_inode_name[ino]), stdout); |
| - | return; |
| - | } |
| - | |
| - | retval = ext2fs_get_pathname(fs, dir, ino, &path); |
| - | if (retval) |
| - | fputs("???", stdout); |
| - | else { |
| - | safe_print(path, -1); |
| - | ext2fs_free_mem(&path); |
| - | } |
| - | } |
| - | |
| - | static void print_e2fsck_message(e2fsck_t ctx, const char *msg, |
| - | struct problem_context *pctx, int first); |
| - | /* |
| - | * This function handles the '@' expansion. We allow recursive |
| - | * expansion; an @ expression can contain further '@' and '%' |
| - | * expressions. |
| - | */ |
| - | static void expand_at_expression(e2fsck_t ctx, char ch, |
| - | struct problem_context *pctx, |
| - | int *first) |
| - | { |
| - | const char *const *cpp; |
| - | const char *str; |
| - | |
| - | /* Search for the abbreviation */ |
| - | for (cpp = abbrevs; *cpp; cpp++) { |
| - | if (ch == *cpp[0]) |
| - | break; |
| - | } |
| - | if (*cpp) { |
| - | str = _(*cpp) + 1; |
| - | if (*first && islower(*str)) { |
| - | *first = 0; |
| - | bb_putchar(toupper(*str++)); |
| - | } |
| - | print_e2fsck_message(ctx, str, pctx, *first); |
| - | } else |
| - | printf("@%c", ch); |
| - | } |
| - | |
| - | /* |
| - | * This function expands '%IX' expressions |
| - | */ |
| - | static void expand_inode_expression(char ch, |
| - | struct problem_context *ctx) |
| - | { |
| - | struct ext2_inode *inode; |
| - | struct ext2_inode_large *large_inode; |
| - | char * time_str; |
| - | time_t t; |
| - | int do_gmt = -1; |
| - | |
| - | if (!ctx || !ctx->inode) |
| - | goto no_inode; |
| - | |
| - | inode = ctx->inode; |
| - | large_inode = (struct ext2_inode_large *) inode; |
| - | |
| - | switch (ch) { |
| - | case 's': |
| - | if (LINUX_S_ISDIR(inode->i_mode)) |
| - | printf("%u", inode->i_size); |
| - | else { |
| - | printf("%"PRIu64, (inode->i_size | |
| - | ((uint64_t) inode->i_size_high << 32))); |
| - | } |
| - | break; |
| - | case 'S': |
| - | printf("%u", large_inode->i_extra_isize); |
| - | break; |
| - | case 'b': |
| - | printf("%u", inode->i_blocks); |
| - | break; |
| - | case 'l': |
| - | printf("%d", inode->i_links_count); |
| - | break; |
| - | case 'm': |
| - | printf("0%o", inode->i_mode); |
| - | break; |
| - | case 'M': |
| - | /* The diet libc doesn't respect the TZ environemnt variable */ |
| - | if (do_gmt == -1) { |
| - | time_str = getenv("TZ"); |
| - | if (!time_str) |
| - | time_str = ""; |
| - | do_gmt = !strcmp(time_str, "GMT"); |
| - | } |
| - | t = inode->i_mtime; |
| - | time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t)); |
| - | printf("%.24s", time_str); |
| - | break; |
| - | case 'F': |
| - | printf("%u", inode->i_faddr); |
| - | break; |
| - | case 'f': |
| - | printf("%u", inode->i_file_acl); |
| - | break; |
| - | case 'd': |
| - | printf("%u", (LINUX_S_ISDIR(inode->i_mode) ? |
| - | inode->i_dir_acl : 0)); |
| - | break; |
| - | case 'u': |
| - | printf("%d", (inode->i_uid | |
| - | (inode->osd2.linux2.l_i_uid_high << 16))); |
| - | break; |
| - | case 'g': |
| - | printf("%d", (inode->i_gid | |
| - | (inode->osd2.linux2.l_i_gid_high << 16))); |
| - | break; |
| - | default: |
| - | no_inode: |
| - | printf("%%I%c", ch); |
| - | break; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * This function expands '%dX' expressions |
| - | */ |
| - | static void expand_dirent_expression(char ch, |
| - | struct problem_context *ctx) |
| - | { |
| - | struct ext2_dir_entry *dirent; |
| - | int len; |
| - | |
| - | if (!ctx || !ctx->dirent) |
| - | goto no_dirent; |
| - | |
| - | dirent = ctx->dirent; |
| - | |
| - | switch (ch) { |
| - | case 'i': |
| - | printf("%u", dirent->inode); |
| - | break; |
| - | case 'n': |
| - | len = dirent->name_len & 0xFF; |
| - | if (len > EXT2_NAME_LEN) |
| - | len = EXT2_NAME_LEN; |
| - | if (len > dirent->rec_len) |
| - | len = dirent->rec_len; |
| - | safe_print(dirent->name, len); |
| - | break; |
| - | case 'r': |
| - | printf("%u", dirent->rec_len); |
| - | break; |
| - | case 'l': |
| - | printf("%u", dirent->name_len & 0xFF); |
| - | break; |
| - | case 't': |
| - | printf("%u", dirent->name_len >> 8); |
| - | break; |
| - | default: |
| - | no_dirent: |
| - | printf("%%D%c", ch); |
| - | break; |
| - | } |
| - | } |
| - | |
| - | static void expand_percent_expression(ext2_filsys fs, char ch, |
| - | struct problem_context *ctx) |
| - | { |
| - | if (!ctx) |
| - | goto no_context; |
| - | |
| - | switch (ch) { |
| - | case '%': |
| - | bb_putchar('%'); |
| - | break; |
| - | case 'b': |
| - | printf("%u", ctx->blk); |
| - | break; |
| - | case 'B': |
| - | printf("%"PRIi64, ctx->blkcount); |
| - | break; |
| - | case 'c': |
| - | printf("%u", ctx->blk2); |
| - | break; |
| - | case 'd': |
| - | printf("%u", ctx->dir); |
| - | break; |
| - | case 'g': |
| - | printf("%d", ctx->group); |
| - | break; |
| - | case 'i': |
| - | printf("%u", ctx->ino); |
| - | break; |
| - | case 'j': |
| - | printf("%u", ctx->ino2); |
| - | break; |
| - | case 'm': |
| - | fputs(error_message(ctx->errcode), stdout); |
| - | break; |
| - | case 'N': |
| - | printf("%"PRIi64, ctx->num); |
| - | break; |
| - | case 'p': |
| - | print_pathname(fs, ctx->ino, 0); |
| - | break; |
| - | case 'P': |
| - | print_pathname(fs, ctx->ino2, |
| - | ctx->dirent ? ctx->dirent->inode : 0); |
| - | break; |
| - | case 'q': |
| - | print_pathname(fs, ctx->dir, 0); |
| - | break; |
| - | case 'Q': |
| - | print_pathname(fs, ctx->dir, ctx->ino); |
| - | break; |
| - | case 'S': |
| - | printf("%d", get_backup_sb(NULL, fs, NULL, NULL)); |
| - | break; |
| - | case 's': |
| - | fputs((ctx->str ? ctx->str : "NULL"), stdout); |
| - | break; |
| - | case 'X': |
| - | printf("0x%"PRIi64, ctx->num); |
| - | break; |
| - | default: |
| - | no_context: |
| - | printf("%%%c", ch); |
| - | break; |
| - | } |
| - | } |
| - | |
| - | |
| - | static void print_e2fsck_message(e2fsck_t ctx, const char *msg, |
| - | struct problem_context *pctx, int first) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | const char * cp; |
| - | int i; |
| - | |
| - | e2fsck_clear_progbar(ctx); |
| - | for (cp = msg; *cp; cp++) { |
| - | if (cp[0] == '@') { |
| - | cp++; |
| - | expand_at_expression(ctx, *cp, pctx, &first); |
| - | } else if (cp[0] == '%' && cp[1] == 'I') { |
| - | cp += 2; |
| - | expand_inode_expression(*cp, pctx); |
| - | } else if (cp[0] == '%' && cp[1] == 'D') { |
| - | cp += 2; |
| - | expand_dirent_expression(*cp, pctx); |
| - | } else if ((cp[0] == '%')) { |
| - | cp++; |
| - | expand_percent_expression(fs, *cp, pctx); |
| - | } else { |
| - | for (i=0; cp[i]; i++) |
| - | if ((cp[i] == '@') || cp[i] == '%') |
| - | break; |
| - | printf("%.*s", i, cp); |
| - | cp += i-1; |
| - | } |
| - | first = 0; |
| - | } |
| - | } |
| - | |
| - | |
| - | /* |
| - | * region.c --- code which manages allocations within a region. |
| - | */ |
| - | |
| - | struct region_el { |
| - | region_addr_t start; |
| - | region_addr_t end; |
| - | struct region_el *next; |
| - | }; |
| - | |
| - | struct region_struct { |
| - | region_addr_t min; |
| - | region_addr_t max; |
| - | struct region_el *allocated; |
| - | }; |
| - | |
| - | static region_t region_create(region_addr_t min, region_addr_t max) |
| - | { |
| - | region_t region; |
| - | |
| - | region = xzalloc(sizeof(struct region_struct)); |
| - | region->min = min; |
| - | region->max = max; |
| - | return region; |
| - | } |
| - | |
| - | static void region_free(region_t region) |
| - | { |
| - | struct region_el *r, *next; |
| - | |
| - | for (r = region->allocated; r; r = next) { |
| - | next = r->next; |
| - | free(r); |
| - | } |
| - | memset(region, 0, sizeof(struct region_struct)); |
| - | free(region); |
| - | } |
| - | |
| - | static int region_allocate(region_t region, region_addr_t start, int n) |
| - | { |
| - | struct region_el *r, *new_region, *prev, *next; |
| - | region_addr_t end; |
| - | |
| - | end = start+n; |
| - | if ((start < region->min) || (end > region->max)) |
| - | return -1; |
| - | if (n == 0) |
| - | return 1; |
| - | |
| - | /* |
| - | * Search through the linked list. If we find that it |
| - | * conflicts witih something that's already allocated, return |
| - | * 1; if we can find an existing region which we can grow, do |
| - | * so. Otherwise, stop when we find the appropriate place |
| - | * insert a new region element into the linked list. |
| - | */ |
| - | for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) { |
| - | if (((start >= r->start) && (start < r->end)) || |
| - | ((end > r->start) && (end <= r->end)) || |
| - | ((start <= r->start) && (end >= r->end))) |
| - | return 1; |
| - | if (end == r->start) { |
| - | r->start = start; |
| - | return 0; |
| - | } |
| - | if (start == r->end) { |
| - | if ((next = r->next)) { |
| - | if (end > next->start) |
| - | return 1; |
| - | if (end == next->start) { |
| - | r->end = next->end; |
| - | r->next = next->next; |
| - | free(next); |
| - | return 0; |
| - | } |
| - | } |
| - | r->end = end; |
| - | return 0; |
| - | } |
| - | if (start < r->start) |
| - | break; |
| - | } |
| - | /* |
| - | * Insert a new region element structure into the linked list |
| - | */ |
| - | new_region = xmalloc(sizeof(struct region_el)); |
| - | new_region->start = start; |
| - | new_region->end = start + n; |
| - | new_region->next = r; |
| - | if (prev) |
| - | prev->next = new_region; |
| - | else |
| - | region->allocated = new_region; |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table |
| - | * |
| - | * Pass 1 of e2fsck iterates over all the inodes in the filesystems, |
| - | * and applies the following tests to each inode: |
| - | * |
| - | * - The mode field of the inode must be legal. |
| - | * - The size and block count fields of the inode are correct. |
| - | * - A data block must not be used by another inode |
| - | * |
| - | * Pass 1 also gathers the collects the following information: |
| - | * |
| - | * - A bitmap of which inodes are in use. (inode_used_map) |
| - | * - A bitmap of which inodes are directories. (inode_dir_map) |
| - | * - A bitmap of which inodes are regular files. (inode_reg_map) |
| - | * - A bitmap of which inodes have bad fields. (inode_bad_map) |
| - | * - A bitmap of which inodes are imagic inodes. (inode_imagic_map) |
| - | * - A bitmap of which blocks are in use. (block_found_map) |
| - | * - A bitmap of which blocks are in use by two inodes (block_dup_map) |
| - | * - The data blocks of the directory inodes. (dir_map) |
| - | * |
| - | * Pass 1 is designed to stash away enough information so that the |
| - | * other passes should not need to read in the inode information |
| - | * during the normal course of a filesystem check. (Althogh if an |
| - | * inconsistency is detected, other passes may need to read in an |
| - | * inode to fix it.) |
| - | * |
| - | * Note that pass 1B will be invoked if there are any duplicate blocks |
| - | * found. |
| - | */ |
| - | |
| - | |
| - | static int process_block(ext2_filsys fs, blk_t *blocknr, |
| - | e2_blkcnt_t blockcnt, blk_t ref_blk, |
| - | int ref_offset, void *priv_data); |
| - | static int process_bad_block(ext2_filsys fs, blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, blk_t ref_blk, |
| - | int ref_offset, void *priv_data); |
| - | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
| - | char *block_buf); |
| - | static void mark_table_blocks(e2fsck_t ctx); |
| - | static void alloc_imagic_map(e2fsck_t ctx); |
| - | static void mark_inode_bad(e2fsck_t ctx, ino_t ino); |
| - | static void handle_fs_bad_blocks(e2fsck_t ctx); |
| - | static void process_inodes(e2fsck_t ctx, char *block_buf); |
| - | static int process_inode_cmp(const void *a, const void *b); |
| - | static errcode_t scan_callback(ext2_filsys fs, |
| - | dgrp_t group, void * priv_data); |
| - | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
| - | char *block_buf, int adjust_sign); |
| - | /* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */ |
| - | |
| - | static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino, |
| - | struct ext2_inode * inode, int bufsize, |
| - | const char *proc); |
| - | |
| - | struct process_block_struct_1 { |
| - | ext2_ino_t ino; |
| - | unsigned is_dir:1, is_reg:1, clear:1, suppress:1, |
| - | fragmented:1, compressed:1, bbcheck:1; |
| - | blk_t num_blocks; |
| - | blk_t max_blocks; |
| - | e2_blkcnt_t last_block; |
| - | int num_illegal_blocks; |
| - | blk_t previous_block; |
| - | struct ext2_inode *inode; |
| - | struct problem_context *pctx; |
| - | ext2fs_block_bitmap fs_meta_blocks; |
| - | e2fsck_t ctx; |
| - | }; |
| - | |
| - | struct process_inode_block { |
| - | ext2_ino_t ino; |
| - | struct ext2_inode inode; |
| - | }; |
| - | |
| - | struct scan_callback_struct { |
| - | e2fsck_t ctx; |
| - | char *block_buf; |
| - | }; |
| - | |
| - | /* |
| - | * For the inodes to process list. |
| - | */ |
| - | static struct process_inode_block *inodes_to_process; |
| - | static int process_inode_count; |
| - | |
| - | static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE - |
| - | EXT2_MIN_BLOCK_LOG_SIZE + 1]; |
| - | |
| - | /* |
| - | * Free all memory allocated by pass1 in preparation for restarting |
| - | * things. |
| - | */ |
| - | static void unwind_pass1(void) |
| - | { |
| - | ext2fs_free_mem(&inodes_to_process); |
| - | } |
| - | |
| - | /* |
| - | * Check to make sure a device inode is real. Returns 1 if the device |
| - | * checks out, 0 if not. |
| - | * |
| - | * Note: this routine is now also used to check FIFO's and Sockets, |
| - | * since they have the same requirement; the i_block fields should be |
| - | * zero. |
| - | */ |
| - | static int |
| - | e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode) |
| - | { |
| - | int i; |
| - | |
| - | /* |
| - | * If i_blocks is non-zero, or the index flag is set, then |
| - | * this is a bogus device/fifo/socket |
| - | */ |
| - | if ((ext2fs_inode_data_blocks(fs, inode) != 0) || |
| - | (inode->i_flags & EXT2_INDEX_FL)) |
| - | return 0; |
| - | |
| - | /* |
| - | * We should be able to do the test below all the time, but |
| - | * because the kernel doesn't forcibly clear the device |
| - | * inode's additional i_block fields, there are some rare |
| - | * occasions when a legitimate device inode will have non-zero |
| - | * additional i_block fields. So for now, we only complain |
| - | * when the immutable flag is set, which should never happen |
| - | * for devices. (And that's when the problem is caused, since |
| - | * you can't set or clear immutable flags for devices.) Once |
| - | * the kernel has been fixed we can change this... |
| - | */ |
| - | if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) { |
| - | for (i=4; i < EXT2_N_BLOCKS; i++) |
| - | if (inode->i_block[i]) |
| - | return 0; |
| - | } |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * Check to make sure a symlink inode is real. Returns 1 if the symlink |
| - | * checks out, 0 if not. |
| - | */ |
| - | static int |
| - | e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf) |
| - | { |
| - | unsigned int len; |
| - | int i; |
| - | blk_t blocks; |
| - | |
| - | if ((inode->i_size_high || inode->i_size == 0) || |
| - | (inode->i_flags & EXT2_INDEX_FL)) |
| - | return 0; |
| - | |
| - | blocks = ext2fs_inode_data_blocks(fs, inode); |
| - | if (blocks) { |
| - | if ((inode->i_size >= fs->blocksize) || |
| - | (blocks != fs->blocksize >> 9) || |
| - | (inode->i_block[0] < fs->super->s_first_data_block) || |
| - | (inode->i_block[0] >= fs->super->s_blocks_count)) |
| - | return 0; |
| - | |
| - | for (i = 1; i < EXT2_N_BLOCKS; i++) |
| - | if (inode->i_block[i]) |
| - | return 0; |
| - | |
| - | if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf)) |
| - | return 0; |
| - | |
| - | len = strnlen(buf, fs->blocksize); |
| - | if (len == fs->blocksize) |
| - | return 0; |
| - | } else { |
| - | if (inode->i_size >= sizeof(inode->i_block)) |
| - | return 0; |
| - | |
| - | len = strnlen((char *)inode->i_block, sizeof(inode->i_block)); |
| - | if (len == sizeof(inode->i_block)) |
| - | return 0; |
| - | } |
| - | if (len != inode->i_size) |
| - | return 0; |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * If the immutable (or append-only) flag is set on the inode, offer |
| - | * to clear it. |
| - | */ |
| - | #define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL) |
| - | static void check_immutable(e2fsck_t ctx, struct problem_context *pctx) |
| - | { |
| - | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) |
| - | return; |
| - | |
| - | if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx)) |
| - | return; |
| - | |
| - | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; |
| - | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
| - | } |
| - | |
| - | /* |
| - | * If device, fifo or socket, check size is zero -- if not offer to |
| - | * clear it |
| - | */ |
| - | static void check_size(e2fsck_t ctx, struct problem_context *pctx) |
| - | { |
| - | struct ext2_inode *inode = pctx->inode; |
| - | |
| - | if ((inode->i_size == 0) && (inode->i_size_high == 0)) |
| - | return; |
| - | |
| - | if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) |
| - | return; |
| - | |
| - | inode->i_size = 0; |
| - | inode->i_size_high = 0; |
| - | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
| - | } |
| - | |
| - | static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | struct ext2_inode_large *inode; |
| - | struct ext2_ext_attr_entry *entry; |
| - | char *start, *end; |
| - | int storage_size, remain, offs; |
| - | int problem = 0; |
| - | |
| - | inode = (struct ext2_inode_large *) pctx->inode; |
| - | storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE - |
| - | inode->i_extra_isize; |
| - | start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + |
| - | inode->i_extra_isize + sizeof(__u32); |
| - | end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super); |
| - | entry = (struct ext2_ext_attr_entry *) start; |
| - | |
| - | /* scan all entry's headers first */ |
| - | |
| - | /* take finish entry 0UL into account */ |
| - | remain = storage_size - sizeof(__u32); |
| - | offs = end - start; |
| - | |
| - | while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { |
| - | |
| - | /* header eats this space */ |
| - | remain -= sizeof(struct ext2_ext_attr_entry); |
| - | |
| - | /* is attribute name valid? */ |
| - | if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) { |
| - | pctx->num = entry->e_name_len; |
| - | problem = PR_1_ATTR_NAME_LEN; |
| - | goto fix; |
| - | } |
| - | |
| - | /* attribute len eats this space */ |
| - | remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); |
| - | |
| - | /* check value size */ |
| - | if (entry->e_value_size == 0 || entry->e_value_size > remain) { |
| - | pctx->num = entry->e_value_size; |
| - | problem = PR_1_ATTR_VALUE_SIZE; |
| - | goto fix; |
| - | } |
| - | |
| - | /* check value placement */ |
| - | if (entry->e_value_offs + |
| - | EXT2_XATTR_SIZE(entry->e_value_size) != offs) { |
| - | printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs); |
| - | pctx->num = entry->e_value_offs; |
| - | problem = PR_1_ATTR_VALUE_OFFSET; |
| - | goto fix; |
| - | } |
| - | |
| - | /* e_value_block must be 0 in inode's ea */ |
| - | if (entry->e_value_block != 0) { |
| - | pctx->num = entry->e_value_block; |
| - | problem = PR_1_ATTR_VALUE_BLOCK; |
| - | goto fix; |
| - | } |
| - | |
| - | /* e_hash must be 0 in inode's ea */ |
| - | if (entry->e_hash != 0) { |
| - | pctx->num = entry->e_hash; |
| - | problem = PR_1_ATTR_HASH; |
| - | goto fix; |
| - | } |
| - | |
| - | remain -= entry->e_value_size; |
| - | offs -= EXT2_XATTR_SIZE(entry->e_value_size); |
| - | |
| - | entry = EXT2_EXT_ATTR_NEXT(entry); |
| - | } |
| - | fix: |
| - | /* |
| - | * it seems like a corruption. it's very unlikely we could repair |
| - | * EA(s) in automatic fashion -bzzz |
| - | */ |
| - | if (problem == 0 || !fix_problem(ctx, problem, pctx)) |
| - | return; |
| - | |
| - | /* simple remove all possible EA(s) */ |
| - | *((__u32 *)start) = 0UL; |
| - | e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode, |
| - | EXT2_INODE_SIZE(sb), "pass1"); |
| - | } |
| - | |
| - | static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | struct ext2_inode_large *inode; |
| - | __u32 *eamagic; |
| - | int min, max; |
| - | |
| - | inode = (struct ext2_inode_large *) pctx->inode; |
| - | if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) { |
| - | /* this isn't large inode. so, nothing to check */ |
| - | return; |
| - | } |
| - | |
| - | /* i_extra_isize must cover i_extra_isize + i_pad1 at least */ |
| - | min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1); |
| - | max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; |
| - | /* |
| - | * For now we will allow i_extra_isize to be 0, but really |
| - | * implementations should never allow i_extra_isize to be 0 |
| - | */ |
| - | if (inode->i_extra_isize && |
| - | (inode->i_extra_isize < min || inode->i_extra_isize > max)) { |
| - | if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx)) |
| - | return; |
| - | inode->i_extra_isize = min; |
| - | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, |
| - | EXT2_INODE_SIZE(sb), "pass1"); |
| - | return; |
| - | } |
| - | |
| - | eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + |
| - | inode->i_extra_isize); |
| - | if (*eamagic == EXT2_EXT_ATTR_MAGIC) { |
| - | /* it seems inode has an extended attribute(s) in body */ |
| - | check_ea_in_inode(ctx, pctx); |
| - | } |
| - | } |
| - | |
| - | static void e2fsck_pass1(e2fsck_t ctx) |
| - | { |
| - | int i; |
| - | __u64 max_sizes; |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t ino; |
| - | struct ext2_inode *inode; |
| - | ext2_inode_scan scan; |
| - | char *block_buf; |
| - | unsigned char frag, fsize; |
| - | struct problem_context pctx; |
| - | struct scan_callback_struct scan_struct; |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | int imagic_fs; |
| - | int busted_fs_time = 0; |
| - | int inode_size; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); |
| - | |
| - | if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && |
| - | !(ctx->options & E2F_OPT_NO)) { |
| - | if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) |
| - | ctx->dirs_to_hash = 0; |
| - | } |
| - | |
| - | /* Pass 1 */ |
| - | |
| - | #define EXT2_BPP(bits) (1ULL << ((bits) - 2)) |
| - | |
| - | for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) { |
| - | max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i); |
| - | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i); |
| - | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i); |
| - | max_sizes = (max_sizes * (1UL << i)) - 1; |
| - | ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes; |
| - | } |
| - | #undef EXT2_BPP |
| - | |
| - | imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES); |
| - | |
| - | /* |
| - | * Allocate bitmaps structures |
| - | */ |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"), |
| - | &ctx->inode_used_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 1; |
| - | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
| - | _("directory inode map"), &ctx->inode_dir_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 2; |
| - | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
| - | _("regular file inode map"), &ctx->inode_reg_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 6; |
| - | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"), |
| - | &ctx->block_found_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 1; |
| - | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, |
| - | &ctx->inode_link_info); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | inode_size = EXT2_INODE_SIZE(fs->super); |
| - | inode = (struct ext2_inode *) |
| - | e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); |
| - | |
| - | inodes_to_process = (struct process_inode_block *) |
| - | e2fsck_allocate_memory(ctx, |
| - | (ctx->process_inode_size * |
| - | sizeof(struct process_inode_block)), |
| - | "array of inodes to process"); |
| - | process_inode_count = 0; |
| - | |
| - | pctx.errcode = ext2fs_init_dblist(fs, 0); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | /* |
| - | * If the last orphan field is set, clear it, since the pass1 |
| - | * processing will automatically find and clear the orphans. |
| - | * In the future, we may want to try using the last_orphan |
| - | * linked list ourselves, but for now, we clear it so that the |
| - | * ext3 mount code won't get confused. |
| - | */ |
| - | if (!(ctx->options & E2F_OPT_READONLY)) { |
| - | if (fs->super->s_last_orphan) { |
| - | fs->super->s_last_orphan = 0; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | |
| - | mark_table_blocks(ctx); |
| - | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
| - | "block interate buffer"); |
| - | e2fsck_use_inode_shortcuts(ctx, 1); |
| - | ehandler_operation(_("doing inode scan")); |
| - | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
| - | &scan); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); |
| - | ctx->stashed_inode = inode; |
| - | scan_struct.ctx = ctx; |
| - | scan_struct.block_buf = block_buf; |
| - | ext2fs_set_inode_callback(scan, scan_callback, &scan_struct); |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count)) |
| - | return; |
| - | if ((fs->super->s_wtime < fs->super->s_inodes_count) || |
| - | (fs->super->s_mtime < fs->super->s_inodes_count)) |
| - | busted_fs_time = 1; |
| - | |
| - | while (1) { |
| - | pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, |
| - | inode, inode_size); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { |
| - | continue; |
| - | } |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if (!ino) |
| - | break; |
| - | pctx.ino = ino; |
| - | pctx.inode = inode; |
| - | ctx->stashed_ino = ino; |
| - | if (inode->i_links_count) { |
| - | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, |
| - | ino, inode->i_links_count); |
| - | if (pctx.errcode) { |
| - | pctx.num = inode->i_links_count; |
| - | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | if (ino == EXT2_BAD_INO) { |
| - | struct process_block_struct_1 pb; |
| - | |
| - | pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map, |
| - | &pb.fs_meta_blocks); |
| - | if (pctx.errcode) { |
| - | pctx.num = 4; |
| - | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | pb.ino = EXT2_BAD_INO; |
| - | pb.num_blocks = pb.last_block = 0; |
| - | pb.num_illegal_blocks = 0; |
| - | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
| - | pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0; |
| - | pb.inode = inode; |
| - | pb.pctx = &pctx; |
| - | pb.ctx = ctx; |
| - | pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, |
| - | block_buf, process_bad_block, &pb); |
| - | ext2fs_free_block_bitmap(pb.fs_meta_blocks); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if (pb.bbcheck) |
| - | if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) { |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
| - | clear_problem_context(&pctx); |
| - | continue; |
| - | } else if (ino == EXT2_ROOT_INO) { |
| - | /* |
| - | * Make sure the root inode is a directory; if |
| - | * not, offer to clear it. It will be |
| - | * regnerated in pass #3. |
| - | */ |
| - | if (!LINUX_S_ISDIR(inode->i_mode)) { |
| - | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) { |
| - | inode->i_dtime = time(NULL); |
| - | inode->i_links_count = 0; |
| - | ext2fs_icount_store(ctx->inode_link_info, |
| - | ino, 0); |
| - | e2fsck_write_inode(ctx, ino, inode, |
| - | "pass1"); |
| - | } |
| - | } |
| - | /* |
| - | * If dtime is set, offer to clear it. mke2fs |
| - | * version 0.2b created filesystems with the |
| - | * dtime field set for the root and lost+found |
| - | * directories. We won't worry about |
| - | * /lost+found, since that can be regenerated |
| - | * easily. But we will fix the root directory |
| - | * as a special case. |
| - | */ |
| - | if (inode->i_dtime && inode->i_links_count) { |
| - | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
| - | inode->i_dtime = 0; |
| - | e2fsck_write_inode(ctx, ino, inode, |
| - | "pass1"); |
| - | } |
| - | } |
| - | } else if (ino == EXT2_JOURNAL_INO) { |
| - | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
| - | if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) { |
| - | if (!LINUX_S_ISREG(inode->i_mode) && |
| - | fix_problem(ctx, PR_1_JOURNAL_BAD_MODE, |
| - | &pctx)) { |
| - | inode->i_mode = LINUX_S_IFREG; |
| - | e2fsck_write_inode(ctx, ino, inode, |
| - | "pass1"); |
| - | } |
| - | check_blocks(ctx, &pctx, block_buf); |
| - | continue; |
| - | } |
| - | if ((inode->i_links_count || inode->i_blocks || |
| - | inode->i_block[0]) && |
| - | fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, |
| - | &pctx)) { |
| - | memset(inode, 0, inode_size); |
| - | ext2fs_icount_store(ctx->inode_link_info, |
| - | ino, 0); |
| - | e2fsck_write_inode_full(ctx, ino, inode, |
| - | inode_size, "pass1"); |
| - | } |
| - | } else if (ino < EXT2_FIRST_INODE(fs->super)) { |
| - | int problem = 0; |
| - | |
| - | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
| - | if (ino == EXT2_BOOT_LOADER_INO) { |
| - | if (LINUX_S_ISDIR(inode->i_mode)) |
| - | problem = PR_1_RESERVED_BAD_MODE; |
| - | } else if (ino == EXT2_RESIZE_INO) { |
| - | if (inode->i_mode && |
| - | !LINUX_S_ISREG(inode->i_mode)) |
| - | problem = PR_1_RESERVED_BAD_MODE; |
| - | } else { |
| - | if (inode->i_mode != 0) |
| - | problem = PR_1_RESERVED_BAD_MODE; |
| - | } |
| - | if (problem) { |
| - | if (fix_problem(ctx, problem, &pctx)) { |
| - | inode->i_mode = 0; |
| - | e2fsck_write_inode(ctx, ino, inode, |
| - | "pass1"); |
| - | } |
| - | } |
| - | check_blocks(ctx, &pctx, block_buf); |
| - | continue; |
| - | } |
| - | /* |
| - | * Check for inodes who might have been part of the |
| - | * orphaned list linked list. They should have gotten |
| - | * dealt with by now, unless the list had somehow been |
| - | * corrupted. |
| - | * |
| - | * FIXME: In the future, inodes which are still in use |
| - | * (and which are therefore) pending truncation should |
| - | * be handled specially. Right now we just clear the |
| - | * dtime field, and the normal e2fsck handling of |
| - | * inodes where i_size and the inode blocks are |
| - | * inconsistent is to fix i_size, instead of releasing |
| - | * the extra blocks. This won't catch the inodes that |
| - | * was at the end of the orphan list, but it's better |
| - | * than nothing. The right answer is that there |
| - | * shouldn't be any bugs in the orphan list handling. :-) |
| - | */ |
| - | if (inode->i_dtime && !busted_fs_time && |
| - | inode->i_dtime < ctx->fs->super->s_inodes_count) { |
| - | if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { |
| - | inode->i_dtime = inode->i_links_count ? |
| - | 0 : time(NULL); |
| - | e2fsck_write_inode(ctx, ino, inode, |
| - | "pass1"); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * This code assumes that deleted inodes have |
| - | * i_links_count set to 0. |
| - | */ |
| - | if (!inode->i_links_count) { |
| - | if (!inode->i_dtime && inode->i_mode) { |
| - | if (fix_problem(ctx, |
| - | PR_1_ZERO_DTIME, &pctx)) { |
| - | inode->i_dtime = time(NULL); |
| - | e2fsck_write_inode(ctx, ino, inode, |
| - | "pass1"); |
| - | } |
| - | } |
| - | continue; |
| - | } |
| - | /* |
| - | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
| - | * deleted files. Oops. |
| - | * |
| - | * Since all new ext2 implementations get this right, |
| - | * we now assume that the case of non-zero |
| - | * i_links_count and non-zero dtime means that we |
| - | * should keep the file, not delete it. |
| - | * |
| - | */ |
| - | if (inode->i_dtime) { |
| - | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
| - | inode->i_dtime = 0; |
| - | e2fsck_write_inode(ctx, ino, inode, "pass1"); |
| - | } |
| - | } |
| - | |
| - | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
| - | switch (fs->super->s_creator_os) { |
| - | case EXT2_OS_LINUX: |
| - | frag = inode->osd2.linux2.l_i_frag; |
| - | fsize = inode->osd2.linux2.l_i_fsize; |
| - | break; |
| - | case EXT2_OS_HURD: |
| - | frag = inode->osd2.hurd2.h_i_frag; |
| - | fsize = inode->osd2.hurd2.h_i_fsize; |
| - | break; |
| - | case EXT2_OS_MASIX: |
| - | frag = inode->osd2.masix2.m_i_frag; |
| - | fsize = inode->osd2.masix2.m_i_fsize; |
| - | break; |
| - | default: |
| - | frag = fsize = 0; |
| - | } |
| - | |
| - | if (inode->i_faddr || frag || fsize || |
| - | (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl)) |
| - | mark_inode_bad(ctx, ino); |
| - | if (inode->i_flags & EXT2_IMAGIC_FL) { |
| - | if (imagic_fs) { |
| - | if (!ctx->inode_imagic_map) |
| - | alloc_imagic_map(ctx); |
| - | ext2fs_mark_inode_bitmap(ctx->inode_imagic_map, |
| - | ino); |
| - | } else { |
| - | if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) { |
| - | inode->i_flags &= ~EXT2_IMAGIC_FL; |
| - | e2fsck_write_inode(ctx, ino, |
| - | inode, "pass1"); |
| - | } |
| - | } |
| - | } |
| - | |
| - | check_inode_extra_space(ctx, &pctx); |
| - | |
| - | if (LINUX_S_ISDIR(inode->i_mode)) { |
| - | ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); |
| - | e2fsck_add_dir_info(ctx, ino, 0); |
| - | ctx->fs_directory_count++; |
| - | } else if (LINUX_S_ISREG (inode->i_mode)) { |
| - | ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino); |
| - | ctx->fs_regular_count++; |
| - | } else if (LINUX_S_ISCHR (inode->i_mode) && |
| - | e2fsck_pass1_check_device_inode(fs, inode)) { |
| - | check_immutable(ctx, &pctx); |
| - | check_size(ctx, &pctx); |
| - | ctx->fs_chardev_count++; |
| - | } else if (LINUX_S_ISBLK (inode->i_mode) && |
| - | e2fsck_pass1_check_device_inode(fs, inode)) { |
| - | check_immutable(ctx, &pctx); |
| - | check_size(ctx, &pctx); |
| - | ctx->fs_blockdev_count++; |
| - | } else if (LINUX_S_ISLNK (inode->i_mode) && |
| - | e2fsck_pass1_check_symlink(fs, inode, block_buf)) { |
| - | check_immutable(ctx, &pctx); |
| - | ctx->fs_symlinks_count++; |
| - | if (ext2fs_inode_data_blocks(fs, inode) == 0) { |
| - | ctx->fs_fast_symlinks_count++; |
| - | check_blocks(ctx, &pctx, block_buf); |
| - | continue; |
| - | } |
| - | } |
| - | else if (LINUX_S_ISFIFO (inode->i_mode) && |
| - | e2fsck_pass1_check_device_inode(fs, inode)) { |
| - | check_immutable(ctx, &pctx); |
| - | check_size(ctx, &pctx); |
| - | ctx->fs_fifo_count++; |
| - | } else if ((LINUX_S_ISSOCK (inode->i_mode)) && |
| - | e2fsck_pass1_check_device_inode(fs, inode)) { |
| - | check_immutable(ctx, &pctx); |
| - | check_size(ctx, &pctx); |
| - | ctx->fs_sockets_count++; |
| - | } else |
| - | mark_inode_bad(ctx, ino); |
| - | if (inode->i_block[EXT2_IND_BLOCK]) |
| - | ctx->fs_ind_count++; |
| - | if (inode->i_block[EXT2_DIND_BLOCK]) |
| - | ctx->fs_dind_count++; |
| - | if (inode->i_block[EXT2_TIND_BLOCK]) |
| - | ctx->fs_tind_count++; |
| - | if (inode->i_block[EXT2_IND_BLOCK] || |
| - | inode->i_block[EXT2_DIND_BLOCK] || |
| - | inode->i_block[EXT2_TIND_BLOCK] || |
| - | inode->i_file_acl) { |
| - | inodes_to_process[process_inode_count].ino = ino; |
| - | inodes_to_process[process_inode_count].inode = *inode; |
| - | process_inode_count++; |
| - | } else |
| - | check_blocks(ctx, &pctx, block_buf); |
| - | |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | |
| - | if (process_inode_count >= ctx->process_inode_size) { |
| - | process_inodes(ctx, block_buf); |
| - | |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | } |
| - | } |
| - | process_inodes(ctx, block_buf); |
| - | ext2fs_close_inode_scan(scan); |
| - | ehandler_operation(0); |
| - | |
| - | /* |
| - | * If any extended attribute blocks' reference counts need to |
| - | * be adjusted, either up (ctx->refcount_extra), or down |
| - | * (ctx->refcount), then fix them. |
| - | */ |
| - | if (ctx->refcount) { |
| - | adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1); |
| - | ea_refcount_free(ctx->refcount); |
| - | ctx->refcount = 0; |
| - | } |
| - | if (ctx->refcount_extra) { |
| - | adjust_extattr_refcount(ctx, ctx->refcount_extra, |
| - | block_buf, +1); |
| - | ea_refcount_free(ctx->refcount_extra); |
| - | ctx->refcount_extra = 0; |
| - | } |
| - | |
| - | if (ctx->invalid_bitmaps) |
| - | handle_fs_bad_blocks(ctx); |
| - | |
| - | /* We don't need the block_ea_map any more */ |
| - | ext2fs_free_block_bitmap(ctx->block_ea_map); |
| - | ctx->block_ea_map = 0; |
| - | |
| - | if (ctx->flags & E2F_FLAG_RESIZE_INODE) { |
| - | ext2fs_block_bitmap save_bmap; |
| - | |
| - | save_bmap = fs->block_map; |
| - | fs->block_map = ctx->block_found_map; |
| - | clear_problem_context(&pctx); |
| - | pctx.errcode = ext2fs_create_resize_inode(fs); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx); |
| - | /* Should never get here */ |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, |
| - | "recreate inode"); |
| - | inode->i_mtime = time(NULL); |
| - | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, |
| - | "recreate inode"); |
| - | fs->block_map = save_bmap; |
| - | ctx->flags &= ~E2F_FLAG_RESIZE_INODE; |
| - | } |
| - | |
| - | if (ctx->flags & E2F_FLAG_RESTART) { |
| - | /* |
| - | * Only the master copy of the superblock and block |
| - | * group descriptors are going to be written during a |
| - | * restart, so set the superblock to be used to be the |
| - | * master superblock. |
| - | */ |
| - | ctx->use_superblock = 0; |
| - | unwind_pass1(); |
| - | goto endit; |
| - | } |
| - | |
| - | if (ctx->block_dup_map) { |
| - | if (ctx->options & E2F_OPT_PREEN) { |
| - | clear_problem_context(&pctx); |
| - | fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); |
| - | } |
| - | e2fsck_pass1_dupblocks(ctx, block_buf); |
| - | } |
| - | ext2fs_free_mem(&inodes_to_process); |
| - | endit: |
| - | e2fsck_use_inode_shortcuts(ctx, 0); |
| - | |
| - | ext2fs_free_mem(&block_buf); |
| - | ext2fs_free_mem(&inode); |
| - | } |
| - | |
| - | /* |
| - | * When the inode_scan routines call this callback at the end of the |
| - | * glock group, call process_inodes. |
| - | */ |
| - | static errcode_t scan_callback(ext2_filsys fs, |
| - | dgrp_t group, void * priv_data) |
| - | { |
| - | struct scan_callback_struct *scan_struct; |
| - | e2fsck_t ctx; |
| - | |
| - | scan_struct = (struct scan_callback_struct *) priv_data; |
| - | ctx = scan_struct->ctx; |
| - | |
| - | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
| - | |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 1, group+1, |
| - | ctx->fs->group_desc_count)) |
| - | return EXT2_ET_CANCEL_REQUESTED; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Process the inodes in the "inodes to process" list. |
| - | */ |
| - | static void process_inodes(e2fsck_t ctx, char *block_buf) |
| - | { |
| - | int i; |
| - | struct ext2_inode *old_stashed_inode; |
| - | ext2_ino_t old_stashed_ino; |
| - | const char *old_operation; |
| - | char buf[80]; |
| - | struct problem_context pctx; |
| - | |
| - | /* begin process_inodes */ |
| - | if (process_inode_count == 0) |
| - | return; |
| - | old_operation = ehandler_operation(0); |
| - | old_stashed_inode = ctx->stashed_inode; |
| - | old_stashed_ino = ctx->stashed_ino; |
| - | qsort(inodes_to_process, process_inode_count, |
| - | sizeof(struct process_inode_block), process_inode_cmp); |
| - | clear_problem_context(&pctx); |
| - | for (i=0; i < process_inode_count; i++) { |
| - | pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; |
| - | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; |
| - | sprintf(buf, _("reading indirect blocks of inode %u"), |
| - | pctx.ino); |
| - | ehandler_operation(buf); |
| - | check_blocks(ctx, &pctx, block_buf); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | break; |
| - | } |
| - | ctx->stashed_inode = old_stashed_inode; |
| - | ctx->stashed_ino = old_stashed_ino; |
| - | process_inode_count = 0; |
| - | /* end process inodes */ |
| - | |
| - | ehandler_operation(old_operation); |
| - | } |
| - | |
| - | static int process_inode_cmp(const void *a, const void *b) |
| - | { |
| - | const struct process_inode_block *ib_a = |
| - | (const struct process_inode_block *) a; |
| - | const struct process_inode_block *ib_b = |
| - | (const struct process_inode_block *) b; |
| - | int ret; |
| - | |
| - | ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] - |
| - | ib_b->inode.i_block[EXT2_IND_BLOCK]); |
| - | if (ret == 0) |
| - | ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl; |
| - | return ret; |
| - | } |
| - | |
| - | /* |
| - | * Mark an inode as being bad in some what |
| - | */ |
| - | static void mark_inode_bad(e2fsck_t ctx, ino_t ino) |
| - | { |
| - | struct problem_context pctx; |
| - | |
| - | if (!ctx->inode_bad_map) { |
| - | clear_problem_context(&pctx); |
| - | |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, |
| - | _("bad inode map"), &ctx->inode_bad_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 3; |
| - | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | /* Should never get here */ |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * This procedure will allocate the inode imagic table |
| - | */ |
| - | static void alloc_imagic_map(e2fsck_t ctx) |
| - | { |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, |
| - | _("imagic inode map"), |
| - | &ctx->inode_imagic_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 5; |
| - | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | /* Should never get here */ |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Marks a block as in use, setting the dup_map if it's been set |
| - | * already. Called by process_block and process_bad_block. |
| - | * |
| - | * WARNING: Assumes checks have already been done to make sure block |
| - | * is valid. This is true in both process_block and process_bad_block. |
| - | */ |
| - | static void mark_block_used(e2fsck_t ctx, blk_t block) |
| - | { |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) { |
| - | if (!ctx->block_dup_map) { |
| - | pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs, |
| - | _("multiply claimed block map"), |
| - | &ctx->block_dup_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 3; |
| - | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, |
| - | &pctx); |
| - | /* Should never get here */ |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block); |
| - | } else { |
| - | ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Adjust the extended attribute block's reference counts at the end |
| - | * of pass 1, either by subtracting out references for EA blocks that |
| - | * are still referenced in ctx->refcount, or by adding references for |
| - | * EA blocks that had extra references as accounted for in |
| - | * ctx->refcount_extra. |
| - | */ |
| - | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
| - | char *block_buf, int adjust_sign) |
| - | { |
| - | struct ext2_ext_attr_header *header; |
| - | struct problem_context pctx; |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t blk; |
| - | __u32 should_be; |
| - | int count; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | ea_refcount_intr_begin(refcount); |
| - | while (1) { |
| - | if ((blk = ea_refcount_intr_next(refcount, &count)) == 0) |
| - | break; |
| - | pctx.blk = blk; |
| - | pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx); |
| - | return; |
| - | } |
| - | header = (struct ext2_ext_attr_header *) block_buf; |
| - | pctx.blkcount = header->h_refcount; |
| - | should_be = header->h_refcount + adjust_sign * count; |
| - | pctx.num = should_be; |
| - | if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) { |
| - | header->h_refcount = should_be; |
| - | pctx.errcode = ext2fs_write_ext_attr(fs, blk, |
| - | block_buf); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx); |
| - | continue; |
| - | } |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Handle processing the extended attribute blocks |
| - | */ |
| - | static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, |
| - | char *block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t ino = pctx->ino; |
| - | struct ext2_inode *inode = pctx->inode; |
| - | blk_t blk; |
| - | char * end; |
| - | struct ext2_ext_attr_header *header; |
| - | struct ext2_ext_attr_entry *entry; |
| - | int count; |
| - | region_t region; |
| - | |
| - | blk = inode->i_file_acl; |
| - | if (blk == 0) |
| - | return 0; |
| - | |
| - | /* |
| - | * If the Extended attribute flag isn't set, then a non-zero |
| - | * file acl means that the inode is corrupted. |
| - | * |
| - | * Or if the extended attribute block is an invalid block, |
| - | * then the inode is also corrupted. |
| - | */ |
| - | if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) || |
| - | (blk < fs->super->s_first_data_block) || |
| - | (blk >= fs->super->s_blocks_count)) { |
| - | mark_inode_bad(ctx, ino); |
| - | return 0; |
| - | } |
| - | |
| - | /* If ea bitmap hasn't been allocated, create it */ |
| - | if (!ctx->block_ea_map) { |
| - | pctx->errcode = ext2fs_allocate_block_bitmap(fs, |
| - | _("ext attr block map"), |
| - | &ctx->block_ea_map); |
| - | if (pctx->errcode) { |
| - | pctx->num = 2; |
| - | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return 0; |
| - | } |
| - | } |
| - | |
| - | /* Create the EA refcount structure if necessary */ |
| - | if (!ctx->refcount) { |
| - | pctx->errcode = ea_refcount_create(0, &ctx->refcount); |
| - | if (pctx->errcode) { |
| - | pctx->num = 1; |
| - | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return 0; |
| - | } |
| - | } |
| - | |
| - | /* Have we seen this EA block before? */ |
| - | if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) { |
| - | if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0) |
| - | return 1; |
| - | /* Ooops, this EA was referenced more than it stated */ |
| - | if (!ctx->refcount_extra) { |
| - | pctx->errcode = ea_refcount_create(0, |
| - | &ctx->refcount_extra); |
| - | if (pctx->errcode) { |
| - | pctx->num = 2; |
| - | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return 0; |
| - | } |
| - | } |
| - | ea_refcount_increment(ctx->refcount_extra, blk, 0); |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * OK, we haven't seen this EA block yet. So we need to |
| - | * validate it |
| - | */ |
| - | pctx->blk = blk; |
| - | pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf); |
| - | if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) |
| - | goto clear_extattr; |
| - | header = (struct ext2_ext_attr_header *) block_buf; |
| - | pctx->blk = inode->i_file_acl; |
| - | if (((ctx->ext_attr_ver == 1) && |
| - | (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) || |
| - | ((ctx->ext_attr_ver == 2) && |
| - | (header->h_magic != EXT2_EXT_ATTR_MAGIC))) { |
| - | if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | |
| - | if (header->h_blocks != 1) { |
| - | if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | |
| - | region = region_create(0, fs->blocksize); |
| - | if (!region) { |
| - | fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return 0; |
| - | } |
| - | if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) { |
| - | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | |
| - | entry = (struct ext2_ext_attr_entry *)(header+1); |
| - | end = block_buf + fs->blocksize; |
| - | while ((char *)entry < end && *(__u32 *)entry) { |
| - | if (region_allocate(region, (char *)entry - (char *)header, |
| - | EXT2_EXT_ATTR_LEN(entry->e_name_len))) { |
| - | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | if ((ctx->ext_attr_ver == 1 && |
| - | (entry->e_name_len == 0 || entry->e_name_index != 0)) || |
| - | (ctx->ext_attr_ver == 2 && |
| - | entry->e_name_index == 0)) { |
| - | if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | if (entry->e_value_block != 0) { |
| - | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | if (entry->e_value_size && |
| - | region_allocate(region, entry->e_value_offs, |
| - | EXT2_EXT_ATTR_SIZE(entry->e_value_size))) { |
| - | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | entry = EXT2_EXT_ATTR_NEXT(entry); |
| - | } |
| - | if (region_allocate(region, (char *)entry - (char *)header, 4)) { |
| - | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
| - | goto clear_extattr; |
| - | } |
| - | region_free(region); |
| - | |
| - | count = header->h_refcount - 1; |
| - | if (count) |
| - | ea_refcount_store(ctx->refcount, blk, count); |
| - | mark_block_used(ctx, blk); |
| - | ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk); |
| - | |
| - | return 1; |
| - | |
| - | clear_extattr: |
| - | inode->i_file_acl = 0; |
| - | e2fsck_write_inode(ctx, ino, inode, "check_ext_attr"); |
| - | return 0; |
| - | } |
| - | |
| - | /* Returns 1 if bad htree, 0 if OK */ |
| - | static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, |
| - | ext2_ino_t ino FSCK_ATTR((unused)), |
| - | struct ext2_inode *inode, |
| - | char *block_buf) |
| - | { |
| - | struct ext2_dx_root_info *root; |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | blk_t blk; |
| - | |
| - | if ((!LINUX_S_ISDIR(inode->i_mode) && |
| - | fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) || |
| - | (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && |
| - | fix_problem(ctx, PR_1_HTREE_SET, pctx))) |
| - | return 1; |
| - | |
| - | blk = inode->i_block[0]; |
| - | if (((blk == 0) || |
| - | (blk < fs->super->s_first_data_block) || |
| - | (blk >= fs->super->s_blocks_count)) && |
| - | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
| - | return 1; |
| - | |
| - | retval = io_channel_read_blk(fs->io, blk, 1, block_buf); |
| - | if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
| - | return 1; |
| - | |
| - | /* XXX should check that beginning matches a directory */ |
| - | root = (struct ext2_dx_root_info *) (block_buf + 24); |
| - | |
| - | if ((root->reserved_zero || root->info_length < 8) && |
| - | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
| - | return 1; |
| - | |
| - | pctx->num = root->hash_version; |
| - | if ((root->hash_version != EXT2_HASH_LEGACY) && |
| - | (root->hash_version != EXT2_HASH_HALF_MD4) && |
| - | (root->hash_version != EXT2_HASH_TEA) && |
| - | fix_problem(ctx, PR_1_HTREE_HASHV, pctx)) |
| - | return 1; |
| - | |
| - | if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) && |
| - | fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx)) |
| - | return 1; |
| - | |
| - | pctx->num = root->indirect_levels; |
| - | if ((root->indirect_levels > 1) && |
| - | fix_problem(ctx, PR_1_HTREE_DEPTH, pctx)) |
| - | return 1; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This subroutine is called on each inode to account for all of the |
| - | * blocks used by that inode. |
| - | */ |
| - | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
| - | char *block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct process_block_struct_1 pb; |
| - | ext2_ino_t ino = pctx->ino; |
| - | struct ext2_inode *inode = pctx->inode; |
| - | int bad_size = 0; |
| - | int dirty_inode = 0; |
| - | __u64 size; |
| - | |
| - | pb.ino = ino; |
| - | pb.num_blocks = 0; |
| - | pb.last_block = -1; |
| - | pb.num_illegal_blocks = 0; |
| - | pb.suppress = 0; pb.clear = 0; |
| - | pb.fragmented = 0; |
| - | pb.compressed = 0; |
| - | pb.previous_block = 0; |
| - | pb.is_dir = LINUX_S_ISDIR(inode->i_mode); |
| - | pb.is_reg = LINUX_S_ISREG(inode->i_mode); |
| - | pb.max_blocks = 1 << (31 - fs->super->s_log_block_size); |
| - | pb.inode = inode; |
| - | pb.pctx = pctx; |
| - | pb.ctx = ctx; |
| - | pctx->ino = ino; |
| - | pctx->errcode = 0; |
| - | |
| - | if (inode->i_flags & EXT2_COMPRBLK_FL) { |
| - | if (fs->super->s_feature_incompat & |
| - | EXT2_FEATURE_INCOMPAT_COMPRESSION) |
| - | pb.compressed = 1; |
| - | else { |
| - | if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { |
| - | inode->i_flags &= ~EXT2_COMPRBLK_FL; |
| - | dirty_inode++; |
| - | } |
| - | } |
| - | } |
| - | |
| - | if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf)) |
| - | pb.num_blocks++; |
| - | |
| - | if (ext2fs_inode_has_valid_blocks(inode)) |
| - | pctx->errcode = ext2fs_block_iterate2(fs, ino, |
| - | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
| - | block_buf, process_block, &pb); |
| - | end_problem_latch(ctx, PR_LATCH_BLOCK); |
| - | end_problem_latch(ctx, PR_LATCH_TOOBIG); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | goto out; |
| - | if (pctx->errcode) |
| - | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); |
| - | |
| - | if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) |
| - | ctx->fs_fragmented++; |
| - | |
| - | if (pb.clear) { |
| - | inode->i_links_count = 0; |
| - | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
| - | inode->i_dtime = time(NULL); |
| - | dirty_inode++; |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); |
| - | /* |
| - | * The inode was probably partially accounted for |
| - | * before processing was aborted, so we need to |
| - | * restart the pass 1 scan. |
| - | */ |
| - | ctx->flags |= E2F_FLAG_RESTART; |
| - | goto out; |
| - | } |
| - | |
| - | if (inode->i_flags & EXT2_INDEX_FL) { |
| - | if (handle_htree(ctx, pctx, ino, inode, block_buf)) { |
| - | inode->i_flags &= ~EXT2_INDEX_FL; |
| - | dirty_inode++; |
| - | } else { |
| - | #ifdef ENABLE_HTREE |
| - | e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); |
| - | #endif |
| - | } |
| - | } |
| - | if (ctx->dirs_to_hash && pb.is_dir && |
| - | !(inode->i_flags & EXT2_INDEX_FL) && |
| - | ((inode->i_size / fs->blocksize) >= 3)) |
| - | ext2fs_u32_list_add(ctx->dirs_to_hash, ino); |
| - | |
| - | if (!pb.num_blocks && pb.is_dir) { |
| - | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
| - | inode->i_links_count = 0; |
| - | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
| - | inode->i_dtime = time(NULL); |
| - | dirty_inode++; |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); |
| - | ctx->fs_directory_count--; |
| - | goto out; |
| - | } |
| - | } |
| - | |
| - | pb.num_blocks *= (fs->blocksize / 512); |
| - | |
| - | if (pb.is_dir) { |
| - | int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); |
| - | if (nblock > (pb.last_block + 1)) |
| - | bad_size = 1; |
| - | else if (nblock < (pb.last_block + 1)) { |
| - | if (((pb.last_block + 1) - nblock) > |
| - | fs->super->s_prealloc_dir_blocks) |
| - | bad_size = 2; |
| - | } |
| - | } else { |
| - | size = EXT2_I_SIZE(inode); |
| - | if ((pb.last_block >= 0) && |
| - | (size < (__u64) pb.last_block * fs->blocksize)) |
| - | bad_size = 3; |
| - | else if (size > ext2_max_sizes[fs->super->s_log_block_size]) |
| - | bad_size = 4; |
| - | } |
| - | /* i_size for symlinks is checked elsewhere */ |
| - | if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) { |
| - | pctx->num = (pb.last_block+1) * fs->blocksize; |
| - | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
| - | inode->i_size = pctx->num; |
| - | if (!LINUX_S_ISDIR(inode->i_mode)) |
| - | inode->i_size_high = pctx->num >> 32; |
| - | dirty_inode++; |
| - | } |
| - | pctx->num = 0; |
| - | } |
| - | if (LINUX_S_ISREG(inode->i_mode) && |
| - | (inode->i_size_high || inode->i_size & 0x80000000UL)) |
| - | ctx->large_files++; |
| - | if (pb.num_blocks != inode->i_blocks) { |
| - | pctx->num = pb.num_blocks; |
| - | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
| - | inode->i_blocks = pb.num_blocks; |
| - | dirty_inode++; |
| - | } |
| - | pctx->num = 0; |
| - | } |
| - | out: |
| - | if (dirty_inode) |
| - | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * This is a helper function for check_blocks(). |
| - | */ |
| - | static int process_block(ext2_filsys fs, |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct process_block_struct_1 *p; |
| - | struct problem_context *pctx; |
| - | blk_t blk = *block_nr; |
| - | int ret_code = 0; |
| - | int problem = 0; |
| - | e2fsck_t ctx; |
| - | |
| - | p = (struct process_block_struct_1 *) priv_data; |
| - | pctx = p->pctx; |
| - | ctx = p->ctx; |
| - | |
| - | if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) { |
| - | /* todo: Check that the comprblk_fl is high, that the |
| - | blkaddr pattern looks right (all non-holes up to |
| - | first EXT2FS_COMPRESSED_BLKADDR, then all |
| - | EXT2FS_COMPRESSED_BLKADDR up to end of cluster), |
| - | that the feature_incompat bit is high, and that the |
| - | inode is a regular file. If we're doing a "full |
| - | check" (a concept introduced to e2fsck by e2compr, |
| - | meaning that we look at data blocks as well as |
| - | metadata) then call some library routine that |
| - | checks the compressed data. I'll have to think |
| - | about this, because one particularly important |
| - | problem to be able to fix is to recalculate the |
| - | cluster size if necessary. I think that perhaps |
| - | we'd better do most/all e2compr-specific checks |
| - | separately, after the non-e2compr checks. If not |
| - | doing a full check, it may be useful to test that |
| - | the personality is linux; e.g. if it isn't then |
| - | perhaps this really is just an illegal block. */ |
| - | return 0; |
| - | } |
| - | |
| - | if (blk == 0) { |
| - | if (p->is_dir == 0) { |
| - | /* |
| - | * Should never happen, since only directories |
| - | * get called with BLOCK_FLAG_HOLE |
| - | */ |
| - | #ifdef DEBUG_E2FSCK |
| - | printf("process_block() called with blk == 0, " |
| - | "blockcnt=%d, inode %lu???\n", |
| - | blockcnt, p->ino); |
| - | #endif |
| - | return 0; |
| - | } |
| - | if (blockcnt < 0) |
| - | return 0; |
| - | if (blockcnt * fs->blocksize < p->inode->i_size) { |
| - | goto mark_dir; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Simplistic fragmentation check. We merely require that the |
| - | * file be contiguous. (Which can never be true for really |
| - | * big files that are greater than a block group.) |
| - | */ |
| - | if (!HOLE_BLKADDR(p->previous_block)) { |
| - | if (p->previous_block+1 != blk) |
| - | p->fragmented = 1; |
| - | } |
| - | p->previous_block = blk; |
| - | |
| - | if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size))) |
| - | problem = PR_1_TOOBIG_DIR; |
| - | if (p->is_reg && p->num_blocks+1 >= p->max_blocks) |
| - | problem = PR_1_TOOBIG_REG; |
| - | if (!p->is_dir && !p->is_reg && blockcnt > 0) |
| - | problem = PR_1_TOOBIG_SYMLINK; |
| - | |
| - | if (blk < fs->super->s_first_data_block || |
| - | blk >= fs->super->s_blocks_count) |
| - | problem = PR_1_ILLEGAL_BLOCK_NUM; |
| - | |
| - | if (problem) { |
| - | p->num_illegal_blocks++; |
| - | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
| - | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
| - | p->clear = 1; |
| - | return BLOCK_ABORT; |
| - | } |
| - | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
| - | p->suppress = 1; |
| - | set_latch_flags(PR_LATCH_BLOCK, |
| - | PRL_SUPPRESS, 0); |
| - | } |
| - | } |
| - | pctx->blk = blk; |
| - | pctx->blkcount = blockcnt; |
| - | if (fix_problem(ctx, problem, pctx)) { |
| - | blk = *block_nr = 0; |
| - | ret_code = BLOCK_CHANGED; |
| - | goto mark_dir; |
| - | } else |
| - | return 0; |
| - | } |
| - | |
| - | if (p->ino == EXT2_RESIZE_INO) { |
| - | /* |
| - | * The resize inode has already be sanity checked |
| - | * during pass #0 (the superblock checks). All we |
| - | * have to do is mark the double indirect block as |
| - | * being in use; all of the other blocks are handled |
| - | * by mark_table_blocks()). |
| - | */ |
| - | if (blockcnt == BLOCK_COUNT_DIND) |
| - | mark_block_used(ctx, blk); |
| - | } else |
| - | mark_block_used(ctx, blk); |
| - | p->num_blocks++; |
| - | if (blockcnt >= 0) |
| - | p->last_block = blockcnt; |
| - | mark_dir: |
| - | if (p->is_dir && (blockcnt >= 0)) { |
| - | pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino, |
| - | blk, blockcnt); |
| - | if (pctx->errcode) { |
| - | pctx->blk = blk; |
| - | pctx->num = blockcnt; |
| - | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
| - | /* Should never get here */ |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return BLOCK_ABORT; |
| - | } |
| - | } |
| - | return ret_code; |
| - | } |
| - | |
| - | static int process_bad_block(ext2_filsys fs FSCK_ATTR((unused)), |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data EXT2FS_ATTR((unused))) |
| - | { |
| - | /* |
| - | * Note: This function processes blocks for the bad blocks |
| - | * inode, which is never compressed. So we don't use HOLE_BLKADDR(). |
| - | */ |
| - | |
| - | printf("Unrecoverable Error: Found %"PRIi64" bad blocks starting at block number: %u\n", blockcnt, *block_nr); |
| - | return BLOCK_ERROR; |
| - | } |
| - | |
| - | /* |
| - | * This routine gets called at the end of pass 1 if bad blocks are |
| - | * detected in the superblock, group descriptors, inode_bitmaps, or |
| - | * block bitmaps. At this point, all of the blocks have been mapped |
| - | * out, so we can try to allocate new block(s) to replace the bad |
| - | * blocks. |
| - | */ |
| - | static void handle_fs_bad_blocks(e2fsck_t ctx) |
| - | { |
| - | printf("Bad blocks detected on your filesystem\n" |
| - | "You should get your data off as the device will soon die\n"); |
| - | } |
| - | |
| - | /* |
| - | * This routine marks all blocks which are used by the superblock, |
| - | * group descriptors, inode bitmaps, and block bitmaps. |
| - | */ |
| - | static void mark_table_blocks(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t block, b; |
| - | dgrp_t i; |
| - | int j; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | block = fs->super->s_first_data_block; |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | pctx.group = i; |
| - | |
| - | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map); |
| - | |
| - | /* |
| - | * Mark the blocks used for the inode table |
| - | */ |
| - | if (fs->group_desc[i].bg_inode_table) { |
| - | for (j = 0, b = fs->group_desc[i].bg_inode_table; |
| - | j < fs->inode_blocks_per_group; |
| - | j++, b++) { |
| - | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
| - | b)) { |
| - | pctx.blk = b; |
| - | if (fix_problem(ctx, |
| - | PR_1_ITABLE_CONFLICT, &pctx)) { |
| - | ctx->invalid_inode_table_flag[i]++; |
| - | ctx->invalid_bitmaps++; |
| - | } |
| - | } else { |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, b); |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Mark block used for the block bitmap |
| - | */ |
| - | if (fs->group_desc[i].bg_block_bitmap) { |
| - | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
| - | fs->group_desc[i].bg_block_bitmap)) { |
| - | pctx.blk = fs->group_desc[i].bg_block_bitmap; |
| - | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
| - | ctx->invalid_block_bitmap_flag[i]++; |
| - | ctx->invalid_bitmaps++; |
| - | } |
| - | } else { |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, |
| - | fs->group_desc[i].bg_block_bitmap); |
| - | } |
| - | } |
| - | /* |
| - | * Mark block used for the inode bitmap |
| - | */ |
| - | if (fs->group_desc[i].bg_inode_bitmap) { |
| - | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
| - | fs->group_desc[i].bg_inode_bitmap)) { |
| - | pctx.blk = fs->group_desc[i].bg_inode_bitmap; |
| - | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
| - | ctx->invalid_inode_bitmap_flag[i]++; |
| - | ctx->invalid_bitmaps++; |
| - | } |
| - | } else { |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, |
| - | fs->group_desc[i].bg_inode_bitmap); |
| - | } |
| - | } |
| - | block += fs->super->s_blocks_per_group; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Thes subroutines short circuits ext2fs_get_blocks and |
| - | * ext2fs_check_directory; we use them since we already have the inode |
| - | * structure, so there's no point in letting the ext2fs library read |
| - | * the inode again. |
| - | */ |
| - | static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino, |
| - | blk_t *blocks) |
| - | { |
| - | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
| - | int i; |
| - | |
| - | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
| - | return EXT2_ET_CALLBACK_NOTHANDLED; |
| - | |
| - | for (i=0; i < EXT2_N_BLOCKS; i++) |
| - | blocks[i] = ctx->stashed_inode->i_block[i]; |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino, |
| - | struct ext2_inode *inode) |
| - | { |
| - | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
| - | |
| - | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
| - | return EXT2_ET_CALLBACK_NOTHANDLED; |
| - | *inode = *ctx->stashed_inode; |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino, |
| - | struct ext2_inode *inode) |
| - | { |
| - | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
| - | |
| - | if ((ino == ctx->stashed_ino) && ctx->stashed_inode) |
| - | *ctx->stashed_inode = *inode; |
| - | return EXT2_ET_CALLBACK_NOTHANDLED; |
| - | } |
| - | |
| - | static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino) |
| - | { |
| - | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
| - | |
| - | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
| - | return EXT2_ET_CALLBACK_NOTHANDLED; |
| - | |
| - | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) |
| - | return EXT2_ET_NO_DIRECTORY; |
| - | return 0; |
| - | } |
| - | |
| - | void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | |
| - | if (bool) { |
| - | fs->get_blocks = pass1_get_blocks; |
| - | fs->check_directory = pass1_check_directory; |
| - | fs->read_inode = pass1_read_inode; |
| - | fs->write_inode = pass1_write_inode; |
| - | ctx->stashed_ino = 0; |
| - | } else { |
| - | fs->get_blocks = 0; |
| - | fs->check_directory = 0; |
| - | fs->read_inode = 0; |
| - | fs->write_inode = 0; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * pass1b.c --- Pass #1b of e2fsck |
| - | * |
| - | * This file contains pass1B, pass1C, and pass1D of e2fsck. They are |
| - | * only invoked if pass 1 discovered blocks which are in use by more |
| - | * than one inode. |
| - | * |
| - | * Pass1B scans the data blocks of all the inodes again, generating a |
| - | * complete list of duplicate blocks and which inodes have claimed |
| - | * them. |
| - | * |
| - | * Pass1C does a tree-traversal of the filesystem, to determine the |
| - | * parent directories of these inodes. This step is necessary so that |
| - | * e2fsck can print out the pathnames of affected inodes. |
| - | * |
| - | * Pass1D is a reconciliation pass. For each inode with duplicate |
| - | * blocks, the user is prompted if s/he would like to clone the file |
| - | * (so that the file gets a fresh copy of the duplicated blocks) or |
| - | * simply to delete the file. |
| - | * |
| - | */ |
| - | |
| - | |
| - | /* Needed for architectures where sizeof(int) != sizeof(void *) */ |
| - | #define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) |
| - | #define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr)) |
| - | |
| - | /* Define an extension to the ext2 library's block count information */ |
| - | #define BLOCK_COUNT_EXTATTR (-5) |
| - | |
| - | struct block_el { |
| - | blk_t block; |
| - | struct block_el *next; |
| - | }; |
| - | |
| - | struct inode_el { |
| - | ext2_ino_t inode; |
| - | struct inode_el *next; |
| - | }; |
| - | |
| - | struct dup_block { |
| - | int num_bad; |
| - | struct inode_el *inode_list; |
| - | }; |
| - | |
| - | /* |
| - | * This structure stores information about a particular inode which |
| - | * is sharing blocks with other inodes. This information is collected |
| - | * to display to the user, so that the user knows what files he or she |
| - | * is dealing with, when trying to decide how to resolve the conflict |
| - | * of multiply-claimed blocks. |
| - | */ |
| - | struct dup_inode { |
| - | ext2_ino_t dir; |
| - | int num_dupblocks; |
| - | struct ext2_inode inode; |
| - | struct block_el *block_list; |
| - | }; |
| - | |
| - | static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr, |
| - | e2_blkcnt_t blockcnt, blk_t ref_blk, |
| - | int ref_offset, void *priv_data); |
| - | static void delete_file(e2fsck_t ctx, ext2_ino_t ino, |
| - | struct dup_inode *dp, char *block_buf); |
| - | static int clone_file(e2fsck_t ctx, ext2_ino_t ino, |
| - | struct dup_inode *dp, char* block_buf); |
| - | static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk); |
| - | |
| - | static void pass1b(e2fsck_t ctx, char *block_buf); |
| - | static void pass1c(e2fsck_t ctx, char *block_buf); |
| - | static void pass1d(e2fsck_t ctx, char *block_buf); |
| - | |
| - | static int dup_inode_count = 0; |
| - | |
| - | static dict_t blk_dict, ino_dict; |
| - | |
| - | static ext2fs_inode_bitmap inode_dup_map; |
| - | |
| - | static int dict_int_cmp(const void *a, const void *b) |
| - | { |
| - | intptr_t ia, ib; |
| - | |
| - | ia = (intptr_t)a; |
| - | ib = (intptr_t)b; |
| - | |
| - | return (ia-ib); |
| - | } |
| - | |
| - | /* |
| - | * Add a duplicate block record |
| - | */ |
| - | static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk, |
| - | struct ext2_inode *inode) |
| - | { |
| - | dnode_t *n; |
| - | struct dup_block *db; |
| - | struct dup_inode *di; |
| - | struct block_el *blk_el; |
| - | struct inode_el *ino_el; |
| - | |
| - | n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk)); |
| - | if (n) |
| - | db = (struct dup_block *) dnode_get(n); |
| - | else { |
| - | db = (struct dup_block *) e2fsck_allocate_memory(ctx, |
| - | sizeof(struct dup_block), "duplicate block header"); |
| - | db->num_bad = 0; |
| - | db->inode_list = 0; |
| - | dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db); |
| - | } |
| - | ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx, |
| - | sizeof(struct inode_el), "inode element"); |
| - | ino_el->inode = ino; |
| - | ino_el->next = db->inode_list; |
| - | db->inode_list = ino_el; |
| - | db->num_bad++; |
| - | |
| - | n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino)); |
| - | if (n) |
| - | di = (struct dup_inode *) dnode_get(n); |
| - | else { |
| - | di = (struct dup_inode *) e2fsck_allocate_memory(ctx, |
| - | sizeof(struct dup_inode), "duplicate inode header"); |
| - | di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0; |
| - | di->num_dupblocks = 0; |
| - | di->block_list = 0; |
| - | di->inode = *inode; |
| - | dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di); |
| - | } |
| - | blk_el = (struct block_el *) e2fsck_allocate_memory(ctx, |
| - | sizeof(struct block_el), "block element"); |
| - | blk_el->block = blk; |
| - | blk_el->next = di->block_list; |
| - | di->block_list = blk_el; |
| - | di->num_dupblocks++; |
| - | } |
| - | |
| - | /* |
| - | * Free a duplicate inode record |
| - | */ |
| - | static void inode_dnode_free(dnode_t *node) |
| - | { |
| - | struct dup_inode *di; |
| - | struct block_el *p, *next; |
| - | |
| - | di = (struct dup_inode *) dnode_get(node); |
| - | for (p = di->block_list; p; p = next) { |
| - | next = p->next; |
| - | free(p); |
| - | } |
| - | free(node); |
| - | } |
| - | |
| - | /* |
| - | * Free a duplicate block record |
| - | */ |
| - | static void block_dnode_free(dnode_t *node) |
| - | { |
| - | struct dup_block *db; |
| - | struct inode_el *p, *next; |
| - | |
| - | db = (struct dup_block *) dnode_get(node); |
| - | for (p = db->inode_list; p; p = next) { |
| - | next = p->next; |
| - | free(p); |
| - | } |
| - | free(node); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Main procedure for handling duplicate blocks |
| - | */ |
| - | void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
| - | _("multiply claimed inode map"), &inode_dup_map); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp); |
| - | dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp); |
| - | dict_set_allocator(&ino_dict, inode_dnode_free); |
| - | dict_set_allocator(&blk_dict, block_dnode_free); |
| - | |
| - | pass1b(ctx, block_buf); |
| - | pass1c(ctx, block_buf); |
| - | pass1d(ctx, block_buf); |
| - | |
| - | /* |
| - | * Time to free all of the accumulated data structures that we |
| - | * don't need anymore. |
| - | */ |
| - | dict_free_nodes(&ino_dict); |
| - | dict_free_nodes(&blk_dict); |
| - | } |
| - | |
| - | /* |
| - | * Scan the inodes looking for inodes that contain duplicate blocks. |
| - | */ |
| - | struct process_block_struct_1b { |
| - | e2fsck_t ctx; |
| - | ext2_ino_t ino; |
| - | int dup_blocks; |
| - | struct ext2_inode *inode; |
| - | struct problem_context *pctx; |
| - | }; |
| - | |
| - | static void pass1b(e2fsck_t ctx, char *block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t ino; |
| - | struct ext2_inode inode; |
| - | ext2_inode_scan scan; |
| - | struct process_block_struct_1b pb; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_1B_PASS_HEADER, &pctx); |
| - | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
| - | &scan); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ctx->stashed_inode = &inode; |
| - | pb.ctx = ctx; |
| - | pb.pctx = &pctx; |
| - | pctx.str = "pass1b"; |
| - | while (1) { |
| - | pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); |
| - | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) |
| - | continue; |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if (!ino) |
| - | break; |
| - | pctx.ino = ctx->stashed_ino = ino; |
| - | if ((ino != EXT2_BAD_INO) && |
| - | !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)) |
| - | continue; |
| - | |
| - | pb.ino = ino; |
| - | pb.dup_blocks = 0; |
| - | pb.inode = &inode; |
| - | |
| - | if (ext2fs_inode_has_valid_blocks(&inode) || |
| - | (ino == EXT2_BAD_INO)) |
| - | pctx.errcode = ext2fs_block_iterate2(fs, ino, |
| - | 0, block_buf, process_pass1b_block, &pb); |
| - | if (inode.i_file_acl) |
| - | process_pass1b_block(fs, &inode.i_file_acl, |
| - | BLOCK_COUNT_EXTATTR, 0, 0, &pb); |
| - | if (pb.dup_blocks) { |
| - | end_problem_latch(ctx, PR_LATCH_DBLOCK); |
| - | if (ino >= EXT2_FIRST_INODE(fs->super) || |
| - | ino == EXT2_ROOT_INO) |
| - | dup_inode_count++; |
| - | } |
| - | if (pctx.errcode) |
| - | fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); |
| - | } |
| - | ext2fs_close_inode_scan(scan); |
| - | e2fsck_use_inode_shortcuts(ctx, 0); |
| - | } |
| - | |
| - | static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)), |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt FSCK_ATTR((unused)), |
| - | blk_t ref_blk FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct process_block_struct_1b *p; |
| - | e2fsck_t ctx; |
| - | |
| - | if (HOLE_BLKADDR(*block_nr)) |
| - | return 0; |
| - | p = (struct process_block_struct_1b *) priv_data; |
| - | ctx = p->ctx; |
| - | |
| - | if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) |
| - | return 0; |
| - | |
| - | /* OK, this is a duplicate block */ |
| - | if (p->ino != EXT2_BAD_INO) { |
| - | p->pctx->blk = *block_nr; |
| - | fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx); |
| - | } |
| - | p->dup_blocks++; |
| - | ext2fs_mark_inode_bitmap(inode_dup_map, p->ino); |
| - | |
| - | add_dupe(ctx, p->ino, *block_nr, p->inode); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Pass 1c: Scan directories for inodes with duplicate blocks. This |
| - | * is used so that we can print pathnames when prompting the user for |
| - | * what to do. |
| - | */ |
| - | struct search_dir_struct { |
| - | int count; |
| - | ext2_ino_t first_inode; |
| - | ext2_ino_t max_inode; |
| - | }; |
| - | |
| - | static int search_dirent_proc(ext2_ino_t dir, int entry, |
| - | struct ext2_dir_entry *dirent, |
| - | int offset FSCK_ATTR((unused)), |
| - | int blocksize FSCK_ATTR((unused)), |
| - | char *buf FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct search_dir_struct *sd; |
| - | struct dup_inode *p; |
| - | dnode_t *n; |
| - | |
| - | sd = (struct search_dir_struct *) priv_data; |
| - | |
| - | if (dirent->inode > sd->max_inode) |
| - | /* Should abort this inode, but not everything */ |
| - | return 0; |
| - | |
| - | if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) || |
| - | !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode)) |
| - | return 0; |
| - | |
| - | n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode)); |
| - | if (!n) |
| - | return 0; |
| - | p = (struct dup_inode *) dnode_get(n); |
| - | p->dir = dir; |
| - | sd->count--; |
| - | |
| - | return sd->count ? 0 : DIRENT_ABORT; |
| - | } |
| - | |
| - | |
| - | static void pass1c(e2fsck_t ctx, char *block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct search_dir_struct sd; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_1C_PASS_HEADER, &pctx); |
| - | |
| - | /* |
| - | * Search through all directories to translate inodes to names |
| - | * (by searching for the containing directory for that inode.) |
| - | */ |
| - | sd.count = dup_inode_count; |
| - | sd.first_inode = EXT2_FIRST_INODE(fs->super); |
| - | sd.max_inode = fs->super->s_inodes_count; |
| - | ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf, |
| - | search_dirent_proc, &sd); |
| - | } |
| - | |
| - | static void pass1d(e2fsck_t ctx, char *block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct dup_inode *p, *t; |
| - | struct dup_block *q; |
| - | ext2_ino_t *shared, ino; |
| - | int shared_len; |
| - | int i; |
| - | int file_ok; |
| - | int meta_data = 0; |
| - | struct problem_context pctx; |
| - | dnode_t *n, *m; |
| - | struct block_el *s; |
| - | struct inode_el *r; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_1D_PASS_HEADER, &pctx); |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | pctx.num = dup_inode_count; /* dict_count(&ino_dict); */ |
| - | fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx); |
| - | shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx, |
| - | sizeof(ext2_ino_t) * dict_count(&ino_dict), |
| - | "Shared inode list"); |
| - | for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) { |
| - | p = (struct dup_inode *) dnode_get(n); |
| - | shared_len = 0; |
| - | file_ok = 1; |
| - | ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n)); |
| - | if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO) |
| - | continue; |
| - | |
| - | /* |
| - | * Find all of the inodes which share blocks with this |
| - | * one. First we find all of the duplicate blocks |
| - | * belonging to this inode, and then search each block |
| - | * get the list of inodes, and merge them together. |
| - | */ |
| - | for (s = p->block_list; s; s = s->next) { |
| - | m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block)); |
| - | if (!m) |
| - | continue; /* Should never happen... */ |
| - | q = (struct dup_block *) dnode_get(m); |
| - | if (q->num_bad > 1) |
| - | file_ok = 0; |
| - | if (check_if_fs_block(ctx, s->block)) { |
| - | file_ok = 0; |
| - | meta_data = 1; |
| - | } |
| - | |
| - | /* |
| - | * Add all inodes used by this block to the |
| - | * shared[] --- which is a unique list, so |
| - | * if an inode is already in shared[], don't |
| - | * add it again. |
| - | */ |
| - | for (r = q->inode_list; r; r = r->next) { |
| - | if (r->inode == ino) |
| - | continue; |
| - | for (i = 0; i < shared_len; i++) |
| - | if (shared[i] == r->inode) |
| - | break; |
| - | if (i == shared_len) { |
| - | shared[shared_len++] = r->inode; |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Report the inode that we are working on |
| - | */ |
| - | pctx.inode = &p->inode; |
| - | pctx.ino = ino; |
| - | pctx.dir = p->dir; |
| - | pctx.blkcount = p->num_dupblocks; |
| - | pctx.num = meta_data ? shared_len+1 : shared_len; |
| - | fix_problem(ctx, PR_1D_DUP_FILE, &pctx); |
| - | pctx.blkcount = 0; |
| - | pctx.num = 0; |
| - | |
| - | if (meta_data) |
| - | fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx); |
| - | |
| - | for (i = 0; i < shared_len; i++) { |
| - | m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i])); |
| - | if (!m) |
| - | continue; /* should never happen */ |
| - | t = (struct dup_inode *) dnode_get(m); |
| - | /* |
| - | * Report the inode that we are sharing with |
| - | */ |
| - | pctx.inode = &t->inode; |
| - | pctx.ino = shared[i]; |
| - | pctx.dir = t->dir; |
| - | fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx); |
| - | } |
| - | if (file_ok) { |
| - | fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx); |
| - | continue; |
| - | } |
| - | if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) { |
| - | pctx.errcode = clone_file(ctx, ino, p, block_buf); |
| - | if (pctx.errcode) |
| - | fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx); |
| - | else |
| - | continue; |
| - | } |
| - | if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx)) |
| - | delete_file(ctx, ino, p, block_buf); |
| - | else |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | ext2fs_free_mem(&shared); |
| - | } |
| - | |
| - | /* |
| - | * Drop the refcount on the dup_block structure, and clear the entry |
| - | * in the block_dup_map if appropriate. |
| - | */ |
| - | static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p) |
| - | { |
| - | p->num_bad--; |
| - | if (p->num_bad <= 0 || |
| - | (p->num_bad == 1 && !check_if_fs_block(ctx, block))) |
| - | ext2fs_unmark_block_bitmap(ctx->block_dup_map, block); |
| - | } |
| - | |
| - | static int delete_file_block(ext2_filsys fs, |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt FSCK_ATTR((unused)), |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct process_block_struct_1b *pb; |
| - | struct dup_block *p; |
| - | dnode_t *n; |
| - | e2fsck_t ctx; |
| - | |
| - | pb = (struct process_block_struct_1b *) priv_data; |
| - | ctx = pb->ctx; |
| - | |
| - | if (HOLE_BLKADDR(*block_nr)) |
| - | return 0; |
| - | |
| - | if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) { |
| - | n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr)); |
| - | if (n) { |
| - | p = (struct dup_block *) dnode_get(n); |
| - | decrement_badcount(ctx, *block_nr, p); |
| - | } else |
| - | bb_error_msg(_("internal error; can't find dup_blk for %d"), |
| - | *block_nr); |
| - | } else { |
| - | ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); |
| - | ext2fs_block_alloc_stats(fs, *block_nr, -1); |
| - | } |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static void delete_file(e2fsck_t ctx, ext2_ino_t ino, |
| - | struct dup_inode *dp, char* block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct process_block_struct_1b pb; |
| - | struct ext2_inode inode; |
| - | struct problem_context pctx; |
| - | unsigned int count; |
| - | |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = pb.ino = ino; |
| - | pb.dup_blocks = dp->num_dupblocks; |
| - | pb.ctx = ctx; |
| - | pctx.str = "delete_file"; |
| - | |
| - | e2fsck_read_inode(ctx, ino, &inode, "delete_file"); |
| - | if (ext2fs_inode_has_valid_blocks(&inode)) |
| - | pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, |
| - | delete_file_block, &pb); |
| - | if (pctx.errcode) |
| - | fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
| - | if (ctx->inode_bad_map) |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); |
| - | ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); |
| - | |
| - | /* Inode may have changed by block_iterate, so reread it */ |
| - | e2fsck_read_inode(ctx, ino, &inode, "delete_file"); |
| - | inode.i_links_count = 0; |
| - | inode.i_dtime = time(NULL); |
| - | if (inode.i_file_acl && |
| - | (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { |
| - | count = 1; |
| - | pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl, |
| - | block_buf, -1, &count); |
| - | if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { |
| - | pctx.errcode = 0; |
| - | count = 1; |
| - | } |
| - | if (pctx.errcode) { |
| - | pctx.blk = inode.i_file_acl; |
| - | fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx); |
| - | } |
| - | /* |
| - | * If the count is zero, then arrange to have the |
| - | * block deleted. If the block is in the block_dup_map, |
| - | * also call delete_file_block since it will take care |
| - | * of keeping the accounting straight. |
| - | */ |
| - | if ((count == 0) || |
| - | ext2fs_test_block_bitmap(ctx->block_dup_map, |
| - | inode.i_file_acl)) |
| - | delete_file_block(fs, &inode.i_file_acl, |
| - | BLOCK_COUNT_EXTATTR, 0, 0, &pb); |
| - | } |
| - | e2fsck_write_inode(ctx, ino, &inode, "delete_file"); |
| - | } |
| - | |
| - | struct clone_struct { |
| - | errcode_t errcode; |
| - | ext2_ino_t dir; |
| - | char *buf; |
| - | e2fsck_t ctx; |
| - | }; |
| - | |
| - | static int clone_file_block(ext2_filsys fs, |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct dup_block *p; |
| - | blk_t new_block; |
| - | errcode_t retval; |
| - | struct clone_struct *cs = (struct clone_struct *) priv_data; |
| - | dnode_t *n; |
| - | e2fsck_t ctx; |
| - | |
| - | ctx = cs->ctx; |
| - | |
| - | if (HOLE_BLKADDR(*block_nr)) |
| - | return 0; |
| - | |
| - | if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) { |
| - | n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr)); |
| - | if (n) { |
| - | p = (struct dup_block *) dnode_get(n); |
| - | retval = ext2fs_new_block(fs, 0, ctx->block_found_map, |
| - | &new_block); |
| - | if (retval) { |
| - | cs->errcode = retval; |
| - | return BLOCK_ABORT; |
| - | } |
| - | if (cs->dir && (blockcnt >= 0)) { |
| - | retval = ext2fs_set_dir_block(fs->dblist, |
| - | cs->dir, new_block, blockcnt); |
| - | if (retval) { |
| - | cs->errcode = retval; |
| - | return BLOCK_ABORT; |
| - | } |
| - | } |
| - | |
| - | retval = io_channel_read_blk(fs->io, *block_nr, 1, |
| - | cs->buf); |
| - | if (retval) { |
| - | cs->errcode = retval; |
| - | return BLOCK_ABORT; |
| - | } |
| - | retval = io_channel_write_blk(fs->io, new_block, 1, |
| - | cs->buf); |
| - | if (retval) { |
| - | cs->errcode = retval; |
| - | return BLOCK_ABORT; |
| - | } |
| - | decrement_badcount(ctx, *block_nr, p); |
| - | *block_nr = new_block; |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, |
| - | new_block); |
| - | ext2fs_mark_block_bitmap(fs->block_map, new_block); |
| - | return BLOCK_CHANGED; |
| - | } else |
| - | bb_error_msg(_("internal error; can't find dup_blk for %d"), |
| - | *block_nr); |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static int clone_file(e2fsck_t ctx, ext2_ino_t ino, |
| - | struct dup_inode *dp, char* block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | struct clone_struct cs; |
| - | struct problem_context pctx; |
| - | blk_t blk; |
| - | dnode_t *n; |
| - | struct inode_el *ino_el; |
| - | struct dup_block *db; |
| - | struct dup_inode *di; |
| - | |
| - | clear_problem_context(&pctx); |
| - | cs.errcode = 0; |
| - | cs.dir = 0; |
| - | cs.ctx = ctx; |
| - | retval = ext2fs_get_mem(fs->blocksize, &cs.buf); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) |
| - | cs.dir = ino; |
| - | |
| - | pctx.ino = ino; |
| - | pctx.str = "clone_file"; |
| - | if (ext2fs_inode_has_valid_blocks(&dp->inode)) |
| - | pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, |
| - | clone_file_block, &cs); |
| - | ext2fs_mark_bb_dirty(fs); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); |
| - | retval = pctx.errcode; |
| - | goto errout; |
| - | } |
| - | if (cs.errcode) { |
| - | bb_error_msg(_("returned from clone_file_block")); |
| - | retval = cs.errcode; |
| - | goto errout; |
| - | } |
| - | /* The inode may have changed on disk, so we have to re-read it */ |
| - | e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA"); |
| - | blk = dp->inode.i_file_acl; |
| - | if (blk && (clone_file_block(fs, &dp->inode.i_file_acl, |
| - | BLOCK_COUNT_EXTATTR, 0, 0, &cs) == |
| - | BLOCK_CHANGED)) { |
| - | e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA"); |
| - | /* |
| - | * If we cloned the EA block, find all other inodes |
| - | * which refered to that EA block, and modify |
| - | * them to point to the new EA block. |
| - | */ |
| - | n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk)); |
| - | db = (struct dup_block *) dnode_get(n); |
| - | for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) { |
| - | if (ino_el->inode == ino) |
| - | continue; |
| - | n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode)); |
| - | di = (struct dup_inode *) dnode_get(n); |
| - | if (di->inode.i_file_acl == blk) { |
| - | di->inode.i_file_acl = dp->inode.i_file_acl; |
| - | e2fsck_write_inode(ctx, ino_el->inode, |
| - | &di->inode, "clone file EA"); |
| - | decrement_badcount(ctx, blk, db); |
| - | } |
| - | } |
| - | } |
| - | retval = 0; |
| - | errout: |
| - | ext2fs_free_mem(&cs.buf); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * This routine returns 1 if a block overlaps with one of the superblocks, |
| - | * group descriptors, inode bitmaps, or block bitmaps. |
| - | */ |
| - | static int check_if_fs_block(e2fsck_t ctx, blk_t test_block) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t block; |
| - | dgrp_t i; |
| - | |
| - | block = fs->super->s_first_data_block; |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | |
| - | /* Check superblocks/block group descriptros */ |
| - | if (ext2fs_bg_has_super(fs, i)) { |
| - | if (test_block >= block && |
| - | (test_block <= block + fs->desc_blocks)) |
| - | return 1; |
| - | } |
| - | |
| - | /* Check the inode table */ |
| - | if ((fs->group_desc[i].bg_inode_table) && |
| - | (test_block >= fs->group_desc[i].bg_inode_table) && |
| - | (test_block < (fs->group_desc[i].bg_inode_table + |
| - | fs->inode_blocks_per_group))) |
| - | return 1; |
| - | |
| - | /* Check the bitmap blocks */ |
| - | if ((test_block == fs->group_desc[i].bg_block_bitmap) || |
| - | (test_block == fs->group_desc[i].bg_inode_bitmap)) |
| - | return 1; |
| - | |
| - | block += fs->super->s_blocks_per_group; |
| - | } |
| - | return 0; |
| - | } |
| - | /* |
| - | * pass2.c --- check directory structure |
| - | * |
| - | * Pass 2 of e2fsck iterates through all active directory inodes, and |
| - | * applies to following tests to each directory entry in the directory |
| - | * blocks in the inodes: |
| - | * |
| - | * - The length of the directory entry (rec_len) should be at |
| - | * least 8 bytes, and no more than the remaining space |
| - | * left in the directory block. |
| - | * - The length of the name in the directory entry (name_len) |
| - | * should be less than (rec_len - 8). |
| - | * - The inode number in the directory entry should be within |
| - | * legal bounds. |
| - | * - The inode number should refer to a in-use inode. |
| - | * - The first entry should be '.', and its inode should be |
| - | * the inode of the directory. |
| - | * - The second entry should be '..'. |
| - | * |
| - | * To minimize disk seek time, the directory blocks are processed in |
| - | * sorted order of block numbers. |
| - | * |
| - | * Pass 2 also collects the following information: |
| - | * - The inode numbers of the subdirectories for each directory. |
| - | * |
| - | * Pass 2 relies on the following information from previous passes: |
| - | * - The directory information collected in pass 1. |
| - | * - The inode_used_map bitmap |
| - | * - The inode_bad_map bitmap |
| - | * - The inode_dir_map bitmap |
| - | * |
| - | * Pass 2 frees the following data structures |
| - | * - The inode_bad_map bitmap |
| - | * - The inode_reg_map bitmap |
| - | */ |
| - | |
| - | /* |
| - | * Keeps track of how many times an inode is referenced. |
| - | */ |
| - | static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf); |
| - | static int check_dir_block(ext2_filsys fs, |
| - | struct ext2_db_entry *dir_blocks_info, |
| - | void *priv_data); |
| - | static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info, |
| - | struct problem_context *pctx); |
| - | static int update_dir_block(ext2_filsys fs, |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block, |
| - | int ref_offset, |
| - | void *priv_data); |
| - | static void clear_htree(e2fsck_t ctx, ext2_ino_t ino); |
| - | static int htree_depth(struct dx_dir_info *dx_dir, |
| - | struct dx_dirblock_info *dx_db); |
| - | static int special_dir_block_cmp(const void *a, const void *b); |
| - | |
| - | struct check_dir_struct { |
| - | char *buf; |
| - | struct problem_context pctx; |
| - | int count, max; |
| - | e2fsck_t ctx; |
| - | }; |
| - | |
| - | static void e2fsck_pass2(e2fsck_t ctx) |
| - | { |
| - | struct ext2_super_block *sb = ctx->fs->super; |
| - | struct problem_context pctx; |
| - | ext2_filsys fs = ctx->fs; |
| - | char *buf; |
| - | struct dir_info *dir; |
| - | struct check_dir_struct cd; |
| - | struct dx_dir_info *dx_dir; |
| - | struct dx_dirblock_info *dx_db, *dx_parent; |
| - | int b; |
| - | int i, depth; |
| - | problem_t code; |
| - | int bad_dir; |
| - | |
| - | clear_problem_context(&cd.pctx); |
| - | |
| - | /* Pass 2 */ |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx); |
| - | |
| - | cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT, |
| - | 0, ctx->inode_link_info, |
| - | &ctx->inode_count); |
| - | if (cd.pctx.errcode) { |
| - | fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize, |
| - | "directory scan buffer"); |
| - | |
| - | /* |
| - | * Set up the parent pointer for the root directory, if |
| - | * present. (If the root directory is not present, we will |
| - | * create it in pass 3.) |
| - | */ |
| - | dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO); |
| - | if (dir) |
| - | dir->parent = EXT2_ROOT_INO; |
| - | |
| - | cd.buf = buf; |
| - | cd.ctx = ctx; |
| - | cd.count = 1; |
| - | cd.max = ext2fs_dblist_count(fs->dblist); |
| - | |
| - | if (ctx->progress) |
| - | (void) (ctx->progress)(ctx, 2, 0, cd.max); |
| - | |
| - | if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) |
| - | ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp); |
| - | |
| - | cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block, |
| - | &cd); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | if (cd.pctx.errcode) { |
| - | fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | #ifdef ENABLE_HTREE |
| - | for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | if (dx_dir->numblocks == 0) |
| - | continue; |
| - | clear_problem_context(&pctx); |
| - | bad_dir = 0; |
| - | pctx.dir = dx_dir->ino; |
| - | dx_db = dx_dir->dx_block; |
| - | if (dx_db->flags & DX_FLAG_REFERENCED) |
| - | dx_db->flags |= DX_FLAG_DUP_REF; |
| - | else |
| - | dx_db->flags |= DX_FLAG_REFERENCED; |
| - | /* |
| - | * Find all of the first and last leaf blocks, and |
| - | * update their parent's min and max hash values |
| - | */ |
| - | for (b=0, dx_db = dx_dir->dx_block; |
| - | b < dx_dir->numblocks; |
| - | b++, dx_db++) { |
| - | if ((dx_db->type != DX_DIRBLOCK_LEAF) || |
| - | !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST))) |
| - | continue; |
| - | dx_parent = &dx_dir->dx_block[dx_db->parent]; |
| - | /* |
| - | * XXX Make sure dx_parent->min_hash > dx_db->min_hash |
| - | */ |
| - | if (dx_db->flags & DX_FLAG_FIRST) |
| - | dx_parent->min_hash = dx_db->min_hash; |
| - | /* |
| - | * XXX Make sure dx_parent->max_hash < dx_db->max_hash |
| - | */ |
| - | if (dx_db->flags & DX_FLAG_LAST) |
| - | dx_parent->max_hash = dx_db->max_hash; |
| - | } |
| - | |
| - | for (b=0, dx_db = dx_dir->dx_block; |
| - | b < dx_dir->numblocks; |
| - | b++, dx_db++) { |
| - | pctx.blkcount = b; |
| - | pctx.group = dx_db->parent; |
| - | code = 0; |
| - | if (!(dx_db->flags & DX_FLAG_FIRST) && |
| - | (dx_db->min_hash < dx_db->node_min_hash)) { |
| - | pctx.blk = dx_db->min_hash; |
| - | pctx.blk2 = dx_db->node_min_hash; |
| - | code = PR_2_HTREE_MIN_HASH; |
| - | fix_problem(ctx, code, &pctx); |
| - | bad_dir++; |
| - | } |
| - | if (dx_db->type == DX_DIRBLOCK_LEAF) { |
| - | depth = htree_depth(dx_dir, dx_db); |
| - | if (depth != dx_dir->depth) { |
| - | code = PR_2_HTREE_BAD_DEPTH; |
| - | fix_problem(ctx, code, &pctx); |
| - | bad_dir++; |
| - | } |
| - | } |
| - | /* |
| - | * This test doesn't apply for the root block |
| - | * at block #0 |
| - | */ |
| - | if (b && |
| - | (dx_db->max_hash > dx_db->node_max_hash)) { |
| - | pctx.blk = dx_db->max_hash; |
| - | pctx.blk2 = dx_db->node_max_hash; |
| - | code = PR_2_HTREE_MAX_HASH; |
| - | fix_problem(ctx, code, &pctx); |
| - | bad_dir++; |
| - | } |
| - | if (!(dx_db->flags & DX_FLAG_REFERENCED)) { |
| - | code = PR_2_HTREE_NOTREF; |
| - | fix_problem(ctx, code, &pctx); |
| - | bad_dir++; |
| - | } else if (dx_db->flags & DX_FLAG_DUP_REF) { |
| - | code = PR_2_HTREE_DUPREF; |
| - | fix_problem(ctx, code, &pctx); |
| - | bad_dir++; |
| - | } |
| - | if (code == 0) |
| - | continue; |
| - | } |
| - | if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) { |
| - | clear_htree(ctx, dx_dir->ino); |
| - | dx_dir->numblocks = 0; |
| - | } |
| - | } |
| - | #endif |
| - | ext2fs_free_mem(&buf); |
| - | ext2fs_free_dblist(fs->dblist); |
| - | |
| - | ext2fs_free_inode_bitmap(ctx->inode_bad_map); |
| - | ctx->inode_bad_map = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_reg_map); |
| - | ctx->inode_reg_map = 0; |
| - | |
| - | clear_problem_context(&pctx); |
| - | if (ctx->large_files) { |
| - | if (!(sb->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_LARGE_FILE) && |
| - | fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) { |
| - | sb->s_feature_ro_compat |= |
| - | EXT2_FEATURE_RO_COMPAT_LARGE_FILE; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | if (sb->s_rev_level == EXT2_GOOD_OLD_REV && |
| - | fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) { |
| - | ext2fs_update_dynamic_rev(fs); |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } else if (!ctx->large_files && |
| - | (sb->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { |
| - | if (fs->flags & EXT2_FLAG_RW) { |
| - | sb->s_feature_ro_compat &= |
| - | ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | } |
| - | |
| - | #define MAX_DEPTH 32000 |
| - | static int htree_depth(struct dx_dir_info *dx_dir, |
| - | struct dx_dirblock_info *dx_db) |
| - | { |
| - | int depth = 0; |
| - | |
| - | while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) { |
| - | dx_db = &dx_dir->dx_block[dx_db->parent]; |
| - | depth++; |
| - | } |
| - | return depth; |
| - | } |
| - | |
| - | static int dict_de_cmp(const void *a, const void *b) |
| - | { |
| - | const struct ext2_dir_entry *de_a, *de_b; |
| - | int a_len, b_len; |
| - | |
| - | de_a = (const struct ext2_dir_entry *) a; |
| - | a_len = de_a->name_len & 0xFF; |
| - | de_b = (const struct ext2_dir_entry *) b; |
| - | b_len = de_b->name_len & 0xFF; |
| - | |
| - | if (a_len != b_len) |
| - | return (a_len - b_len); |
| - | |
| - | return strncmp(de_a->name, de_b->name, a_len); |
| - | } |
| - | |
| - | /* |
| - | * This is special sort function that makes sure that directory blocks |
| - | * with a dirblock of zero are sorted to the beginning of the list. |
| - | * This guarantees that the root node of the htree directories are |
| - | * processed first, so we know what hash version to use. |
| - | */ |
| - | static int special_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->blockcnt && !db_b->blockcnt) |
| - | return 1; |
| - | |
| - | if (!db_a->blockcnt && db_b->blockcnt) |
| - | return -1; |
| - | |
| - | 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); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Make sure the first entry in the directory is '.', and that the |
| - | * directory entry is sane. |
| - | */ |
| - | static int check_dot(e2fsck_t ctx, |
| - | struct ext2_dir_entry *dirent, |
| - | ext2_ino_t ino, struct problem_context *pctx) |
| - | { |
| - | struct ext2_dir_entry *nextdir; |
| - | int status = 0; |
| - | int created = 0; |
| - | int new_len; |
| - | int problem = 0; |
| - | |
| - | if (!dirent->inode) |
| - | problem = PR_2_MISSING_DOT; |
| - | else if (((dirent->name_len & 0xFF) != 1) || |
| - | (dirent->name[0] != '.')) |
| - | problem = PR_2_1ST_NOT_DOT; |
| - | else if (dirent->name[1] != '\0') |
| - | problem = PR_2_DOT_NULL_TERM; |
| - | |
| - | if (problem) { |
| - | if (fix_problem(ctx, problem, pctx)) { |
| - | if (dirent->rec_len < 12) |
| - | dirent->rec_len = 12; |
| - | dirent->inode = ino; |
| - | dirent->name_len = 1; |
| - | dirent->name[0] = '.'; |
| - | dirent->name[1] = '\0'; |
| - | status = 1; |
| - | created = 1; |
| - | } |
| - | } |
| - | if (dirent->inode != ino) { |
| - | if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) { |
| - | dirent->inode = ino; |
| - | status = 1; |
| - | } |
| - | } |
| - | if (dirent->rec_len > 12) { |
| - | new_len = dirent->rec_len - 12; |
| - | if (new_len > 12) { |
| - | if (created || |
| - | fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) { |
| - | nextdir = (struct ext2_dir_entry *) |
| - | ((char *) dirent + 12); |
| - | dirent->rec_len = 12; |
| - | nextdir->rec_len = new_len; |
| - | nextdir->inode = 0; |
| - | nextdir->name_len = 0; |
| - | status = 1; |
| - | } |
| - | } |
| - | } |
| - | return status; |
| - | } |
| - | |
| - | /* |
| - | * Make sure the second entry in the directory is '..', and that the |
| - | * directory entry is sane. We do not check the inode number of '..' |
| - | * here; this gets done in pass 3. |
| - | */ |
| - | static int check_dotdot(e2fsck_t ctx, |
| - | struct ext2_dir_entry *dirent, |
| - | struct dir_info *dir, struct problem_context *pctx) |
| - | { |
| - | int problem = 0; |
| - | |
| - | if (!dirent->inode) |
| - | problem = PR_2_MISSING_DOT_DOT; |
| - | else if (((dirent->name_len & 0xFF) != 2) || |
| - | (dirent->name[0] != '.') || |
| - | (dirent->name[1] != '.')) |
| - | problem = PR_2_2ND_NOT_DOT_DOT; |
| - | else if (dirent->name[2] != '\0') |
| - | problem = PR_2_DOT_DOT_NULL_TERM; |
| - | |
| - | if (problem) { |
| - | if (fix_problem(ctx, problem, pctx)) { |
| - | if (dirent->rec_len < 12) |
| - | dirent->rec_len = 12; |
| - | /* |
| - | * Note: we don't have the parent inode just |
| - | * yet, so we will fill it in with the root |
| - | * inode. This will get fixed in pass 3. |
| - | */ |
| - | dirent->inode = EXT2_ROOT_INO; |
| - | dirent->name_len = 2; |
| - | dirent->name[0] = '.'; |
| - | dirent->name[1] = '.'; |
| - | dirent->name[2] = '\0'; |
| - | return 1; |
| - | } |
| - | return 0; |
| - | } |
| - | dir->dotdot = dirent->inode; |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Check to make sure a directory entry doesn't contain any illegal |
| - | * characters. |
| - | */ |
| - | static int check_name(e2fsck_t ctx, |
| - | struct ext2_dir_entry *dirent, |
| - | struct problem_context *pctx) |
| - | { |
| - | int i; |
| - | int fixup = -1; |
| - | int ret = 0; |
| - | |
| - | for ( i = 0; i < (dirent->name_len & 0xFF); i++) { |
| - | if (dirent->name[i] == '/' || dirent->name[i] == '\0') { |
| - | if (fixup < 0) { |
| - | fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); |
| - | } |
| - | if (fixup) { |
| - | dirent->name[i] = '.'; |
| - | ret = 1; |
| - | } |
| - | } |
| - | } |
| - | return ret; |
| - | } |
| - | |
| - | /* |
| - | * Check the directory filetype (if present) |
| - | */ |
| - | |
| - | /* |
| - | * Given a mode, return the ext2 file type |
| - | */ |
| - | static int ext2_file_type(unsigned int mode) |
| - | { |
| - | if (LINUX_S_ISREG(mode)) |
| - | return EXT2_FT_REG_FILE; |
| - | |
| - | if (LINUX_S_ISDIR(mode)) |
| - | return EXT2_FT_DIR; |
| - | |
| - | if (LINUX_S_ISCHR(mode)) |
| - | return EXT2_FT_CHRDEV; |
| - | |
| - | if (LINUX_S_ISBLK(mode)) |
| - | return EXT2_FT_BLKDEV; |
| - | |
| - | if (LINUX_S_ISLNK(mode)) |
| - | return EXT2_FT_SYMLINK; |
| - | |
| - | if (LINUX_S_ISFIFO(mode)) |
| - | return EXT2_FT_FIFO; |
| - | |
| - | if (LINUX_S_ISSOCK(mode)) |
| - | return EXT2_FT_SOCK; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static int check_filetype(e2fsck_t ctx, |
| - | struct ext2_dir_entry *dirent, |
| - | struct problem_context *pctx) |
| - | { |
| - | int filetype = dirent->name_len >> 8; |
| - | int should_be = EXT2_FT_UNKNOWN; |
| - | struct ext2_inode inode; |
| - | |
| - | if (!(ctx->fs->super->s_feature_incompat & |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE)) { |
| - | if (filetype == 0 || |
| - | !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx)) |
| - | return 0; |
| - | dirent->name_len = dirent->name_len & 0xFF; |
| - | return 1; |
| - | } |
| - | |
| - | if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) { |
| - | should_be = EXT2_FT_DIR; |
| - | } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map, |
| - | dirent->inode)) { |
| - | should_be = EXT2_FT_REG_FILE; |
| - | } else if (ctx->inode_bad_map && |
| - | ext2fs_test_inode_bitmap(ctx->inode_bad_map, |
| - | dirent->inode)) |
| - | should_be = 0; |
| - | else { |
| - | e2fsck_read_inode(ctx, dirent->inode, &inode, |
| - | "check_filetype"); |
| - | should_be = ext2_file_type(inode.i_mode); |
| - | } |
| - | if (filetype == should_be) |
| - | return 0; |
| - | pctx->num = should_be; |
| - | |
| - | if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE, |
| - | pctx) == 0) |
| - | return 0; |
| - | |
| - | dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8; |
| - | return 1; |
| - | } |
| - | |
| - | #ifdef ENABLE_HTREE |
| - | static void parse_int_node(ext2_filsys fs, |
| - | struct ext2_db_entry *db, |
| - | struct check_dir_struct *cd, |
| - | struct dx_dir_info *dx_dir, |
| - | char *block_buf) |
| - | { |
| - | struct ext2_dx_root_info *root; |
| - | struct ext2_dx_entry *ent; |
| - | struct ext2_dx_countlimit *limit; |
| - | struct dx_dirblock_info *dx_db; |
| - | int i, expect_limit, count; |
| - | blk_t blk; |
| - | ext2_dirhash_t min_hash = 0xffffffff; |
| - | ext2_dirhash_t max_hash = 0; |
| - | ext2_dirhash_t hash = 0, prev_hash; |
| - | |
| - | if (db->blockcnt == 0) { |
| - | root = (struct ext2_dx_root_info *) (block_buf + 24); |
| - | ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length); |
| - | } else { |
| - | ent = (struct ext2_dx_entry *) (block_buf+8); |
| - | } |
| - | limit = (struct ext2_dx_countlimit *) ent; |
| - | |
| - | count = ext2fs_le16_to_cpu(limit->count); |
| - | expect_limit = (fs->blocksize - ((char *) ent - block_buf)) / |
| - | sizeof(struct ext2_dx_entry); |
| - | if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) { |
| - | cd->pctx.num = ext2fs_le16_to_cpu(limit->limit); |
| - | if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx)) |
| - | goto clear_and_exit; |
| - | } |
| - | if (count > expect_limit) { |
| - | cd->pctx.num = count; |
| - | if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx)) |
| - | goto clear_and_exit; |
| - | count = expect_limit; |
| - | } |
| - | |
| - | for (i=0; i < count; i++) { |
| - | prev_hash = hash; |
| - | hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0; |
| - | blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff; |
| - | /* Check to make sure the block is valid */ |
| - | if (blk > (blk_t) dx_dir->numblocks) { |
| - | cd->pctx.blk = blk; |
| - | if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK, |
| - | &cd->pctx)) |
| - | goto clear_and_exit; |
| - | } |
| - | if (hash < prev_hash && |
| - | fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx)) |
| - | goto clear_and_exit; |
| - | dx_db = &dx_dir->dx_block[blk]; |
| - | if (dx_db->flags & DX_FLAG_REFERENCED) { |
| - | dx_db->flags |= DX_FLAG_DUP_REF; |
| - | } else { |
| - | dx_db->flags |= DX_FLAG_REFERENCED; |
| - | dx_db->parent = db->blockcnt; |
| - | } |
| - | if (hash < min_hash) |
| - | min_hash = hash; |
| - | if (hash > max_hash) |
| - | max_hash = hash; |
| - | dx_db->node_min_hash = hash; |
| - | if ((i+1) < count) |
| - | dx_db->node_max_hash = |
| - | ext2fs_le32_to_cpu(ent[i+1].hash) & ~1; |
| - | else { |
| - | dx_db->node_max_hash = 0xfffffffe; |
| - | dx_db->flags |= DX_FLAG_LAST; |
| - | } |
| - | if (i == 0) |
| - | dx_db->flags |= DX_FLAG_FIRST; |
| - | } |
| - | dx_db = &dx_dir->dx_block[db->blockcnt]; |
| - | dx_db->min_hash = min_hash; |
| - | dx_db->max_hash = max_hash; |
| - | return; |
| - | |
| - | clear_and_exit: |
| - | clear_htree(cd->ctx, cd->pctx.ino); |
| - | dx_dir->numblocks = 0; |
| - | } |
| - | #endif /* ENABLE_HTREE */ |
| - | |
| - | /* |
| - | * Given a busted directory, try to salvage it somehow. |
| - | * |
| - | */ |
| - | static void salvage_directory(ext2_filsys fs, |
| - | struct ext2_dir_entry *dirent, |
| - | struct ext2_dir_entry *prev, |
| - | unsigned int *offset) |
| - | { |
| - | char *cp = (char *) dirent; |
| - | int left = fs->blocksize - *offset - dirent->rec_len; |
| - | int name_len = dirent->name_len & 0xFF; |
| - | |
| - | /* |
| - | * Special case of directory entry of size 8: copy what's left |
| - | * of the directory block up to cover up the invalid hole. |
| - | */ |
| - | if ((left >= 12) && (dirent->rec_len == 8)) { |
| - | memmove(cp, cp+8, left); |
| - | memset(cp + left, 0, 8); |
| - | return; |
| - | } |
| - | /* |
| - | * If the directory entry overruns the end of the directory |
| - | * block, and the name is small enough to fit, then adjust the |
| - | * record length. |
| - | */ |
| - | if ((left < 0) && |
| - | (name_len + 8 <= dirent->rec_len + left) && |
| - | dirent->inode <= fs->super->s_inodes_count && |
| - | strnlen(dirent->name, name_len) == name_len) { |
| - | dirent->rec_len += left; |
| - | return; |
| - | } |
| - | /* |
| - | * If the directory entry is a multiple of four, so it is |
| - | * valid, let the previous directory entry absorb the invalid |
| - | * one. |
| - | */ |
| - | if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) { |
| - | prev->rec_len += dirent->rec_len; |
| - | *offset += dirent->rec_len; |
| - | return; |
| - | } |
| - | /* |
| - | * Default salvage method --- kill all of the directory |
| - | * entries for the rest of the block. We will either try to |
| - | * absorb it into the previous directory entry, or create a |
| - | * new empty directory entry the rest of the directory block. |
| - | */ |
| - | if (prev) { |
| - | prev->rec_len += fs->blocksize - *offset; |
| - | *offset = fs->blocksize; |
| - | } else { |
| - | dirent->rec_len = fs->blocksize - *offset; |
| - | dirent->name_len = 0; |
| - | dirent->inode = 0; |
| - | } |
| - | } |
| - | |
| - | static int check_dir_block(ext2_filsys fs, |
| - | struct ext2_db_entry *db, |
| - | void *priv_data) |
| - | { |
| - | struct dir_info *subdir, *dir; |
| - | struct dx_dir_info *dx_dir; |
| - | #ifdef ENABLE_HTREE |
| - | struct dx_dirblock_info *dx_db = NULL; |
| - | #endif /* ENABLE_HTREE */ |
| - | struct ext2_dir_entry *dirent, *prev; |
| - | ext2_dirhash_t hash; |
| - | unsigned int offset = 0; |
| - | int dir_modified = 0; |
| - | int dot_state; |
| - | blk_t block_nr = db->blk; |
| - | ext2_ino_t ino = db->ino; |
| - | __u16 links; |
| - | struct check_dir_struct *cd; |
| - | char *buf; |
| - | e2fsck_t ctx; |
| - | int problem; |
| - | struct ext2_dx_root_info *root; |
| - | struct ext2_dx_countlimit *limit; |
| - | static dict_t de_dict; |
| - | struct problem_context pctx; |
| - | int dups_found = 0; |
| - | |
| - | cd = (struct check_dir_struct *) priv_data; |
| - | buf = cd->buf; |
| - | ctx = cd->ctx; |
| - | |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return DIRENT_ABORT; |
| - | |
| - | if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max)) |
| - | return DIRENT_ABORT; |
| - | |
| - | /* |
| - | * Make sure the inode is still in use (could have been |
| - | * deleted in the duplicate/bad blocks pass. |
| - | */ |
| - | if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))) |
| - | return 0; |
| - | |
| - | cd->pctx.ino = ino; |
| - | cd->pctx.blk = block_nr; |
| - | cd->pctx.blkcount = db->blockcnt; |
| - | cd->pctx.ino2 = 0; |
| - | cd->pctx.dirent = 0; |
| - | cd->pctx.num = 0; |
| - | |
| - | if (db->blk == 0) { |
| - | if (allocate_dir_block(ctx, db, &cd->pctx)) |
| - | return 0; |
| - | block_nr = db->blk; |
| - | } |
| - | |
| - | if (db->blockcnt) |
| - | dot_state = 2; |
| - | else |
| - | dot_state = 0; |
| - | |
| - | if (ctx->dirs_to_hash && |
| - | ext2fs_u32_list_test(ctx->dirs_to_hash, ino)) |
| - | dups_found++; |
| - | |
| - | cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf); |
| - | if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED) |
| - | cd->pctx.errcode = 0; /* We'll handle this ourselves */ |
| - | if (cd->pctx.errcode) { |
| - | if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) { |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return DIRENT_ABORT; |
| - | } |
| - | memset(buf, 0, fs->blocksize); |
| - | } |
| - | #ifdef ENABLE_HTREE |
| - | dx_dir = e2fsck_get_dx_dir_info(ctx, ino); |
| - | if (dx_dir && dx_dir->numblocks) { |
| - | if (db->blockcnt >= dx_dir->numblocks) { |
| - | printf("XXX should never happen!!!\n"); |
| - | abort(); |
| - | } |
| - | dx_db = &dx_dir->dx_block[db->blockcnt]; |
| - | dx_db->type = DX_DIRBLOCK_LEAF; |
| - | dx_db->phys = block_nr; |
| - | dx_db->min_hash = ~0; |
| - | dx_db->max_hash = 0; |
| - | |
| - | dirent = (struct ext2_dir_entry *) buf; |
| - | limit = (struct ext2_dx_countlimit *) (buf+8); |
| - | if (db->blockcnt == 0) { |
| - | root = (struct ext2_dx_root_info *) (buf + 24); |
| - | dx_db->type = DX_DIRBLOCK_ROOT; |
| - | dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST; |
| - | if ((root->reserved_zero || |
| - | root->info_length < 8 || |
| - | root->indirect_levels > 1) && |
| - | fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) { |
| - | clear_htree(ctx, ino); |
| - | dx_dir->numblocks = 0; |
| - | dx_db = 0; |
| - | } |
| - | dx_dir->hashversion = root->hash_version; |
| - | dx_dir->depth = root->indirect_levels + 1; |
| - | } else if ((dirent->inode == 0) && |
| - | (dirent->rec_len == fs->blocksize) && |
| - | (dirent->name_len == 0) && |
| - | (ext2fs_le16_to_cpu(limit->limit) == |
| - | ((fs->blocksize-8) / |
| - | sizeof(struct ext2_dx_entry)))) |
| - | dx_db->type = DX_DIRBLOCK_NODE; |
| - | } |
| - | #endif /* ENABLE_HTREE */ |
| - | |
| - | dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp); |
| - | prev = 0; |
| - | do { |
| - | problem = 0; |
| - | dirent = (struct ext2_dir_entry *) (buf + offset); |
| - | cd->pctx.dirent = dirent; |
| - | cd->pctx.num = offset; |
| - | if (((offset + dirent->rec_len) > fs->blocksize) || |
| - | (dirent->rec_len < 12) || |
| - | ((dirent->rec_len % 4) != 0) || |
| - | (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { |
| - | if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { |
| - | salvage_directory(fs, dirent, prev, &offset); |
| - | dir_modified++; |
| - | continue; |
| - | } else |
| - | goto abort_free_dict; |
| - | } |
| - | if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) { |
| - | if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) { |
| - | dirent->name_len = EXT2_NAME_LEN; |
| - | dir_modified++; |
| - | } |
| - | } |
| - | |
| - | if (dot_state == 0) { |
| - | if (check_dot(ctx, dirent, ino, &cd->pctx)) |
| - | dir_modified++; |
| - | } else if (dot_state == 1) { |
| - | dir = e2fsck_get_dir_info(ctx, ino); |
| - | if (!dir) { |
| - | fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx); |
| - | goto abort_free_dict; |
| - | } |
| - | if (check_dotdot(ctx, dirent, dir, &cd->pctx)) |
| - | dir_modified++; |
| - | } else if (dirent->inode == ino) { |
| - | problem = PR_2_LINK_DOT; |
| - | if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) { |
| - | dirent->inode = 0; |
| - | dir_modified++; |
| - | goto next; |
| - | } |
| - | } |
| - | if (!dirent->inode) |
| - | goto next; |
| - | |
| - | /* |
| - | * Make sure the inode listed is a legal one. |
| - | */ |
| - | if (((dirent->inode != EXT2_ROOT_INO) && |
| - | (dirent->inode < EXT2_FIRST_INODE(fs->super))) || |
| - | (dirent->inode > fs->super->s_inodes_count)) { |
| - | problem = PR_2_BAD_INO; |
| - | } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, |
| - | dirent->inode))) { |
| - | /* |
| - | * If the inode is unused, offer to clear it. |
| - | */ |
| - | problem = PR_2_UNUSED_INODE; |
| - | } else if ((dot_state > 1) && |
| - | ((dirent->name_len & 0xFF) == 1) && |
| - | (dirent->name[0] == '.')) { |
| - | /* |
| - | * If there's a '.' entry in anything other |
| - | * than the first directory entry, it's a |
| - | * duplicate entry that should be removed. |
| - | */ |
| - | problem = PR_2_DUP_DOT; |
| - | } else if ((dot_state > 1) && |
| - | ((dirent->name_len & 0xFF) == 2) && |
| - | (dirent->name[0] == '.') && |
| - | (dirent->name[1] == '.')) { |
| - | /* |
| - | * If there's a '..' entry in anything other |
| - | * than the second directory entry, it's a |
| - | * duplicate entry that should be removed. |
| - | */ |
| - | problem = PR_2_DUP_DOT_DOT; |
| - | } else if ((dot_state > 1) && |
| - | (dirent->inode == EXT2_ROOT_INO)) { |
| - | /* |
| - | * Don't allow links to the root directory. |
| - | * We check this specially to make sure we |
| - | * catch this error case even if the root |
| - | * directory hasn't been created yet. |
| - | */ |
| - | problem = PR_2_LINK_ROOT; |
| - | } else if ((dot_state > 1) && |
| - | (dirent->name_len & 0xFF) == 0) { |
| - | /* |
| - | * Don't allow zero-length directory names. |
| - | */ |
| - | problem = PR_2_NULL_NAME; |
| - | } |
| - | |
| - | if (problem) { |
| - | if (fix_problem(ctx, problem, &cd->pctx)) { |
| - | dirent->inode = 0; |
| - | dir_modified++; |
| - | goto next; |
| - | } else { |
| - | ext2fs_unmark_valid(fs); |
| - | if (problem == PR_2_BAD_INO) |
| - | goto next; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * If the inode was marked as having bad fields in |
| - | * pass1, process it and offer to fix/clear it. |
| - | * (We wait until now so that we can display the |
| - | * pathname to the user.) |
| - | */ |
| - | if (ctx->inode_bad_map && |
| - | ext2fs_test_inode_bitmap(ctx->inode_bad_map, |
| - | dirent->inode)) { |
| - | if (e2fsck_process_bad_inode(ctx, ino, |
| - | dirent->inode, |
| - | buf + fs->blocksize)) { |
| - | dirent->inode = 0; |
| - | dir_modified++; |
| - | goto next; |
| - | } |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return DIRENT_ABORT; |
| - | } |
| - | |
| - | if (check_name(ctx, dirent, &cd->pctx)) |
| - | dir_modified++; |
| - | |
| - | if (check_filetype(ctx, dirent, &cd->pctx)) |
| - | dir_modified++; |
| - | |
| - | #ifdef ENABLE_HTREE |
| - | if (dx_db) { |
| - | ext2fs_dirhash(dx_dir->hashversion, dirent->name, |
| - | (dirent->name_len & 0xFF), |
| - | fs->super->s_hash_seed, &hash, 0); |
| - | if (hash < dx_db->min_hash) |
| - | dx_db->min_hash = hash; |
| - | if (hash > dx_db->max_hash) |
| - | dx_db->max_hash = hash; |
| - | } |
| - | #endif |
| - | |
| - | /* |
| - | * If this is a directory, then mark its parent in its |
| - | * dir_info structure. If the parent field is already |
| - | * filled in, then this directory has more than one |
| - | * hard link. We assume the first link is correct, |
| - | * and ask the user if he/she wants to clear this one. |
| - | */ |
| - | if ((dot_state > 1) && |
| - | (ext2fs_test_inode_bitmap(ctx->inode_dir_map, |
| - | dirent->inode))) { |
| - | subdir = e2fsck_get_dir_info(ctx, dirent->inode); |
| - | if (!subdir) { |
| - | cd->pctx.ino = dirent->inode; |
| - | fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx); |
| - | goto abort_free_dict; |
| - | } |
| - | if (subdir->parent) { |
| - | cd->pctx.ino2 = subdir->parent; |
| - | if (fix_problem(ctx, PR_2_LINK_DIR, |
| - | &cd->pctx)) { |
| - | dirent->inode = 0; |
| - | dir_modified++; |
| - | goto next; |
| - | } |
| - | cd->pctx.ino2 = 0; |
| - | } else |
| - | subdir->parent = ino; |
| - | } |
| - | |
| - | if (dups_found) { |
| - | ; |
| - | } else if (dict_lookup(&de_dict, dirent)) { |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | pctx.dirent = dirent; |
| - | fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx); |
| - | if (!ctx->dirs_to_hash) |
| - | ext2fs_u32_list_create(&ctx->dirs_to_hash, 50); |
| - | if (ctx->dirs_to_hash) |
| - | ext2fs_u32_list_add(ctx->dirs_to_hash, ino); |
| - | dups_found++; |
| - | } else |
| - | dict_alloc_insert(&de_dict, dirent, dirent); |
| - | |
| - | ext2fs_icount_increment(ctx->inode_count, dirent->inode, |
| - | &links); |
| - | if (links > 1) |
| - | ctx->fs_links_count++; |
| - | ctx->fs_total_count++; |
| - | next: |
| - | prev = dirent; |
| - | offset += dirent->rec_len; |
| - | dot_state++; |
| - | } while (offset < fs->blocksize); |
| - | #ifdef ENABLE_HTREE |
| - | if (dx_db) { |
| - | cd->pctx.dir = cd->pctx.ino; |
| - | if ((dx_db->type == DX_DIRBLOCK_ROOT) || |
| - | (dx_db->type == DX_DIRBLOCK_NODE)) |
| - | parse_int_node(fs, db, cd, dx_dir, buf); |
| - | } |
| - | #endif /* ENABLE_HTREE */ |
| - | if (offset != fs->blocksize) { |
| - | cd->pctx.num = dirent->rec_len - fs->blocksize + offset; |
| - | if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) { |
| - | dirent->rec_len = cd->pctx.num; |
| - | dir_modified++; |
| - | } |
| - | } |
| - | if (dir_modified) { |
| - | cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf); |
| - | if (cd->pctx.errcode) { |
| - | if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK, |
| - | &cd->pctx)) |
| - | goto abort_free_dict; |
| - | } |
| - | ext2fs_mark_changed(fs); |
| - | } |
| - | dict_free_nodes(&de_dict); |
| - | return 0; |
| - | abort_free_dict: |
| - | dict_free_nodes(&de_dict); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return DIRENT_ABORT; |
| - | } |
| - | |
| - | /* |
| - | * This function is called to deallocate a block, and is an interator |
| - | * functioned called by deallocate inode via ext2fs_iterate_block(). |
| - | */ |
| - | static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt FSCK_ATTR((unused)), |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | e2fsck_t ctx = (e2fsck_t) priv_data; |
| - | |
| - | if (HOLE_BLKADDR(*block_nr)) |
| - | return 0; |
| - | if ((*block_nr < fs->super->s_first_data_block) || |
| - | (*block_nr >= fs->super->s_blocks_count)) |
| - | return 0; |
| - | ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); |
| - | ext2fs_block_alloc_stats(fs, *block_nr, -1); |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This function deallocates an inode |
| - | */ |
| - | static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct ext2_inode inode; |
| - | struct problem_context pctx; |
| - | __u32 count; |
| - | |
| - | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
| - | e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); |
| - | inode.i_links_count = 0; |
| - | inode.i_dtime = time(NULL); |
| - | e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode"); |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | |
| - | /* |
| - | * Fix up the bitmaps... |
| - | */ |
| - | e2fsck_read_bitmaps(ctx); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
| - | if (ctx->inode_bad_map) |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); |
| - | ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); |
| - | |
| - | if (inode.i_file_acl && |
| - | (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { |
| - | pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl, |
| - | block_buf, -1, &count); |
| - | if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { |
| - | pctx.errcode = 0; |
| - | count = 1; |
| - | } |
| - | if (pctx.errcode) { |
| - | pctx.blk = inode.i_file_acl; |
| - | fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if (count == 0) { |
| - | ext2fs_unmark_block_bitmap(ctx->block_found_map, |
| - | inode.i_file_acl); |
| - | ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1); |
| - | } |
| - | inode.i_file_acl = 0; |
| - | } |
| - | |
| - | if (!ext2fs_inode_has_valid_blocks(&inode)) |
| - | return; |
| - | |
| - | if (LINUX_S_ISREG(inode.i_mode) && |
| - | (inode.i_size_high || inode.i_size & 0x80000000UL)) |
| - | ctx->large_files--; |
| - | |
| - | pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, |
| - | deallocate_inode_block, ctx); |
| - | if (pctx.errcode) { |
| - | fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * This function clears the htree flag on an inode |
| - | */ |
| - | static void clear_htree(e2fsck_t ctx, ext2_ino_t ino) |
| - | { |
| - | struct ext2_inode inode; |
| - | |
| - | e2fsck_read_inode(ctx, ino, &inode, "clear_htree"); |
| - | inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL; |
| - | e2fsck_write_inode(ctx, ino, &inode, "clear_htree"); |
| - | if (ctx->dirs_to_hash) |
| - | ext2fs_u32_list_add(ctx->dirs_to_hash, ino); |
| - | } |
| - | |
| - | |
| - | static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, |
| - | ext2_ino_t ino, char *buf) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct ext2_inode inode; |
| - | int inode_modified = 0; |
| - | int not_fixed = 0; |
| - | unsigned char *frag, *fsize; |
| - | struct problem_context pctx; |
| - | int problem = 0; |
| - | |
| - | e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode"); |
| - | |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | pctx.dir = dir; |
| - | pctx.inode = &inode; |
| - | |
| - | if (inode.i_file_acl && |
| - | !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) && |
| - | fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) { |
| - | inode.i_file_acl = 0; |
| - | #if BB_BIG_ENDIAN |
| - | /* |
| - | * This is a special kludge to deal with long symlinks |
| - | * on big endian systems. i_blocks had already been |
| - | * decremented earlier in pass 1, but since i_file_acl |
| - | * hadn't yet been cleared, ext2fs_read_inode() |
| - | * assumed that the file was short symlink and would |
| - | * not have byte swapped i_block[0]. Hence, we have |
| - | * to byte-swap it here. |
| - | */ |
| - | if (LINUX_S_ISLNK(inode.i_mode) && |
| - | (fs->flags & EXT2_FLAG_SWAP_BYTES) && |
| - | (inode.i_blocks == fs->blocksize >> 9)) |
| - | inode.i_block[0] = ext2fs_swab32(inode.i_block[0]); |
| - | #endif |
| - | inode_modified++; |
| - | } else |
| - | not_fixed++; |
| - | |
| - | if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) && |
| - | !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) && |
| - | !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) && |
| - | !(LINUX_S_ISSOCK(inode.i_mode))) |
| - | problem = PR_2_BAD_MODE; |
| - | else if (LINUX_S_ISCHR(inode.i_mode) |
| - | && !e2fsck_pass1_check_device_inode(fs, &inode)) |
| - | problem = PR_2_BAD_CHAR_DEV; |
| - | else if (LINUX_S_ISBLK(inode.i_mode) |
| - | && !e2fsck_pass1_check_device_inode(fs, &inode)) |
| - | problem = PR_2_BAD_BLOCK_DEV; |
| - | else if (LINUX_S_ISFIFO(inode.i_mode) |
| - | && !e2fsck_pass1_check_device_inode(fs, &inode)) |
| - | problem = PR_2_BAD_FIFO; |
| - | else if (LINUX_S_ISSOCK(inode.i_mode) |
| - | && !e2fsck_pass1_check_device_inode(fs, &inode)) |
| - | problem = PR_2_BAD_SOCKET; |
| - | else if (LINUX_S_ISLNK(inode.i_mode) |
| - | && !e2fsck_pass1_check_symlink(fs, &inode, buf)) { |
| - | problem = PR_2_INVALID_SYMLINK; |
| - | } |
| - | |
| - | if (problem) { |
| - | if (fix_problem(ctx, problem, &pctx)) { |
| - | deallocate_inode(ctx, ino, 0); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return 0; |
| - | return 1; |
| - | } else |
| - | not_fixed++; |
| - | problem = 0; |
| - | } |
| - | |
| - | if (inode.i_faddr) { |
| - | if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) { |
| - | inode.i_faddr = 0; |
| - | inode_modified++; |
| - | } else |
| - | not_fixed++; |
| - | } |
| - | |
| - | switch (fs->super->s_creator_os) { |
| - | case EXT2_OS_LINUX: |
| - | frag = &inode.osd2.linux2.l_i_frag; |
| - | fsize = &inode.osd2.linux2.l_i_fsize; |
| - | break; |
| - | case EXT2_OS_HURD: |
| - | frag = &inode.osd2.hurd2.h_i_frag; |
| - | fsize = &inode.osd2.hurd2.h_i_fsize; |
| - | break; |
| - | case EXT2_OS_MASIX: |
| - | frag = &inode.osd2.masix2.m_i_frag; |
| - | fsize = &inode.osd2.masix2.m_i_fsize; |
| - | break; |
| - | default: |
| - | frag = fsize = 0; |
| - | } |
| - | if (frag && *frag) { |
| - | pctx.num = *frag; |
| - | if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) { |
| - | *frag = 0; |
| - | inode_modified++; |
| - | } else |
| - | not_fixed++; |
| - | pctx.num = 0; |
| - | } |
| - | if (fsize && *fsize) { |
| - | pctx.num = *fsize; |
| - | if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) { |
| - | *fsize = 0; |
| - | inode_modified++; |
| - | } else |
| - | not_fixed++; |
| - | pctx.num = 0; |
| - | } |
| - | |
| - | if (inode.i_file_acl && |
| - | ((inode.i_file_acl < fs->super->s_first_data_block) || |
| - | (inode.i_file_acl >= fs->super->s_blocks_count))) { |
| - | if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) { |
| - | inode.i_file_acl = 0; |
| - | inode_modified++; |
| - | } else |
| - | not_fixed++; |
| - | } |
| - | if (inode.i_dir_acl && |
| - | LINUX_S_ISDIR(inode.i_mode)) { |
| - | if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) { |
| - | inode.i_dir_acl = 0; |
| - | inode_modified++; |
| - | } else |
| - | not_fixed++; |
| - | } |
| - | |
| - | if (inode_modified) |
| - | e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode"); |
| - | if (!not_fixed) |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * allocate_dir_block --- this function allocates a new directory |
| - | * block for a particular inode; this is done if a directory has |
| - | * a "hole" in it, or if a directory has a illegal block number |
| - | * that was zeroed out and now needs to be replaced. |
| - | */ |
| - | static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db, |
| - | struct problem_context *pctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t blk; |
| - | char *block; |
| - | struct ext2_inode inode; |
| - | |
| - | if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0) |
| - | return 1; |
| - | |
| - | /* |
| - | * Read the inode and block bitmaps in; we'll be messing with |
| - | * them. |
| - | */ |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | /* |
| - | * First, find a free block |
| - | */ |
| - | pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); |
| - | if (pctx->errcode) { |
| - | pctx->str = "ext2fs_new_block"; |
| - | fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); |
| - | return 1; |
| - | } |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, blk); |
| - | ext2fs_mark_block_bitmap(fs->block_map, blk); |
| - | ext2fs_mark_bb_dirty(fs); |
| - | |
| - | /* |
| - | * Now let's create the actual data block for the inode |
| - | */ |
| - | if (db->blockcnt) |
| - | pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block); |
| - | else |
| - | pctx->errcode = ext2fs_new_dir_block(fs, db->ino, |
| - | EXT2_ROOT_INO, &block); |
| - | |
| - | if (pctx->errcode) { |
| - | pctx->str = "ext2fs_new_dir_block"; |
| - | fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); |
| - | return 1; |
| - | } |
| - | |
| - | pctx->errcode = ext2fs_write_dir_block(fs, blk, block); |
| - | ext2fs_free_mem(&block); |
| - | if (pctx->errcode) { |
| - | pctx->str = "ext2fs_write_dir_block"; |
| - | fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * Update the inode block count |
| - | */ |
| - | e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block"); |
| - | inode.i_blocks += fs->blocksize / 512; |
| - | if (inode.i_size < (db->blockcnt+1) * fs->blocksize) |
| - | inode.i_size = (db->blockcnt+1) * fs->blocksize; |
| - | e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block"); |
| - | |
| - | /* |
| - | * Finally, update the block pointers for the inode |
| - | */ |
| - | db->blk = blk; |
| - | pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE, |
| - | 0, update_dir_block, db); |
| - | if (pctx->errcode) { |
| - | pctx->str = "ext2fs_block_iterate"; |
| - | fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); |
| - | return 1; |
| - | } |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This is a helper function for allocate_dir_block(). |
| - | */ |
| - | static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)), |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct ext2_db_entry *db; |
| - | |
| - | db = (struct ext2_db_entry *) priv_data; |
| - | if (db->blockcnt == (int) blockcnt) { |
| - | *block_nr = db->blk; |
| - | return BLOCK_CHANGED; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * pass3.c -- pass #3 of e2fsck: Check for directory connectivity |
| - | * |
| - | * Pass #3 assures that all directories are connected to the |
| - | * filesystem tree, using the following algorithm: |
| - | * |
| - | * First, the root directory is checked to make sure it exists; if |
| - | * not, e2fsck will offer to create a new one. It is then marked as |
| - | * "done". |
| - | * |
| - | * Then, pass3 interates over all directory inodes; for each directory |
| - | * it attempts to trace up the filesystem tree, using dirinfo.parent |
| - | * until it reaches a directory which has been marked "done". If it |
| - | * cannot do so, then the directory must be disconnected, and e2fsck |
| - | * will offer to reconnect it to /lost+found. While it is chasing |
| - | * parent pointers up the filesystem tree, if pass3 sees a directory |
| - | * twice, then it has detected a filesystem loop, and it will again |
| - | * offer to reconnect the directory to /lost+found in to break the |
| - | * filesystem loop. |
| - | * |
| - | * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to |
| - | * reconnect inodes to /lost+found; this subroutine is also used by |
| - | * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which |
| - | * is responsible for creating /lost+found if it does not exist. |
| - | * |
| - | * Pass 3 frees the following data structures: |
| - | * - The dirinfo directory information cache. |
| - | */ |
| - | |
| - | static void check_root(e2fsck_t ctx); |
| - | static int check_directory(e2fsck_t ctx, struct dir_info *dir, |
| - | struct problem_context *pctx); |
| - | static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent); |
| - | |
| - | static ext2fs_inode_bitmap inode_loop_detect; |
| - | static ext2fs_inode_bitmap inode_done_map; |
| - | |
| - | static void e2fsck_pass3(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | int i; |
| - | struct problem_context pctx; |
| - | struct dir_info *dir; |
| - | unsigned long maxdirs, count; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | /* Pass 3 */ |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_3_PASS_HEADER, &pctx); |
| - | |
| - | /* |
| - | * Allocate some bitmaps to do loop detection. |
| - | */ |
| - | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"), |
| - | &inode_done_map); |
| - | if (pctx.errcode) { |
| - | pctx.num = 2; |
| - | fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | goto abort_exit; |
| - | } |
| - | check_root(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | goto abort_exit; |
| - | |
| - | ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO); |
| - | |
| - | maxdirs = e2fsck_get_num_dirinfo(ctx); |
| - | count = 1; |
| - | |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 3, 0, maxdirs)) |
| - | goto abort_exit; |
| - | |
| - | for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) { |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | goto abort_exit; |
| - | if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) |
| - | goto abort_exit; |
| - | if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino)) |
| - | if (check_directory(ctx, dir, &pctx)) |
| - | goto abort_exit; |
| - | } |
| - | |
| - | /* |
| - | * Force the creation of /lost+found if not present |
| - | */ |
| - | if ((ctx->flags & E2F_OPT_READONLY) == 0) |
| - | e2fsck_get_lost_and_found(ctx, 1); |
| - | |
| - | /* |
| - | * If there are any directories that need to be indexed or |
| - | * optimized, do it here. |
| - | */ |
| - | e2fsck_rehash_directories(ctx); |
| - | |
| - | abort_exit: |
| - | e2fsck_free_dir_info(ctx); |
| - | ext2fs_free_inode_bitmap(inode_loop_detect); |
| - | inode_loop_detect = 0; |
| - | ext2fs_free_inode_bitmap(inode_done_map); |
| - | inode_done_map = 0; |
| - | } |
| - | |
| - | /* |
| - | * This makes sure the root inode is present; if not, we ask if the |
| - | * user wants us to create it. Not creating it is a fatal error. |
| - | */ |
| - | static void check_root(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t blk; |
| - | struct ext2_inode inode; |
| - | char * block; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) { |
| - | /* |
| - | * If the root inode is not a directory, die here. The |
| - | * user must have answered 'no' in pass1 when we |
| - | * offered to clear it. |
| - | */ |
| - | if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map, |
| - | EXT2_ROOT_INO))) { |
| - | fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | } |
| - | return; |
| - | } |
| - | |
| - | if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { |
| - | fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | /* |
| - | * First, find a free block |
| - | */ |
| - | pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_new_block"; |
| - | fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, blk); |
| - | ext2fs_mark_block_bitmap(fs->block_map, blk); |
| - | ext2fs_mark_bb_dirty(fs); |
| - | |
| - | /* |
| - | * Now let's create the actual data block for the inode |
| - | */ |
| - | pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, |
| - | &block); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_new_dir_block"; |
| - | fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | pctx.errcode = ext2fs_write_dir_block(fs, blk, block); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_write_dir_block"; |
| - | fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ext2fs_free_mem(&block); |
| - | |
| - | /* |
| - | * Set up the inode structure |
| - | */ |
| - | memset(&inode, 0, sizeof(inode)); |
| - | inode.i_mode = 040755; |
| - | inode.i_size = fs->blocksize; |
| - | inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL); |
| - | inode.i_links_count = 2; |
| - | inode.i_blocks = fs->blocksize / 512; |
| - | inode.i_block[0] = blk; |
| - | |
| - | /* |
| - | * Write out the inode. |
| - | */ |
| - | pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_write_inode"; |
| - | fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | /* |
| - | * Miscellaneous bookkeeping... |
| - | */ |
| - | e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); |
| - | ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); |
| - | ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); |
| - | |
| - | ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO); |
| - | ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO); |
| - | ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO); |
| - | ext2fs_mark_ib_dirty(fs); |
| - | } |
| - | |
| - | /* |
| - | * This subroutine is responsible for making sure that a particular |
| - | * directory is connected to the root; if it isn't we trace it up as |
| - | * far as we can go, and then offer to connect the resulting parent to |
| - | * the lost+found. We have to do loop detection; if we ever discover |
| - | * a loop, we treat that as a disconnected directory and offer to |
| - | * reparent it to lost+found. |
| - | * |
| - | * However, loop detection is expensive, because for very large |
| - | * filesystems, the inode_loop_detect bitmap is huge, and clearing it |
| - | * is non-trivial. Loops in filesystems are also a rare error case, |
| - | * and we shouldn't optimize for error cases. So we try two passes of |
| - | * the algorithm. The first time, we ignore loop detection and merely |
| - | * increment a counter; if the counter exceeds some extreme threshold, |
| - | * then we try again with the loop detection bitmap enabled. |
| - | */ |
| - | static int check_directory(e2fsck_t ctx, struct dir_info *dir, |
| - | struct problem_context *pctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct dir_info *p = dir; |
| - | int loop_pass = 0, parent_count = 0; |
| - | |
| - | if (!p) |
| - | return 0; |
| - | |
| - | while (1) { |
| - | /* |
| - | * Mark this inode as being "done"; by the time we |
| - | * return from this function, the inode we either be |
| - | * verified as being connected to the directory tree, |
| - | * or we will have offered to reconnect this to |
| - | * lost+found. |
| - | * |
| - | * If it was marked done already, then we've reached a |
| - | * parent we've already checked. |
| - | */ |
| - | if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino)) |
| - | break; |
| - | |
| - | /* |
| - | * If this directory doesn't have a parent, or we've |
| - | * seen the parent once already, then offer to |
| - | * reparent it to lost+found |
| - | */ |
| - | if (!p->parent || |
| - | (loop_pass && |
| - | (ext2fs_test_inode_bitmap(inode_loop_detect, |
| - | p->parent)))) { |
| - | pctx->ino = p->ino; |
| - | if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) { |
| - | if (e2fsck_reconnect_file(ctx, pctx->ino)) |
| - | ext2fs_unmark_valid(fs); |
| - | else { |
| - | p = e2fsck_get_dir_info(ctx, pctx->ino); |
| - | p->parent = ctx->lost_and_found; |
| - | fix_dotdot(ctx, p, ctx->lost_and_found); |
| - | } |
| - | } |
| - | break; |
| - | } |
| - | p = e2fsck_get_dir_info(ctx, p->parent); |
| - | if (!p) { |
| - | fix_problem(ctx, PR_3_NO_DIRINFO, pctx); |
| - | return 0; |
| - | } |
| - | if (loop_pass) { |
| - | ext2fs_mark_inode_bitmap(inode_loop_detect, |
| - | p->ino); |
| - | } else if (parent_count++ > 2048) { |
| - | /* |
| - | * If we've run into a path depth that's |
| - | * greater than 2048, try again with the inode |
| - | * loop bitmap turned on and start from the |
| - | * top. |
| - | */ |
| - | loop_pass = 1; |
| - | if (inode_loop_detect) |
| - | ext2fs_clear_inode_bitmap(inode_loop_detect); |
| - | else { |
| - | pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect); |
| - | if (pctx->errcode) { |
| - | pctx->num = 1; |
| - | fix_problem(ctx, |
| - | PR_3_ALLOCATE_IBITMAP_ERROR, pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return -1; |
| - | } |
| - | } |
| - | p = dir; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Make sure that .. and the parent directory are the same; |
| - | * offer to fix it if not. |
| - | */ |
| - | if (dir->parent != dir->dotdot) { |
| - | pctx->ino = dir->ino; |
| - | pctx->ino2 = dir->dotdot; |
| - | pctx->dir = dir->parent; |
| - | if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx)) |
| - | fix_dotdot(ctx, dir, dir->parent); |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This routine gets the lost_and_found inode, making it a directory |
| - | * if necessary |
| - | */ |
| - | ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t ino; |
| - | blk_t blk; |
| - | errcode_t retval; |
| - | struct ext2_inode inode; |
| - | char * block; |
| - | static const char name[] = "lost+found"; |
| - | struct problem_context pctx; |
| - | struct dir_info *dirinfo; |
| - | |
| - | if (ctx->lost_and_found) |
| - | return ctx->lost_and_found; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, |
| - | sizeof(name)-1, 0, &ino); |
| - | if (retval && !fix) |
| - | return 0; |
| - | if (!retval) { |
| - | if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) { |
| - | ctx->lost_and_found = ino; |
| - | return ino; |
| - | } |
| - | |
| - | /* Lost+found isn't a directory! */ |
| - | if (!fix) |
| - | return 0; |
| - | pctx.ino = ino; |
| - | if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) |
| - | return 0; |
| - | |
| - | /* OK, unlink the old /lost+found file. */ |
| - | pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_unlink"; |
| - | fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); |
| - | return 0; |
| - | } |
| - | dirinfo = e2fsck_get_dir_info(ctx, ino); |
| - | if (dirinfo) |
| - | dirinfo->parent = 0; |
| - | e2fsck_adjust_inode_count(ctx, ino, -1); |
| - | } else if (retval != EXT2_ET_FILE_NOT_FOUND) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); |
| - | } |
| - | if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) |
| - | return 0; |
| - | |
| - | /* |
| - | * Read the inode and block bitmaps in; we'll be messing with |
| - | * them. |
| - | */ |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | /* |
| - | * First, find a free block |
| - | */ |
| - | retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); |
| - | return 0; |
| - | } |
| - | ext2fs_mark_block_bitmap(ctx->block_found_map, blk); |
| - | ext2fs_block_alloc_stats(fs, blk, +1); |
| - | |
| - | /* |
| - | * Next find a free inode. |
| - | */ |
| - | retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, |
| - | ctx->inode_used_map, &ino); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); |
| - | return 0; |
| - | } |
| - | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
| - | ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); |
| - | ext2fs_inode_alloc_stats2(fs, ino, +1, 1); |
| - | |
| - | /* |
| - | * Now let's create the actual data block for the inode |
| - | */ |
| - | retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); |
| - | return 0; |
| - | } |
| - | |
| - | retval = ext2fs_write_dir_block(fs, blk, block); |
| - | ext2fs_free_mem(&block); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Set up the inode structure |
| - | */ |
| - | memset(&inode, 0, sizeof(inode)); |
| - | inode.i_mode = 040700; |
| - | inode.i_size = fs->blocksize; |
| - | inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL); |
| - | inode.i_links_count = 2; |
| - | inode.i_blocks = fs->blocksize / 512; |
| - | inode.i_block[0] = blk; |
| - | |
| - | /* |
| - | * Next, write out the inode. |
| - | */ |
| - | pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_write_inode"; |
| - | fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); |
| - | return 0; |
| - | } |
| - | /* |
| - | * Finally, create the directory link |
| - | */ |
| - | pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); |
| - | if (pctx.errcode) { |
| - | pctx.str = "ext2fs_link"; |
| - | fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Miscellaneous bookkeeping that needs to be kept straight. |
| - | */ |
| - | e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); |
| - | e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); |
| - | ext2fs_icount_store(ctx->inode_count, ino, 2); |
| - | ext2fs_icount_store(ctx->inode_link_info, ino, 2); |
| - | ctx->lost_and_found = ino; |
| - | return ino; |
| - | } |
| - | |
| - | /* |
| - | * This routine will connect a file to lost+found |
| - | */ |
| - | int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | char name[80]; |
| - | struct problem_context pctx; |
| - | struct ext2_inode inode; |
| - | int file_type = 0; |
| - | |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | |
| - | if (!ctx->bad_lost_and_found && !ctx->lost_and_found) { |
| - | if (e2fsck_get_lost_and_found(ctx, 1) == 0) |
| - | ctx->bad_lost_and_found++; |
| - | } |
| - | if (ctx->bad_lost_and_found) { |
| - | fix_problem(ctx, PR_3_NO_LPF, &pctx); |
| - | return 1; |
| - | } |
| - | |
| - | sprintf(name, "#%u", ino); |
| - | if (ext2fs_read_inode(fs, ino, &inode) == 0) |
| - | file_type = ext2_file_type(inode.i_mode); |
| - | retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); |
| - | if (retval == EXT2_ET_DIR_NO_SPACE) { |
| - | if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) |
| - | return 1; |
| - | retval = e2fsck_expand_directory(ctx, ctx->lost_and_found, |
| - | 1, 0); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); |
| - | return 1; |
| - | } |
| - | retval = ext2fs_link(fs, ctx->lost_and_found, name, |
| - | ino, file_type); |
| - | } |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); |
| - | return 1; |
| - | } |
| - | e2fsck_adjust_inode_count(ctx, ino, 1); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Utility routine to adjust the inode counts on an inode. |
| - | */ |
| - | errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | struct ext2_inode inode; |
| - | |
| - | if (!ino) |
| - | return 0; |
| - | |
| - | retval = ext2fs_read_inode(fs, ino, &inode); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | if (adj == 1) { |
| - | ext2fs_icount_increment(ctx->inode_count, ino, 0); |
| - | if (inode.i_links_count == (__u16) ~0) |
| - | return 0; |
| - | ext2fs_icount_increment(ctx->inode_link_info, ino, 0); |
| - | inode.i_links_count++; |
| - | } else if (adj == -1) { |
| - | ext2fs_icount_decrement(ctx->inode_count, ino, 0); |
| - | if (inode.i_links_count == 0) |
| - | return 0; |
| - | ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); |
| - | inode.i_links_count--; |
| - | } |
| - | |
| - | retval = ext2fs_write_inode(fs, ino, &inode); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Fix parent --- this routine fixes up the parent of a directory. |
| - | */ |
| - | struct fix_dotdot_struct { |
| - | ext2_filsys fs; |
| - | ext2_ino_t parent; |
| - | int done; |
| - | e2fsck_t ctx; |
| - | }; |
| - | |
| - | static int fix_dotdot_proc(struct ext2_dir_entry *dirent, |
| - | int offset FSCK_ATTR((unused)), |
| - | int blocksize FSCK_ATTR((unused)), |
| - | char *buf FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data; |
| - | errcode_t retval; |
| - | struct problem_context pctx; |
| - | |
| - | if ((dirent->name_len & 0xFF) != 2) |
| - | return 0; |
| - | if (strncmp(dirent->name, "..", 2)) |
| - | return 0; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); |
| - | } |
| - | retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx); |
| - | } |
| - | dirent->inode = fp->parent; |
| - | |
| - | fp->done++; |
| - | return DIRENT_ABORT | DIRENT_CHANGED; |
| - | } |
| - | |
| - | static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | struct fix_dotdot_struct fp; |
| - | struct problem_context pctx; |
| - | |
| - | fp.fs = fs; |
| - | fp.parent = parent; |
| - | fp.done = 0; |
| - | fp.ctx = ctx; |
| - | |
| - | retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY, |
| - | 0, fix_dotdot_proc, &fp); |
| - | if (retval || !fp.done) { |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = dir->ino; |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR : |
| - | PR_3_FIX_PARENT_NOFIND, &pctx); |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | dir->dotdot = parent; |
| - | } |
| - | |
| - | /* |
| - | * These routines are responsible for expanding a /lost+found if it is |
| - | * too small. |
| - | */ |
| - | |
| - | struct expand_dir_struct { |
| - | int num; |
| - | int guaranteed_size; |
| - | int newblocks; |
| - | int last_block; |
| - | errcode_t err; |
| - | e2fsck_t ctx; |
| - | }; |
| - | |
| - | static int expand_dir_proc(ext2_filsys fs, |
| - | blk_t *blocknr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_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; |
| - | e2fsck_t ctx; |
| - | |
| - | ctx = es->ctx; |
| - | |
| - | if (es->guaranteed_size && blockcnt >= es->guaranteed_size) |
| - | return BLOCK_ABORT; |
| - | |
| - | if (blockcnt > 0) |
| - | es->last_block = blockcnt; |
| - | if (*blocknr) { |
| - | last_blk = *blocknr; |
| - | return 0; |
| - | } |
| - | retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map, |
| - | &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->num--; |
| - | 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_mark_block_bitmap(ctx->block_found_map, new_blk); |
| - | ext2fs_block_alloc_stats(fs, new_blk, +1); |
| - | es->newblocks++; |
| - | |
| - | if (es->num == 0) |
| - | return (BLOCK_CHANGED | BLOCK_ABORT); |
| - | else |
| - | return BLOCK_CHANGED; |
| - | } |
| - | |
| - | errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, |
| - | int num, int guaranteed_size) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | struct expand_dir_struct es; |
| - | struct ext2_inode inode; |
| - | |
| - | if (!(fs->flags & EXT2_FLAG_RW)) |
| - | return EXT2_ET_RO_FILSYS; |
| - | |
| - | /* |
| - | * Read the inode and block bitmaps in; we'll be messing with |
| - | * them. |
| - | */ |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | retval = ext2fs_check_directory(fs, dir); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | es.num = num; |
| - | es.guaranteed_size = guaranteed_size; |
| - | es.last_block = 0; |
| - | es.err = 0; |
| - | es.newblocks = 0; |
| - | es.ctx = ctx; |
| - | |
| - | retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, |
| - | 0, expand_dir_proc, &es); |
| - | |
| - | if (es.err) |
| - | return es.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 = (es.last_block + 1) * fs->blocksize; |
| - | inode.i_blocks += (fs->blocksize / 512) * es.newblocks; |
| - | |
| - | e2fsck_write_inode(ctx, dir, &inode, "expand_directory"); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * pass4.c -- pass #4 of e2fsck: Check reference counts |
| - | * |
| - | * Pass 4 frees the following data structures: |
| - | * - A bitmap of which inodes are imagic inodes. (inode_imagic_map) |
| - | */ |
| - | |
| - | /* |
| - | * This routine is called when an inode is not connected to the |
| - | * directory tree. |
| - | * |
| - | * This subroutine returns 1 then the caller shouldn't bother with the |
| - | * rest of the pass 4 tests. |
| - | */ |
| - | static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct ext2_inode inode; |
| - | struct problem_context pctx; |
| - | |
| - | e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode"); |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = i; |
| - | pctx.inode = &inode; |
| - | |
| - | /* |
| - | * Offer to delete any zero-length files that does not have |
| - | * blocks. If there is an EA block, it might have useful |
| - | * information, so we won't prompt to delete it, but let it be |
| - | * reconnected to lost+found. |
| - | */ |
| - | if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) || |
| - | LINUX_S_ISDIR(inode.i_mode))) { |
| - | if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) { |
| - | ext2fs_icount_store(ctx->inode_link_info, i, 0); |
| - | inode.i_links_count = 0; |
| - | inode.i_dtime = time(NULL); |
| - | e2fsck_write_inode(ctx, i, &inode, |
| - | "disconnect_inode"); |
| - | /* |
| - | * Fix up the bitmaps... |
| - | */ |
| - | e2fsck_read_bitmaps(ctx); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i); |
| - | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i); |
| - | ext2fs_inode_alloc_stats2(fs, i, -1, |
| - | LINUX_S_ISDIR(inode.i_mode)); |
| - | return 0; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Prompt to reconnect. |
| - | */ |
| - | if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) { |
| - | if (e2fsck_reconnect_file(ctx, i)) |
| - | ext2fs_unmark_valid(fs); |
| - | } else { |
| - | /* |
| - | * If we don't attach the inode, then skip the |
| - | * i_links_test since there's no point in trying to |
| - | * force i_links_count to zero. |
| - | */ |
| - | ext2fs_unmark_valid(fs); |
| - | return 1; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | static void e2fsck_pass4(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t i; |
| - | struct ext2_inode inode; |
| - | struct problem_context pctx; |
| - | __u16 link_count, link_counted; |
| - | char *buf = NULL; |
| - | int group, maxgroup; |
| - | |
| - | /* Pass 4 */ |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_4_PASS_HEADER, &pctx); |
| - | |
| - | group = 0; |
| - | maxgroup = fs->group_desc_count; |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 4, 0, maxgroup)) |
| - | return; |
| - | |
| - | for (i=1; i <= fs->super->s_inodes_count; i++) { |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | if ((i % fs->super->s_inodes_per_group) == 0) { |
| - | group++; |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 4, group, maxgroup)) |
| - | return; |
| - | } |
| - | if (i == EXT2_BAD_INO || |
| - | (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super))) |
| - | continue; |
| - | if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) || |
| - | (ctx->inode_imagic_map && |
| - | ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i))) |
| - | continue; |
| - | ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); |
| - | ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); |
| - | if (link_counted == 0) { |
| - | if (!buf) |
| - | buf = e2fsck_allocate_memory(ctx, |
| - | fs->blocksize, "bad_inode buffer"); |
| - | if (e2fsck_process_bad_inode(ctx, 0, i, buf)) |
| - | continue; |
| - | if (disconnect_inode(ctx, i)) |
| - | continue; |
| - | ext2fs_icount_fetch(ctx->inode_link_info, i, |
| - | &link_count); |
| - | ext2fs_icount_fetch(ctx->inode_count, i, |
| - | &link_counted); |
| - | } |
| - | if (link_counted != link_count) { |
| - | e2fsck_read_inode(ctx, i, &inode, "pass4"); |
| - | pctx.ino = i; |
| - | pctx.inode = &inode; |
| - | if (link_count != inode.i_links_count) { |
| - | pctx.num = link_count; |
| - | fix_problem(ctx, |
| - | PR_4_INCONSISTENT_COUNT, &pctx); |
| - | } |
| - | pctx.num = link_counted; |
| - | if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) { |
| - | inode.i_links_count = link_counted; |
| - | e2fsck_write_inode(ctx, i, &inode, "pass4"); |
| - | } |
| - | } |
| - | } |
| - | ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; |
| - | ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_imagic_map); |
| - | ctx->inode_imagic_map = 0; |
| - | ext2fs_free_mem(&buf); |
| - | } |
| - | |
| - | /* |
| - | * pass5.c --- check block and inode bitmaps against on-disk bitmaps |
| - | */ |
| - | |
| - | #define NO_BLK ((blk_t) -1) |
| - | |
| - | static void print_bitmap_problem(e2fsck_t ctx, int problem, |
| - | struct problem_context *pctx) |
| - | { |
| - | switch (problem) { |
| - | case PR_5_BLOCK_UNUSED: |
| - | if (pctx->blk == pctx->blk2) |
| - | pctx->blk2 = 0; |
| - | else |
| - | problem = PR_5_BLOCK_RANGE_UNUSED; |
| - | break; |
| - | case PR_5_BLOCK_USED: |
| - | if (pctx->blk == pctx->blk2) |
| - | pctx->blk2 = 0; |
| - | else |
| - | problem = PR_5_BLOCK_RANGE_USED; |
| - | break; |
| - | case PR_5_INODE_UNUSED: |
| - | if (pctx->ino == pctx->ino2) |
| - | pctx->ino2 = 0; |
| - | else |
| - | problem = PR_5_INODE_RANGE_UNUSED; |
| - | break; |
| - | case PR_5_INODE_USED: |
| - | if (pctx->ino == pctx->ino2) |
| - | pctx->ino2 = 0; |
| - | else |
| - | problem = PR_5_INODE_RANGE_USED; |
| - | break; |
| - | } |
| - | fix_problem(ctx, problem, pctx); |
| - | pctx->blk = pctx->blk2 = NO_BLK; |
| - | pctx->ino = pctx->ino2 = 0; |
| - | } |
| - | |
| - | static void check_block_bitmaps(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t i; |
| - | int *free_array; |
| - | int group = 0; |
| - | unsigned int blocks = 0; |
| - | unsigned int free_blocks = 0; |
| - | int group_free = 0; |
| - | int actual, bitmap; |
| - | struct problem_context pctx; |
| - | int problem, save_problem, fixit, had_problem; |
| - | errcode_t retval; |
| - | |
| - | clear_problem_context(&pctx); |
| - | free_array = (int *) e2fsck_allocate_memory(ctx, |
| - | fs->group_desc_count * sizeof(int), "free block count array"); |
| - | |
| - | if ((fs->super->s_first_data_block < |
| - | ext2fs_get_block_bitmap_start(ctx->block_found_map)) || |
| - | (fs->super->s_blocks_count-1 > |
| - | ext2fs_get_block_bitmap_end(ctx->block_found_map))) { |
| - | pctx.num = 1; |
| - | pctx.blk = fs->super->s_first_data_block; |
| - | pctx.blk2 = fs->super->s_blocks_count -1; |
| - | pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map); |
| - | pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map); |
| - | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
| - | |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | |
| - | if ((fs->super->s_first_data_block < |
| - | ext2fs_get_block_bitmap_start(fs->block_map)) || |
| - | (fs->super->s_blocks_count-1 > |
| - | ext2fs_get_block_bitmap_end(fs->block_map))) { |
| - | pctx.num = 2; |
| - | pctx.blk = fs->super->s_first_data_block; |
| - | pctx.blk2 = fs->super->s_blocks_count -1; |
| - | pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map); |
| - | pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map); |
| - | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
| - | |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | |
| - | redo_counts: |
| - | had_problem = 0; |
| - | save_problem = 0; |
| - | pctx.blk = pctx.blk2 = NO_BLK; |
| - | for (i = fs->super->s_first_data_block; |
| - | i < fs->super->s_blocks_count; |
| - | i++) { |
| - | actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i); |
| - | bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i); |
| - | |
| - | if (actual == bitmap) |
| - | goto do_counts; |
| - | |
| - | if (!actual && bitmap) { |
| - | /* |
| - | * Block not used, but marked in use in the bitmap. |
| - | */ |
| - | problem = PR_5_BLOCK_UNUSED; |
| - | } else { |
| - | /* |
| - | * Block used, but not marked in use in the bitmap. |
| - | */ |
| - | problem = PR_5_BLOCK_USED; |
| - | } |
| - | if (pctx.blk == NO_BLK) { |
| - | pctx.blk = pctx.blk2 = i; |
| - | save_problem = problem; |
| - | } else { |
| - | if ((problem == save_problem) && |
| - | (pctx.blk2 == i-1)) |
| - | pctx.blk2++; |
| - | else { |
| - | print_bitmap_problem(ctx, save_problem, &pctx); |
| - | pctx.blk = pctx.blk2 = i; |
| - | save_problem = problem; |
| - | } |
| - | } |
| - | ctx->flags |= E2F_FLAG_PROG_SUPPRESS; |
| - | had_problem++; |
| - | |
| - | do_counts: |
| - | if (!bitmap) { |
| - | group_free++; |
| - | free_blocks++; |
| - | } |
| - | blocks ++; |
| - | if ((blocks == fs->super->s_blocks_per_group) || |
| - | (i == fs->super->s_blocks_count-1)) { |
| - | free_array[group] = group_free; |
| - | group ++; |
| - | blocks = 0; |
| - | group_free = 0; |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 5, group, |
| - | fs->group_desc_count*2)) |
| - | return; |
| - | } |
| - | } |
| - | if (pctx.blk != NO_BLK) |
| - | print_bitmap_problem(ctx, save_problem, &pctx); |
| - | if (had_problem) |
| - | fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP); |
| - | else |
| - | fixit = -1; |
| - | ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; |
| - | |
| - | if (fixit == 1) { |
| - | ext2fs_free_block_bitmap(fs->block_map); |
| - | retval = ext2fs_copy_bitmap(ctx->block_found_map, |
| - | &fs->block_map); |
| - | if (retval) { |
| - | clear_problem_context(&pctx); |
| - | fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ext2fs_set_bitmap_padding(fs->block_map); |
| - | ext2fs_mark_bb_dirty(fs); |
| - | |
| - | /* Redo the counts */ |
| - | blocks = 0; free_blocks = 0; group_free = 0; group = 0; |
| - | memset(free_array, 0, fs->group_desc_count * sizeof(int)); |
| - | goto redo_counts; |
| - | } else if (fixit == 0) |
| - | ext2fs_unmark_valid(fs); |
| - | |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) { |
| - | pctx.group = i; |
| - | pctx.blk = fs->group_desc[i].bg_free_blocks_count; |
| - | pctx.blk2 = free_array[i]; |
| - | |
| - | if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP, |
| - | &pctx)) { |
| - | fs->group_desc[i].bg_free_blocks_count = |
| - | free_array[i]; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | } |
| - | if (free_blocks != fs->super->s_free_blocks_count) { |
| - | pctx.group = 0; |
| - | pctx.blk = fs->super->s_free_blocks_count; |
| - | pctx.blk2 = free_blocks; |
| - | |
| - | if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) { |
| - | fs->super->s_free_blocks_count = free_blocks; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | ext2fs_free_mem(&free_array); |
| - | } |
| - | |
| - | static void check_inode_bitmaps(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t i; |
| - | unsigned int free_inodes = 0; |
| - | int group_free = 0; |
| - | int dirs_count = 0; |
| - | int group = 0; |
| - | unsigned int inodes = 0; |
| - | int *free_array; |
| - | int *dir_array; |
| - | int actual, bitmap; |
| - | errcode_t retval; |
| - | struct problem_context pctx; |
| - | int problem, save_problem, fixit, had_problem; |
| - | |
| - | clear_problem_context(&pctx); |
| - | free_array = (int *) e2fsck_allocate_memory(ctx, |
| - | fs->group_desc_count * sizeof(int), "free inode count array"); |
| - | |
| - | dir_array = (int *) e2fsck_allocate_memory(ctx, |
| - | fs->group_desc_count * sizeof(int), "directory count array"); |
| - | |
| - | if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) || |
| - | (fs->super->s_inodes_count > |
| - | ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) { |
| - | pctx.num = 3; |
| - | pctx.blk = 1; |
| - | pctx.blk2 = fs->super->s_inodes_count; |
| - | pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map); |
| - | pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map); |
| - | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
| - | |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) || |
| - | (fs->super->s_inodes_count > |
| - | ext2fs_get_inode_bitmap_end(fs->inode_map))) { |
| - | pctx.num = 4; |
| - | pctx.blk = 1; |
| - | pctx.blk2 = fs->super->s_inodes_count; |
| - | pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map); |
| - | pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map); |
| - | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
| - | |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | |
| - | redo_counts: |
| - | had_problem = 0; |
| - | save_problem = 0; |
| - | pctx.ino = pctx.ino2 = 0; |
| - | for (i = 1; i <= fs->super->s_inodes_count; i++) { |
| - | actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i); |
| - | bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i); |
| - | |
| - | if (actual == bitmap) |
| - | goto do_counts; |
| - | |
| - | if (!actual && bitmap) { |
| - | /* |
| - | * Inode wasn't used, but marked in bitmap |
| - | */ |
| - | problem = PR_5_INODE_UNUSED; |
| - | } else /* if (actual && !bitmap) */ { |
| - | /* |
| - | * Inode used, but not in bitmap |
| - | */ |
| - | problem = PR_5_INODE_USED; |
| - | } |
| - | if (pctx.ino == 0) { |
| - | pctx.ino = pctx.ino2 = i; |
| - | save_problem = problem; |
| - | } else { |
| - | if ((problem == save_problem) && |
| - | (pctx.ino2 == i-1)) |
| - | pctx.ino2++; |
| - | else { |
| - | print_bitmap_problem(ctx, save_problem, &pctx); |
| - | pctx.ino = pctx.ino2 = i; |
| - | save_problem = problem; |
| - | } |
| - | } |
| - | ctx->flags |= E2F_FLAG_PROG_SUPPRESS; |
| - | had_problem++; |
| - | |
| - | do_counts: |
| - | if (!bitmap) { |
| - | group_free++; |
| - | free_inodes++; |
| - | } else { |
| - | if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i)) |
| - | dirs_count++; |
| - | } |
| - | inodes++; |
| - | if ((inodes == fs->super->s_inodes_per_group) || |
| - | (i == fs->super->s_inodes_count)) { |
| - | free_array[group] = group_free; |
| - | dir_array[group] = dirs_count; |
| - | group ++; |
| - | inodes = 0; |
| - | group_free = 0; |
| - | dirs_count = 0; |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 5, |
| - | group + fs->group_desc_count, |
| - | fs->group_desc_count*2)) |
| - | return; |
| - | } |
| - | } |
| - | if (pctx.ino) |
| - | print_bitmap_problem(ctx, save_problem, &pctx); |
| - | |
| - | if (had_problem) |
| - | fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP); |
| - | else |
| - | fixit = -1; |
| - | ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; |
| - | |
| - | if (fixit == 1) { |
| - | ext2fs_free_inode_bitmap(fs->inode_map); |
| - | retval = ext2fs_copy_bitmap(ctx->inode_used_map, |
| - | &fs->inode_map); |
| - | if (retval) { |
| - | clear_problem_context(&pctx); |
| - | fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | ext2fs_set_bitmap_padding(fs->inode_map); |
| - | ext2fs_mark_ib_dirty(fs); |
| - | |
| - | /* redo counts */ |
| - | inodes = 0; free_inodes = 0; group_free = 0; |
| - | dirs_count = 0; group = 0; |
| - | memset(free_array, 0, fs->group_desc_count * sizeof(int)); |
| - | memset(dir_array, 0, fs->group_desc_count * sizeof(int)); |
| - | goto redo_counts; |
| - | } else if (fixit == 0) |
| - | ext2fs_unmark_valid(fs); |
| - | |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) { |
| - | pctx.group = i; |
| - | pctx.ino = fs->group_desc[i].bg_free_inodes_count; |
| - | pctx.ino2 = free_array[i]; |
| - | if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP, |
| - | &pctx)) { |
| - | fs->group_desc[i].bg_free_inodes_count = |
| - | free_array[i]; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) { |
| - | pctx.group = i; |
| - | pctx.ino = fs->group_desc[i].bg_used_dirs_count; |
| - | pctx.ino2 = dir_array[i]; |
| - | |
| - | if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP, |
| - | &pctx)) { |
| - | fs->group_desc[i].bg_used_dirs_count = |
| - | dir_array[i]; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | } |
| - | if (free_inodes != fs->super->s_free_inodes_count) { |
| - | pctx.group = -1; |
| - | pctx.ino = fs->super->s_free_inodes_count; |
| - | pctx.ino2 = free_inodes; |
| - | |
| - | if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) { |
| - | fs->super->s_free_inodes_count = free_inodes; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | ext2fs_free_mem(&free_array); |
| - | ext2fs_free_mem(&dir_array); |
| - | } |
| - | |
| - | static void check_inode_end(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t end, save_inodes_count, i; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; |
| - | pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end, |
| - | &save_inodes_count); |
| - | if (pctx.errcode) { |
| - | pctx.num = 1; |
| - | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | if (save_inodes_count == end) |
| - | return; |
| - | |
| - | for (i = save_inodes_count + 1; i <= end; i++) { |
| - | if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) { |
| - | if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) { |
| - | for (i = save_inodes_count + 1; i <= end; i++) |
| - | ext2fs_mark_inode_bitmap(fs->inode_map, |
| - | i); |
| - | ext2fs_mark_ib_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | break; |
| - | } |
| - | } |
| - | |
| - | pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, |
| - | save_inodes_count, 0); |
| - | if (pctx.errcode) { |
| - | pctx.num = 2; |
| - | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | } |
| - | |
| - | static void check_block_end(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t end, save_blocks_count, i; |
| - | struct problem_context pctx; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | end = fs->block_map->start + |
| - | (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; |
| - | pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end, |
| - | &save_blocks_count); |
| - | if (pctx.errcode) { |
| - | pctx.num = 3; |
| - | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | if (save_blocks_count == end) |
| - | return; |
| - | |
| - | for (i = save_blocks_count + 1; i <= end; i++) { |
| - | if (!ext2fs_test_block_bitmap(fs->block_map, i)) { |
| - | if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { |
| - | for (i = save_blocks_count + 1; i <= end; i++) |
| - | ext2fs_mark_block_bitmap(fs->block_map, |
| - | i); |
| - | ext2fs_mark_bb_dirty(fs); |
| - | } else |
| - | ext2fs_unmark_valid(fs); |
| - | break; |
| - | } |
| - | } |
| - | |
| - | pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, |
| - | save_blocks_count, 0); |
| - | if (pctx.errcode) { |
| - | pctx.num = 4; |
| - | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
| - | return; |
| - | } |
| - | } |
| - | |
| - | static void e2fsck_pass5(e2fsck_t ctx) |
| - | { |
| - | struct problem_context pctx; |
| - | |
| - | /* Pass 5 */ |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | fix_problem(ctx, PR_5_PASS_HEADER, &pctx); |
| - | |
| - | if (ctx->progress) |
| - | if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2)) |
| - | return; |
| - | |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | check_block_bitmaps(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | check_inode_bitmaps(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | check_inode_end(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | check_block_end(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | |
| - | ext2fs_free_inode_bitmap(ctx->inode_used_map); |
| - | ctx->inode_used_map = 0; |
| - | ext2fs_free_inode_bitmap(ctx->inode_dir_map); |
| - | ctx->inode_dir_map = 0; |
| - | ext2fs_free_block_bitmap(ctx->block_found_map); |
| - | ctx->block_found_map = 0; |
| - | } |
| - | |
| - | /* |
| - | * problem.c --- report filesystem problems to the user |
| - | */ |
| - | |
| - | #define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */ |
| - | #define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */ |
| - | #define PR_NO_DEFAULT 0x000004 /* Default to no */ |
| - | #define PR_MSG_ONLY 0x000008 /* Print message only */ |
| - | |
| - | /* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */ |
| - | |
| - | #define PR_FATAL 0x001000 /* Fatal error */ |
| - | #define PR_AFTER_CODE 0x002000 /* After asking the first question, */ |
| - | /* ask another */ |
| - | #define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */ |
| - | #define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */ |
| - | #define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */ |
| - | #define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */ |
| - | #define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */ |
| - | |
| - | |
| - | #define PROMPT_NONE 0 |
| - | #define PROMPT_FIX 1 |
| - | #define PROMPT_CLEAR 2 |
| - | #define PROMPT_RELOCATE 3 |
| - | #define PROMPT_ALLOCATE 4 |
| - | #define PROMPT_EXPAND 5 |
| - | #define PROMPT_CONNECT 6 |
| - | #define PROMPT_CREATE 7 |
| - | #define PROMPT_SALVAGE 8 |
| - | #define PROMPT_TRUNCATE 9 |
| - | #define PROMPT_CLEAR_INODE 10 |
| - | #define PROMPT_ABORT 11 |
| - | #define PROMPT_SPLIT 12 |
| - | #define PROMPT_CONTINUE 13 |
| - | #define PROMPT_CLONE 14 |
| - | #define PROMPT_DELETE 15 |
| - | #define PROMPT_SUPPRESS 16 |
| - | #define PROMPT_UNLINK 17 |
| - | #define PROMPT_CLEAR_HTREE 18 |
| - | #define PROMPT_RECREATE 19 |
| - | #define PROMPT_NULL 20 |
| - | |
| - | struct e2fsck_problem { |
| - | problem_t e2p_code; |
| - | const char * e2p_description; |
| - | char prompt; |
| - | int flags; |
| - | problem_t second_code; |
| - | }; |
| - | |
| - | struct latch_descr { |
| - | int latch_code; |
| - | problem_t question; |
| - | problem_t end_message; |
| - | int flags; |
| - | }; |
| - | |
| - | /* |
| - | * These are the prompts which are used to ask the user if they want |
| - | * to fix a problem. |
| - | */ |
| - | static const char *const prompt[] = { |
| - | N_("(no prompt)"), /* 0 */ |
| - | N_("Fix"), /* 1 */ |
| - | N_("Clear"), /* 2 */ |
| - | N_("Relocate"), /* 3 */ |
| - | N_("Allocate"), /* 4 */ |
| - | N_("Expand"), /* 5 */ |
| - | N_("Connect to /lost+found"), /* 6 */ |
| - | N_("Create"), /* 7 */ |
| - | N_("Salvage"), /* 8 */ |
| - | N_("Truncate"), /* 9 */ |
| - | N_("Clear inode"), /* 10 */ |
| - | N_("Abort"), /* 11 */ |
| - | N_("Split"), /* 12 */ |
| - | N_("Continue"), /* 13 */ |
| - | N_("Clone multiply-claimed blocks"), /* 14 */ |
| - | N_("Delete file"), /* 15 */ |
| - | N_("Suppress messages"),/* 16 */ |
| - | N_("Unlink"), /* 17 */ |
| - | N_("Clear HTree index"),/* 18 */ |
| - | N_("Recreate"), /* 19 */ |
| - | "", /* 20 */ |
| - | }; |
| - | |
| - | /* |
| - | * These messages are printed when we are preen mode and we will be |
| - | * automatically fixing the problem. |
| - | */ |
| - | static const char *const preen_msg[] = { |
| - | N_("(NONE)"), /* 0 */ |
| - | N_("FIXED"), /* 1 */ |
| - | N_("CLEARED"), /* 2 */ |
| - | N_("RELOCATED"), /* 3 */ |
| - | N_("ALLOCATED"), /* 4 */ |
| - | N_("EXPANDED"), /* 5 */ |
| - | N_("RECONNECTED"), /* 6 */ |
| - | N_("CREATED"), /* 7 */ |
| - | N_("SALVAGED"), /* 8 */ |
| - | N_("TRUNCATED"), /* 9 */ |
| - | N_("INODE CLEARED"), /* 10 */ |
| - | N_("ABORTED"), /* 11 */ |
| - | N_("SPLIT"), /* 12 */ |
| - | N_("CONTINUING"), /* 13 */ |
| - | N_("MULTIPLY-CLAIMED BLOCKS CLONED"), /* 14 */ |
| - | N_("FILE DELETED"), /* 15 */ |
| - | N_("SUPPRESSED"), /* 16 */ |
| - | N_("UNLINKED"), /* 17 */ |
| - | N_("HTREE INDEX CLEARED"),/* 18 */ |
| - | N_("WILL RECREATE"), /* 19 */ |
| - | "", /* 20 */ |
| - | }; |
| - | |
| - | static const struct e2fsck_problem problem_table[] = { |
| - | |
| - | /* Pre-Pass 1 errors */ |
| - | |
| - | /* Block bitmap not in group */ |
| - | { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"), |
| - | PROMPT_RELOCATE, PR_LATCH_RELOC }, |
| - | |
| - | /* Inode bitmap not in group */ |
| - | { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"), |
| - | PROMPT_RELOCATE, PR_LATCH_RELOC }, |
| - | |
| - | /* Inode table not in group */ |
| - | { PR_0_ITABLE_NOT_GROUP, |
| - | N_("@i table for @g %g is not in @g. (@b %b)\n" |
| - | "WARNING: SEVERE DATA LOSS POSSIBLE.\n"), |
| - | PROMPT_RELOCATE, PR_LATCH_RELOC }, |
| - | |
| - | /* Superblock corrupt */ |
| - | { PR_0_SB_CORRUPT, |
| - | N_("\nThe @S could not be read or does not describe a correct ext2\n" |
| - | "@f. If the @v is valid and it really contains an ext2\n" |
| - | "@f (and not swap or ufs or something else), then the @S\n" |
| - | "is corrupt, and you might try running e2fsck with an alternate @S:\n" |
| - | " e2fsck -b %S <@v>\n\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Filesystem size is wrong */ |
| - | { PR_0_FS_SIZE_WRONG, |
| - | N_("The @f size (according to the @S) is %b @bs\n" |
| - | "The physical size of the @v is %c @bs\n" |
| - | "Either the @S or the partition table is likely to be corrupt!\n"), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* Fragments not supported */ |
| - | { PR_0_NO_FRAGMENTS, |
| - | N_("@S @b_size = %b, fragsize = %c.\n" |
| - | "This version of e2fsck does not support fragment sizes different\n" |
| - | "from the @b size.\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Bad blocks_per_group */ |
| - | { PR_0_BLOCKS_PER_GROUP, |
| - | N_("@S @bs_per_group = %b, should have been %c\n"), |
| - | PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT }, |
| - | |
| - | /* Bad first_data_block */ |
| - | { PR_0_FIRST_DATA_BLOCK, |
| - | N_("@S first_data_@b = %b, should have been %c\n"), |
| - | PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT }, |
| - | |
| - | /* Adding UUID to filesystem */ |
| - | { PR_0_ADD_UUID, |
| - | N_("@f did not have a UUID; generating one.\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Relocate hint */ |
| - | { PR_0_RELOCATE_HINT, |
| - | N_("Note: if several inode or block bitmap blocks or part\n" |
| - | "of the inode table require relocation, you may wish to try\n" |
| - | "running e2fsck with the '-b %S' option first. The problem\n" |
| - | "may lie only with the primary block group descriptors, and\n" |
| - | "the backup block group descriptors may be OK.\n\n"), |
| - | PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE }, |
| - | |
| - | /* Miscellaneous superblock corruption */ |
| - | { PR_0_MISC_CORRUPT_SUPER, |
| - | N_("Corruption found in @S. (%s = %N).\n"), |
| - | PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT }, |
| - | |
| - | /* Error determing physical device size of filesystem */ |
| - | { PR_0_GETSIZE_ERROR, |
| - | N_("Error determining size of the physical @v: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Inode count in superblock is incorrect */ |
| - | { PR_0_INODE_COUNT_WRONG, |
| - | N_("@i count in @S is %i, @s %j.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | { PR_0_HURD_CLEAR_FILETYPE, |
| - | N_("The Hurd does not support the filetype feature.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Journal inode is invalid */ |
| - | { PR_0_JOURNAL_BAD_INODE, |
| - | N_("@S has an @n ext3 @j (@i %i).\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* The external journal has (unsupported) multiple filesystems */ |
| - | { PR_0_JOURNAL_UNSUPP_MULTIFS, |
| - | N_("External @j has multiple @f users (unsupported).\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Can't find external journal */ |
| - | { PR_0_CANT_FIND_JOURNAL, |
| - | N_("Can't find external @j\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* External journal has bad superblock */ |
| - | { PR_0_EXT_JOURNAL_BAD_SUPER, |
| - | N_("External @j has bad @S\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Superblock has a bad journal UUID */ |
| - | { PR_0_JOURNAL_BAD_UUID, |
| - | N_("External @j does not support this @f\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Journal has an unknown superblock type */ |
| - | { PR_0_JOURNAL_UNSUPP_SUPER, |
| - | N_("Ext3 @j @S is unknown type %N (unsupported).\n" |
| - | "It is likely that your copy of e2fsck is old and/or doesn't " |
| - | "support this @j format.\n" |
| - | "It is also possible the @j @S is corrupt.\n"), |
| - | PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER }, |
| - | |
| - | /* Journal superblock is corrupt */ |
| - | { PR_0_JOURNAL_BAD_SUPER, |
| - | N_("Ext3 @j @S is corrupt.\n"), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Superblock flag should be cleared */ |
| - | { PR_0_JOURNAL_HAS_JOURNAL, |
| - | N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Superblock flag is incorrect */ |
| - | { PR_0_JOURNAL_RECOVER_SET, |
| - | N_("@S has ext3 needs_recovery flag set, but no @j.\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Journal has data, but recovery flag is clear */ |
| - | { PR_0_JOURNAL_RECOVERY_CLEAR, |
| - | N_("ext3 recovery flag is clear, but @j has data.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Ask if we should clear the journal */ |
| - | { PR_0_JOURNAL_RESET_JOURNAL, |
| - | N_("Clear @j"), |
| - | PROMPT_NULL, PR_PREEN_NOMSG }, |
| - | |
| - | /* Ask if we should run the journal anyway */ |
| - | { PR_0_JOURNAL_RUN, |
| - | N_("Run @j anyway"), |
| - | PROMPT_NULL, 0 }, |
| - | |
| - | /* Run the journal by default */ |
| - | { PR_0_JOURNAL_RUN_DEFAULT, |
| - | N_("Recovery flag not set in backup @S, so running @j anyway.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Clearing orphan inode */ |
| - | { PR_0_ORPHAN_CLEAR_INODE, |
| - | N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Illegal block found in orphaned inode */ |
| - | { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, |
| - | N_("@I @b #%B (%b) found in @o @i %i.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Already cleared block found in orphaned inode */ |
| - | { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, |
| - | N_("Already cleared @b #%B (%b) found in @o @i %i.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Illegal orphan inode in superblock */ |
| - | { PR_0_ORPHAN_ILLEGAL_HEAD_INODE, |
| - | N_("@I @o @i %i in @S.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Illegal inode in orphaned inode list */ |
| - | { PR_0_ORPHAN_ILLEGAL_INODE, |
| - | N_("@I @i %i in @o @i list.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Filesystem revision is 0, but feature flags are set */ |
| - | { PR_0_FS_REV_LEVEL, |
| - | N_("@f has feature flag(s) set, but is a revision 0 @f. "), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_NO_OK }, |
| - | |
| - | /* Journal superblock has an unknown read-only feature flag set */ |
| - | { PR_0_JOURNAL_UNSUPP_ROCOMPAT, |
| - | N_("Ext3 @j @S has an unknown read-only feature flag set.\n"), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* Journal superblock has an unknown incompatible feature flag set */ |
| - | { PR_0_JOURNAL_UNSUPP_INCOMPAT, |
| - | N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* Journal has unsupported version number */ |
| - | { PR_0_JOURNAL_UNSUPP_VERSION, |
| - | N_("@j version not supported by this e2fsck.\n"), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* Moving journal to hidden file */ |
| - | { PR_0_MOVE_JOURNAL, |
| - | N_("Moving @j from /%s to hidden @i.\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error moving journal to hidden file */ |
| - | { PR_0_ERR_MOVE_JOURNAL, |
| - | N_("Error moving @j: %m\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Clearing V2 journal superblock */ |
| - | { PR_0_CLEAR_V2_JOURNAL, |
| - | N_("Found @n V2 @j @S fields (from V1 @j).\n" |
| - | "Clearing fields beyond the V1 @j @S...\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Backup journal inode blocks */ |
| - | { PR_0_BACKUP_JNL, |
| - | N_("Backing up @j @i @b information.\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Reserved blocks w/o resize_inode */ |
| - | { PR_0_NONZERO_RESERVED_GDT_BLOCKS, |
| - | N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n" |
| - | "is %N; @s zero. "), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Resize_inode not enabled, but resize inode is non-zero */ |
| - | { PR_0_CLEAR_RESIZE_INODE, |
| - | N_("Resize_@i not enabled, but the resize @i is non-zero. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Resize inode invalid */ |
| - | { PR_0_RESIZE_INODE_INVALID, |
| - | N_("Resize @i not valid. "), |
| - | PROMPT_RECREATE, 0 }, |
| - | |
| - | /* Pass 1 errors */ |
| - | |
| - | /* Pass 1: Checking inodes, blocks, and sizes */ |
| - | { PR_1_PASS_HEADER, |
| - | N_("Pass 1: Checking @is, @bs, and sizes\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Root directory is not an inode */ |
| - | { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Root directory has dtime set */ |
| - | { PR_1_ROOT_DTIME, |
| - | N_("@r has dtime set (probably due to old mke2fs). "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Reserved inode has bad mode */ |
| - | { PR_1_RESERVED_BAD_MODE, |
| - | N_("Reserved @i %i (%Q) has @n mode. "), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Deleted inode has zero dtime */ |
| - | { PR_1_ZERO_DTIME, |
| - | N_("@D @i %i has zero dtime. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Inode in use, but dtime set */ |
| - | { PR_1_SET_DTIME, |
| - | N_("@i %i is in use, but has dtime set. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Zero-length directory */ |
| - | { PR_1_ZERO_LENGTH_DIR, |
| - | N_("@i %i is a @z @d. "), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Block bitmap conflicts with some other fs block */ |
| - | { PR_1_BB_CONFLICT, |
| - | N_("@g %g's @b @B at %b @C.\n"), |
| - | PROMPT_RELOCATE, 0 }, |
| - | |
| - | /* Inode bitmap conflicts with some other fs block */ |
| - | { PR_1_IB_CONFLICT, |
| - | N_("@g %g's @i @B at %b @C.\n"), |
| - | PROMPT_RELOCATE, 0 }, |
| - | |
| - | /* Inode table conflicts with some other fs block */ |
| - | { PR_1_ITABLE_CONFLICT, |
| - | N_("@g %g's @i table at %b @C.\n"), |
| - | PROMPT_RELOCATE, 0 }, |
| - | |
| - | /* Block bitmap is on a bad block */ |
| - | { PR_1_BB_BAD_BLOCK, |
| - | N_("@g %g's @b @B (%b) is bad. "), |
| - | PROMPT_RELOCATE, 0 }, |
| - | |
| - | /* Inode bitmap is on a bad block */ |
| - | { PR_1_IB_BAD_BLOCK, |
| - | N_("@g %g's @i @B (%b) is bad. "), |
| - | PROMPT_RELOCATE, 0 }, |
| - | |
| - | /* Inode has incorrect i_size */ |
| - | { PR_1_BAD_I_SIZE, |
| - | N_("@i %i, i_size is %Is, @s %N. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Inode has incorrect i_blocks */ |
| - | { PR_1_BAD_I_BLOCKS, |
| - | N_("@i %i, i_@bs is %Ib, @s %N. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Illegal blocknumber in inode */ |
| - | { PR_1_ILLEGAL_BLOCK_NUM, |
| - | N_("@I @b #%B (%b) in @i %i. "), |
| - | PROMPT_CLEAR, PR_LATCH_BLOCK }, |
| - | |
| - | /* Block number overlaps fs metadata */ |
| - | { PR_1_BLOCK_OVERLAPS_METADATA, |
| - | N_("@b #%B (%b) overlaps @f metadata in @i %i. "), |
| - | PROMPT_CLEAR, PR_LATCH_BLOCK }, |
| - | |
| - | /* Inode has illegal blocks (latch question) */ |
| - | { PR_1_INODE_BLOCK_LATCH, |
| - | N_("@i %i has illegal @b(s). "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Too many bad blocks in inode */ |
| - | { PR_1_TOO_MANY_BAD_BLOCKS, |
| - | N_("Too many illegal @bs in @i %i.\n"), |
| - | PROMPT_CLEAR_INODE, PR_NO_OK }, |
| - | |
| - | /* Illegal block number in bad block inode */ |
| - | { PR_1_BB_ILLEGAL_BLOCK_NUM, |
| - | N_("@I @b #%B (%b) in bad @b @i. "), |
| - | PROMPT_CLEAR, PR_LATCH_BBLOCK }, |
| - | |
| - | /* Bad block inode has illegal blocks (latch question) */ |
| - | { PR_1_INODE_BBLOCK_LATCH, |
| - | N_("Bad @b @i has illegal @b(s). "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Duplicate or bad blocks in use! */ |
| - | { PR_1_DUP_BLOCKS_PREENSTOP, |
| - | N_("Duplicate or bad @b in use!\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Bad block used as bad block indirect block */ |
| - | { PR_1_BBINODE_BAD_METABLOCK, |
| - | N_("Bad @b %b used as bad @b @i indirect @b. "), |
| - | PROMPT_CLEAR, PR_LATCH_BBLOCK }, |
| - | |
| - | /* Inconsistency can't be fixed prompt */ |
| - | { PR_1_BBINODE_BAD_METABLOCK_PROMPT, |
| - | N_("\nThe bad @b @i has probably been corrupted. You probably\n" |
| - | "should stop now and run ""e2fsck -c"" to scan for bad blocks\n" |
| - | "in the @f.\n"), |
| - | PROMPT_CONTINUE, PR_PREEN_NOMSG }, |
| - | |
| - | /* Bad primary block */ |
| - | { PR_1_BAD_PRIMARY_BLOCK, |
| - | N_("\nIf the @b is really bad, the @f cannot be fixed.\n"), |
| - | PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT }, |
| - | |
| - | /* Bad primary block prompt */ |
| - | { PR_1_BAD_PRIMARY_BLOCK_PROMPT, |
| - | N_("You can remove this @b from the bad @b list and hope\n" |
| - | "that the @b is really OK. But there are no guarantees.\n\n"), |
| - | PROMPT_CLEAR, PR_PREEN_NOMSG }, |
| - | |
| - | /* Bad primary superblock */ |
| - | { PR_1_BAD_PRIMARY_SUPERBLOCK, |
| - | N_("The primary @S (%b) is on the bad @b list.\n"), |
| - | PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK }, |
| - | |
| - | /* Bad primary block group descriptors */ |
| - | { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, |
| - | N_("Block %b in the primary @g descriptors " |
| - | "is on the bad @b list\n"), |
| - | PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK }, |
| - | |
| - | /* Bad superblock in group */ |
| - | { PR_1_BAD_SUPERBLOCK, |
| - | N_("Warning: Group %g's @S (%b) is bad.\n"), |
| - | PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Bad block group descriptors in group */ |
| - | { PR_1_BAD_GROUP_DESCRIPTORS, |
| - | N_("Warning: Group %g's copy of the @g descriptors has a bad " |
| - | "@b (%b).\n"), |
| - | PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Block claimed for no reason */ |
| - | { PR_1_PROGERR_CLAIMED_BLOCK, |
| - | N_("Programming error? @b #%b claimed for no reason in " |
| - | "process_bad_@b.\n"), |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Error allocating blocks for relocating metadata */ |
| - | { PR_1_RELOC_BLOCK_ALLOCATE, |
| - | N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"), |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Error allocating block buffer during relocation process */ |
| - | { PR_1_RELOC_MEMORY_ALLOCATE, |
| - | N_("@A @b buffer for relocating %s\n"), |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Relocating metadata group information from X to Y */ |
| - | { PR_1_RELOC_FROM_TO, |
| - | N_("Relocating @g %g's %s from %b to %c...\n"), |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Relocating metatdata group information to X */ |
| - | { PR_1_RELOC_TO, |
| - | N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */ |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Block read error during relocation process */ |
| - | { PR_1_RELOC_READ_ERR, |
| - | N_("Warning: could not read @b %b of %s: %m\n"), |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Block write error during relocation process */ |
| - | { PR_1_RELOC_WRITE_ERR, |
| - | N_("Warning: could not write @b %b for %s: %m\n"), |
| - | PROMPT_NONE, PR_PREEN_OK }, |
| - | |
| - | /* Error allocating inode bitmap */ |
| - | { PR_1_ALLOCATE_IBITMAP_ERROR, |
| - | N_("@A @i @B (%N): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error allocating block bitmap */ |
| - | { PR_1_ALLOCATE_BBITMAP_ERROR, |
| - | N_("@A @b @B (%N): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error allocating icount structure */ |
| - | { PR_1_ALLOCATE_ICOUNT, |
| - | N_("@A icount link information: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error allocating dbcount */ |
| - | { PR_1_ALLOCATE_DBCOUNT, |
| - | N_("@A @d @b array: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error while scanning inodes */ |
| - | { PR_1_ISCAN_ERROR, |
| - | N_("Error while scanning @is (%i): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error while iterating over blocks */ |
| - | { PR_1_BLOCK_ITERATE, |
| - | N_("Error while iterating over @bs in @i %i: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error while storing inode count information */ |
| - | { PR_1_ICOUNT_STORE, |
| - | N_("Error storing @i count information (@i=%i, count=%N): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error while storing directory block information */ |
| - | { PR_1_ADD_DBLOCK, |
| - | N_("Error storing @d @b information " |
| - | "(@i=%i, @b=%b, num=%N): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error while reading inode (for clearing) */ |
| - | { PR_1_READ_INODE, |
| - | N_("Error reading @i %i: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Suppress messages prompt */ |
| - | { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK }, |
| - | |
| - | /* Imagic flag set on an inode when filesystem doesn't support it */ |
| - | { PR_1_SET_IMAGIC, |
| - | N_("@i %i has imagic flag set. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Immutable flag set on a device or socket inode */ |
| - | { PR_1_SET_IMMUTABLE, |
| - | N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n" |
| - | "or append-only flag set. "), |
| - | PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK }, |
| - | |
| - | /* Compression flag set on an inode when filesystem doesn't support it */ |
| - | { PR_1_COMPR_SET, |
| - | N_("@i %i has @cion flag set on @f without @cion support. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Non-zero size for device, fifo or socket inode */ |
| - | { PR_1_SET_NONZSIZE, |
| - | N_("Special (@v/socket/fifo) @i %i has non-zero size. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Filesystem revision is 0, but feature flags are set */ |
| - | { PR_1_FS_REV_LEVEL, |
| - | N_("@f has feature flag(s) set, but is a revision 0 @f. "), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_NO_OK }, |
| - | |
| - | /* Journal inode is not in use, but contains data */ |
| - | { PR_1_JOURNAL_INODE_NOT_CLEAR, |
| - | N_("@j @i is not in use, but contains data. "), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Journal has bad mode */ |
| - | { PR_1_JOURNAL_BAD_MODE, |
| - | N_("@j is not regular file. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Deal with inodes that were part of orphan linked list */ |
| - | { PR_1_LOW_DTIME, |
| - | N_("@i %i was part of the @o @i list. "), |
| - | PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 }, |
| - | |
| - | /* Deal with inodes that were part of corrupted orphan linked |
| - | list (latch question) */ |
| - | { PR_1_ORPHAN_LIST_REFUGEES, |
| - | N_("@is that were part of a corrupted orphan linked list found. "), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Error allocating refcount structure */ |
| - | { PR_1_ALLOCATE_REFCOUNT, |
| - | N_("@A refcount structure (%N): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error reading extended attribute block */ |
| - | { PR_1_READ_EA_BLOCK, |
| - | N_("Error reading @a @b %b for @i %i. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Invalid extended attribute block */ |
| - | { PR_1_BAD_EA_BLOCK, |
| - | N_("@i %i has a bad @a @b %b. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Error reading Extended Attribute block while fixing refcount */ |
| - | { PR_1_EXTATTR_READ_ABORT, |
| - | N_("Error reading @a @b %b (%m). "), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* Extended attribute reference count incorrect */ |
| - | { PR_1_EXTATTR_REFCOUNT, |
| - | N_("@a @b %b has reference count %B, @s %N. "), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Error writing Extended Attribute block while fixing refcount */ |
| - | { PR_1_EXTATTR_WRITE, |
| - | N_("Error writing @a @b %b (%m). "), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* Multiple EA blocks not supported */ |
| - | { PR_1_EA_MULTI_BLOCK, |
| - | N_("@a @b %b has h_@bs > 1. "), |
| - | PROMPT_CLEAR, 0}, |
| - | |
| - | /* Error allocating EA region allocation structure */ |
| - | { PR_1_EA_ALLOC_REGION, |
| - | N_("@A @a @b %b. "), |
| - | PROMPT_ABORT, 0}, |
| - | |
| - | /* Error EA allocation collision */ |
| - | { PR_1_EA_ALLOC_COLLISION, |
| - | N_("@a @b %b is corrupt (allocation collision). "), |
| - | PROMPT_CLEAR, 0}, |
| - | |
| - | /* Bad extended attribute name */ |
| - | { PR_1_EA_BAD_NAME, |
| - | N_("@a @b %b is corrupt (@n name). "), |
| - | PROMPT_CLEAR, 0}, |
| - | |
| - | /* Bad extended attribute value */ |
| - | { PR_1_EA_BAD_VALUE, |
| - | N_("@a @b %b is corrupt (@n value). "), |
| - | PROMPT_CLEAR, 0}, |
| - | |
| - | /* Inode too big (latch question) */ |
| - | { PR_1_INODE_TOOBIG, |
| - | N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 }, |
| - | |
| - | /* Directory too big */ |
| - | { PR_1_TOOBIG_DIR, |
| - | N_("@b #%B (%b) causes @d to be too big. "), |
| - | PROMPT_CLEAR, PR_LATCH_TOOBIG }, |
| - | |
| - | /* Regular file too big */ |
| - | { PR_1_TOOBIG_REG, |
| - | N_("@b #%B (%b) causes file to be too big. "), |
| - | PROMPT_CLEAR, PR_LATCH_TOOBIG }, |
| - | |
| - | /* Symlink too big */ |
| - | { PR_1_TOOBIG_SYMLINK, |
| - | N_("@b #%B (%b) causes symlink to be too big. "), |
| - | PROMPT_CLEAR, PR_LATCH_TOOBIG }, |
| - | |
| - | /* INDEX_FL flag set on a non-HTREE filesystem */ |
| - | { PR_1_HTREE_SET, |
| - | N_("@i %i has INDEX_FL flag set on @f without htree support.\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* INDEX_FL flag set on a non-directory */ |
| - | { PR_1_HTREE_NODIR, |
| - | N_("@i %i has INDEX_FL flag set but is not a @d.\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Invalid root node in HTREE directory */ |
| - | { PR_1_HTREE_BADROOT, |
| - | N_("@h %i has an @n root node.\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Unsupported hash version in HTREE directory */ |
| - | { PR_1_HTREE_HASHV, |
| - | N_("@h %i has an unsupported hash version (%N)\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Incompatible flag in HTREE root node */ |
| - | { PR_1_HTREE_INCOMPAT, |
| - | N_("@h %i uses an incompatible htree root node flag.\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* HTREE too deep */ |
| - | { PR_1_HTREE_DEPTH, |
| - | N_("@h %i has a tree depth (%N) which is too big\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Bad block has indirect block that conflicts with filesystem block */ |
| - | { PR_1_BB_FS_BLOCK, |
| - | N_("Bad @b @i has an indirect @b (%b) that conflicts with\n" |
| - | "@f metadata. "), |
| - | PROMPT_CLEAR, PR_LATCH_BBLOCK }, |
| - | |
| - | /* Resize inode failed */ |
| - | { PR_1_RESIZE_INODE_CREATE, |
| - | N_("Resize @i (re)creation failed: %m."), |
| - | PROMPT_ABORT, 0 }, |
| - | |
| - | /* invalid inode->i_extra_isize */ |
| - | { PR_1_EXTRA_ISIZE, |
| - | N_("@i %i has a extra size (%IS) which is @n\n"), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* invalid ea entry->e_name_len */ |
| - | { PR_1_ATTR_NAME_LEN, |
| - | N_("@a in @i %i has a namelen (%N) which is @n\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* invalid ea entry->e_value_size */ |
| - | { PR_1_ATTR_VALUE_SIZE, |
| - | N_("@a in @i %i has a value size (%N) which is @n\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* invalid ea entry->e_value_offs */ |
| - | { PR_1_ATTR_VALUE_OFFSET, |
| - | N_("@a in @i %i has a value offset (%N) which is @n\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* invalid ea entry->e_value_block */ |
| - | { PR_1_ATTR_VALUE_BLOCK, |
| - | N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* invalid ea entry->e_hash */ |
| - | { PR_1_ATTR_HASH, |
| - | N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Pass 1b errors */ |
| - | |
| - | /* Pass 1B: Rescan for duplicate/bad blocks */ |
| - | { PR_1B_PASS_HEADER, |
| - | N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n" |
| - | "Pass 1B: Rescanning for @m @bs\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Duplicate/bad block(s) header */ |
| - | { PR_1B_DUP_BLOCK_HEADER, |
| - | N_("@m @b(s) in @i %i:"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Duplicate/bad block(s) in inode */ |
| - | { PR_1B_DUP_BLOCK, |
| - | " %b", |
| - | PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR }, |
| - | |
| - | /* Duplicate/bad block(s) end */ |
| - | { PR_1B_DUP_BLOCK_END, |
| - | "\n", |
| - | PROMPT_NONE, PR_PREEN_NOHDR }, |
| - | |
| - | /* Error while scanning inodes */ |
| - | { PR_1B_ISCAN_ERROR, |
| - | N_("Error while scanning inodes (%i): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error allocating inode bitmap */ |
| - | { PR_1B_ALLOCATE_IBITMAP_ERROR, |
| - | N_("@A @i @B (@i_dup_map): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error while iterating over blocks */ |
| - | { PR_1B_BLOCK_ITERATE, |
| - | N_("Error while iterating over @bs in @i %i (%s): %m\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error adjusting EA refcount */ |
| - | { PR_1B_ADJ_EA_REFCOUNT, |
| - | N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | |
| - | /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */ |
| - | { PR_1C_PASS_HEADER, |
| - | N_("Pass 1C: Scanning directories for @is with @m @bs.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | |
| - | /* Pass 1D: Reconciling multiply-claimed blocks */ |
| - | { PR_1D_PASS_HEADER, |
| - | N_("Pass 1D: Reconciling @m @bs\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* File has duplicate blocks */ |
| - | { PR_1D_DUP_FILE, |
| - | N_("File %Q (@i #%i, mod time %IM)\n" |
| - | " has %B @m @b(s), shared with %N file(s):\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* List of files sharing duplicate blocks */ |
| - | { PR_1D_DUP_FILE_LIST, |
| - | N_("\t%Q (@i #%i, mod time %IM)\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* File sharing blocks with filesystem metadata */ |
| - | { PR_1D_SHARE_METADATA, |
| - | N_("\t<@f metadata>\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Report of how many duplicate/bad inodes */ |
| - | { PR_1D_NUM_DUP_INODES, |
| - | N_("(There are %N @is containing @m @bs.)\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Duplicated blocks already reassigned or cloned. */ |
| - | { PR_1D_DUP_BLOCKS_DEALT, |
| - | N_("@m @bs already reassigned or cloned.\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Clone duplicate/bad blocks? */ |
| - | { PR_1D_CLONE_QUESTION, |
| - | "", PROMPT_CLONE, PR_NO_OK }, |
| - | |
| - | /* Delete file? */ |
| - | { PR_1D_DELETE_QUESTION, |
| - | "", PROMPT_DELETE, 0 }, |
| - | |
| - | /* Couldn't clone file (error) */ |
| - | { PR_1D_CLONE_ERROR, |
| - | N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 }, |
| - | |
| - | /* Pass 2 errors */ |
| - | |
| - | /* Pass 2: Checking directory structure */ |
| - | { PR_2_PASS_HEADER, |
| - | N_("Pass 2: Checking @d structure\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Bad inode number for '.' */ |
| - | { PR_2_BAD_INODE_DOT, |
| - | N_("@n @i number for '.' in @d @i %i.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Directory entry has bad inode number */ |
| - | { PR_2_BAD_INO, |
| - | N_("@E has @n @i #: %Di.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Directory entry has deleted or unused inode */ |
| - | { PR_2_UNUSED_INODE, |
| - | N_("@E has @D/unused @i %Di. "), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Directry entry is link to '.' */ |
| - | { PR_2_LINK_DOT, |
| - | N_("@E @L to '.' "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Directory entry points to inode now located in a bad block */ |
| - | { PR_2_BB_INODE, |
| - | N_("@E points to @i (%Di) located in a bad @b.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Directory entry contains a link to a directory */ |
| - | { PR_2_LINK_DIR, |
| - | N_("@E @L to @d %P (%Di).\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Directory entry contains a link to the root directry */ |
| - | { PR_2_LINK_ROOT, |
| - | N_("@E @L to the @r.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Directory entry has illegal characters in its name */ |
| - | { PR_2_BAD_NAME, |
| - | N_("@E has illegal characters in its name.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Missing '.' in directory inode */ |
| - | { PR_2_MISSING_DOT, |
| - | N_("Missing '.' in @d @i %i.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Missing '..' in directory inode */ |
| - | { PR_2_MISSING_DOT_DOT, |
| - | N_("Missing '..' in @d @i %i.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* First entry in directory inode doesn't contain '.' */ |
| - | { PR_2_1ST_NOT_DOT, |
| - | N_("First @e '%Dn' (@i=%Di) in @d @i %i (%p) @s '.'\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Second entry in directory inode doesn't contain '..' */ |
| - | { PR_2_2ND_NOT_DOT_DOT, |
| - | N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* i_faddr should be zero */ |
| - | { PR_2_FADDR_ZERO, |
| - | N_("i_faddr @F %IF, @s zero.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* i_file_acl should be zero */ |
| - | { PR_2_FILE_ACL_ZERO, |
| - | N_("i_file_acl @F %If, @s zero.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* i_dir_acl should be zero */ |
| - | { PR_2_DIR_ACL_ZERO, |
| - | N_("i_dir_acl @F %Id, @s zero.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* i_frag should be zero */ |
| - | { PR_2_FRAG_ZERO, |
| - | N_("i_frag @F %N, @s zero.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* i_fsize should be zero */ |
| - | { PR_2_FSIZE_ZERO, |
| - | N_("i_fsize @F %N, @s zero.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* inode has bad mode */ |
| - | { PR_2_BAD_MODE, |
| - | N_("@i %i (%Q) has @n mode (%Im).\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* directory corrupted */ |
| - | { PR_2_DIR_CORRUPTED, |
| - | N_("@d @i %i, @b %B, offset %N: @d corrupted\n"), |
| - | PROMPT_SALVAGE, 0 }, |
| - | |
| - | /* filename too long */ |
| - | { PR_2_FILENAME_LONG, |
| - | N_("@d @i %i, @b %B, offset %N: filename too long\n"), |
| - | PROMPT_TRUNCATE, 0 }, |
| - | |
| - | /* Directory inode has a missing block (hole) */ |
| - | { PR_2_DIRECTORY_HOLE, |
| - | N_("@d @i %i has an unallocated @b #%B. "), |
| - | PROMPT_ALLOCATE, 0 }, |
| - | |
| - | /* '.' is not NULL terminated */ |
| - | { PR_2_DOT_NULL_TERM, |
| - | N_("'.' @d @e in @d @i %i is not NULL terminated\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* '..' is not NULL terminated */ |
| - | { PR_2_DOT_DOT_NULL_TERM, |
| - | N_("'..' @d @e in @d @i %i is not NULL terminated\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Illegal character device inode */ |
| - | { PR_2_BAD_CHAR_DEV, |
| - | N_("@i %i (%Q) is an @I character @v.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Illegal block device inode */ |
| - | { PR_2_BAD_BLOCK_DEV, |
| - | N_("@i %i (%Q) is an @I @b @v.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Duplicate '.' entry */ |
| - | { PR_2_DUP_DOT, |
| - | N_("@E is duplicate '.' @e.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Duplicate '..' entry */ |
| - | { PR_2_DUP_DOT_DOT, |
| - | N_("@E is duplicate '..' @e.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Internal error: couldn't find dir_info */ |
| - | { PR_2_NO_DIRINFO, |
| - | N_("Internal error: cannot find dir_info for %i.\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Final rec_len is wrong */ |
| - | { PR_2_FINAL_RECLEN, |
| - | N_("@E has rec_len of %Dr, @s %N.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Error allocating icount structure */ |
| - | { PR_2_ALLOCATE_ICOUNT, |
| - | N_("@A icount structure: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error iterating over directory blocks */ |
| - | { PR_2_DBLIST_ITERATE, |
| - | N_("Error iterating over @d @bs: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error reading directory block */ |
| - | { PR_2_READ_DIRBLOCK, |
| - | N_("Error reading @d @b %b (@i %i): %m\n"), |
| - | PROMPT_CONTINUE, 0 }, |
| - | |
| - | /* Error writing directory block */ |
| - | { PR_2_WRITE_DIRBLOCK, |
| - | N_("Error writing @d @b %b (@i %i): %m\n"), |
| - | PROMPT_CONTINUE, 0 }, |
| - | |
| - | /* Error allocating new directory block */ |
| - | { PR_2_ALLOC_DIRBOCK, |
| - | N_("@A new @d @b for @i %i (%s): %m\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error deallocating inode */ |
| - | { PR_2_DEALLOC_INODE, |
| - | N_("Error deallocating @i %i: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Directory entry for '.' is big. Split? */ |
| - | { PR_2_SPLIT_DOT, |
| - | N_("@d @e for '.' is big. "), |
| - | PROMPT_SPLIT, PR_NO_OK }, |
| - | |
| - | /* Illegal FIFO inode */ |
| - | { PR_2_BAD_FIFO, |
| - | N_("@i %i (%Q) is an @I FIFO.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Illegal socket inode */ |
| - | { PR_2_BAD_SOCKET, |
| - | N_("@i %i (%Q) is an @I socket.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Directory filetype not set */ |
| - | { PR_2_SET_FILETYPE, |
| - | N_("Setting filetype for @E to %N.\n"), |
| - | PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG }, |
| - | |
| - | /* Directory filetype incorrect */ |
| - | { PR_2_BAD_FILETYPE, |
| - | N_("@E has an incorrect filetype (was %Dt, @s %N).\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Directory filetype set on filesystem */ |
| - | { PR_2_CLEAR_FILETYPE, |
| - | N_("@E has filetype set.\n"), |
| - | PROMPT_CLEAR, PR_PREEN_OK }, |
| - | |
| - | /* Directory filename is null */ |
| - | { PR_2_NULL_NAME, |
| - | N_("@E has a @z name.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Invalid symlink */ |
| - | { PR_2_INVALID_SYMLINK, |
| - | N_("Symlink %Q (@i #%i) is @n.\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* i_file_acl (extended attribute block) is bad */ |
| - | { PR_2_FILE_ACL_BAD, |
| - | N_("@a @b @F @n (%If).\n"), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Filesystem contains large files, but has no such flag in sb */ |
| - | { PR_2_FEATURE_LARGE_FILES, |
| - | N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Node in HTREE directory not referenced */ |
| - | { PR_2_HTREE_NOTREF, |
| - | N_("@p @h %d: node (%B) not referenced\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Node in HTREE directory referenced twice */ |
| - | { PR_2_HTREE_DUPREF, |
| - | N_("@p @h %d: node (%B) referenced twice\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Node in HTREE directory has bad min hash */ |
| - | { PR_2_HTREE_MIN_HASH, |
| - | N_("@p @h %d: node (%B) has bad min hash\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Node in HTREE directory has bad max hash */ |
| - | { PR_2_HTREE_MAX_HASH, |
| - | N_("@p @h %d: node (%B) has bad max hash\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Clear invalid HTREE directory */ |
| - | { PR_2_HTREE_CLEAR, |
| - | N_("@n @h %d (%q). "), PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Bad block in htree interior node */ |
| - | { PR_2_HTREE_BADBLK, |
| - | N_("@p @h %d (%q): bad @b number %b.\n"), |
| - | PROMPT_CLEAR_HTREE, 0 }, |
| - | |
| - | /* Error adjusting EA refcount */ |
| - | { PR_2_ADJ_EA_REFCOUNT, |
| - | N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Invalid HTREE root node */ |
| - | { PR_2_HTREE_BAD_ROOT, |
| - | N_("@p @h %d: root node is @n\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Invalid HTREE limit */ |
| - | { PR_2_HTREE_BAD_LIMIT, |
| - | N_("@p @h %d: node (%B) has @n limit (%N)\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Invalid HTREE count */ |
| - | { PR_2_HTREE_BAD_COUNT, |
| - | N_("@p @h %d: node (%B) has @n count (%N)\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* HTREE interior node has out-of-order hashes in table */ |
| - | { PR_2_HTREE_HASH_ORDER, |
| - | N_("@p @h %d: node (%B) has an unordered hash table\n"), |
| - | PROMPT_CLEAR_HTREE, PR_PREEN_OK }, |
| - | |
| - | /* Node in HTREE directory has invalid depth */ |
| - | { PR_2_HTREE_BAD_DEPTH, |
| - | N_("@p @h %d: node (%B) has @n depth\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Duplicate directory entry found */ |
| - | { PR_2_DUPLICATE_DIRENT, |
| - | N_("Duplicate @E found. "), |
| - | PROMPT_CLEAR, 0 }, |
| - | |
| - | /* Non-unique filename found */ |
| - | { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */ |
| - | N_("@E has a non-unique filename.\nRename to %s"), |
| - | PROMPT_NULL, 0 }, |
| - | |
| - | /* Duplicate directory entry found */ |
| - | { PR_2_REPORT_DUP_DIRENT, |
| - | N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Pass 3 errors */ |
| - | |
| - | /* Pass 3: Checking directory connectivity */ |
| - | { PR_3_PASS_HEADER, |
| - | N_("Pass 3: Checking @d connectivity\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Root inode not allocated */ |
| - | { PR_3_NO_ROOT_INODE, |
| - | N_("@r not allocated. "), |
| - | PROMPT_ALLOCATE, 0 }, |
| - | |
| - | /* No room in lost+found */ |
| - | { PR_3_EXPAND_LF_DIR, |
| - | N_("No room in @l @d. "), |
| - | PROMPT_EXPAND, 0 }, |
| - | |
| - | /* Unconnected directory inode */ |
| - | { PR_3_UNCONNECTED_DIR, |
| - | N_("Unconnected @d @i %i (%p)\n"), |
| - | PROMPT_CONNECT, 0 }, |
| - | |
| - | /* /lost+found not found */ |
| - | { PR_3_NO_LF_DIR, |
| - | N_("/@l not found. "), |
| - | PROMPT_CREATE, PR_PREEN_OK }, |
| - | |
| - | /* .. entry is incorrect */ |
| - | { PR_3_BAD_DOT_DOT, |
| - | N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"), |
| - | PROMPT_FIX, 0 }, |
| - | |
| - | /* Bad or non-existent /lost+found. Cannot reconnect */ |
| - | { PR_3_NO_LPF, |
| - | N_("Bad or non-existent /@l. Cannot reconnect.\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Could not expand /lost+found */ |
| - | { PR_3_CANT_EXPAND_LPF, |
| - | N_("Could not expand /@l: %m\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Could not reconnect inode */ |
| - | { PR_3_CANT_RECONNECT, |
| - | N_("Could not reconnect %i: %m\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error while trying to find /lost+found */ |
| - | { PR_3_ERR_FIND_LPF, |
| - | N_("Error while trying to find /@l: %m\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error in ext2fs_new_block while creating /lost+found */ |
| - | { PR_3_ERR_LPF_NEW_BLOCK, |
| - | N_("ext2fs_new_@b: %m while trying to create /@l @d\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error in ext2fs_new_inode while creating /lost+found */ |
| - | { PR_3_ERR_LPF_NEW_INODE, |
| - | N_("ext2fs_new_@i: %m while trying to create /@l @d\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error in ext2fs_new_dir_block while creating /lost+found */ |
| - | { PR_3_ERR_LPF_NEW_DIR_BLOCK, |
| - | N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error while writing directory block for /lost+found */ |
| - | { PR_3_ERR_LPF_WRITE_BLOCK, |
| - | N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error while adjusting inode count */ |
| - | { PR_3_ADJUST_INODE, |
| - | N_("Error while adjusting @i count on @i %i\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Couldn't fix parent directory -- error */ |
| - | { PR_3_FIX_PARENT_ERR, |
| - | N_("Couldn't fix parent of @i %i: %m\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Couldn't fix parent directory -- couldn't find it */ |
| - | { PR_3_FIX_PARENT_NOFIND, |
| - | N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error allocating inode bitmap */ |
| - | { PR_3_ALLOCATE_IBITMAP_ERROR, |
| - | N_("@A @i @B (%N): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error creating root directory */ |
| - | { PR_3_CREATE_ROOT_ERROR, |
| - | N_("Error creating root @d (%s): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error creating lost and found directory */ |
| - | { PR_3_CREATE_LPF_ERROR, |
| - | N_("Error creating /@l @d (%s): %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Root inode is not directory; aborting */ |
| - | { PR_3_ROOT_NOT_DIR_ABORT, |
| - | N_("@r is not a @d; aborting.\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Cannot proceed without a root inode. */ |
| - | { PR_3_NO_ROOT_INODE_ABORT, |
| - | N_("can't proceed without a @r.\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Internal error: couldn't find dir_info */ |
| - | { PR_3_NO_DIRINFO, |
| - | N_("Internal error: cannot find dir_info for %i.\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Lost+found not a directory */ |
| - | { PR_3_LPF_NOTDIR, |
| - | N_("/@l is not a @d (ino=%i)\n"), |
| - | PROMPT_UNLINK, 0 }, |
| - | |
| - | /* Pass 3A Directory Optimization */ |
| - | |
| - | /* Pass 3A: Optimizing directories */ |
| - | { PR_3A_PASS_HEADER, |
| - | N_("Pass 3A: Optimizing directories\n"), |
| - | PROMPT_NONE, PR_PREEN_NOMSG }, |
| - | |
| - | /* Error iterating over directories */ |
| - | { PR_3A_OPTIMIZE_ITER, |
| - | N_("Failed to create dirs_to_hash iterator: %m"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Error rehash directory */ |
| - | { PR_3A_OPTIMIZE_DIR_ERR, |
| - | N_("Failed to optimize directory %q (%d): %m"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Rehashing dir header */ |
| - | { PR_3A_OPTIMIZE_DIR_HEADER, |
| - | N_("Optimizing directories: "), |
| - | PROMPT_NONE, PR_MSG_ONLY }, |
| - | |
| - | /* Rehashing directory %d */ |
| - | { PR_3A_OPTIMIZE_DIR, |
| - | " %d", |
| - | PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR}, |
| - | |
| - | /* Rehashing dir end */ |
| - | { PR_3A_OPTIMIZE_DIR_END, |
| - | "\n", |
| - | PROMPT_NONE, PR_PREEN_NOHDR }, |
| - | |
| - | /* Pass 4 errors */ |
| - | |
| - | /* Pass 4: Checking reference counts */ |
| - | { PR_4_PASS_HEADER, |
| - | N_("Pass 4: Checking reference counts\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Unattached zero-length inode */ |
| - | { PR_4_ZERO_LEN_INODE, |
| - | N_("@u @z @i %i. "), |
| - | PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK }, |
| - | |
| - | /* Unattached inode */ |
| - | { PR_4_UNATTACHED_INODE, |
| - | N_("@u @i %i\n"), |
| - | PROMPT_CONNECT, 0 }, |
| - | |
| - | /* Inode ref count wrong */ |
| - | { PR_4_BAD_REF_COUNT, |
| - | N_("@i %i ref count is %Il, @s %N. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | { PR_4_INCONSISTENT_COUNT, |
| - | N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n" |
| - | "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n" |
| - | "@i_link_info[%i] is %N, @i.i_links_count is %Il. " |
| - | "They @s the same!\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Pass 5 errors */ |
| - | |
| - | /* Pass 5: Checking group summary information */ |
| - | { PR_5_PASS_HEADER, |
| - | N_("Pass 5: Checking @g summary information\n"), |
| - | PROMPT_NONE, 0 }, |
| - | |
| - | /* Padding at end of inode bitmap is not set. */ |
| - | { PR_5_INODE_BMAP_PADDING, |
| - | N_("Padding at end of @i @B is not set. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Padding at end of block bitmap is not set. */ |
| - | { PR_5_BLOCK_BMAP_PADDING, |
| - | N_("Padding at end of @b @B is not set. "), |
| - | PROMPT_FIX, PR_PREEN_OK }, |
| - | |
| - | /* Block bitmap differences header */ |
| - | { PR_5_BLOCK_BITMAP_HEADER, |
| - | N_("@b @B differences: "), |
| - | PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG}, |
| - | |
| - | /* Block not used, but marked in bitmap */ |
| - | { PR_5_BLOCK_UNUSED, |
| - | " -%b", |
| - | PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Block used, but not marked used in bitmap */ |
| - | { PR_5_BLOCK_USED, |
| - | " +%b", |
| - | PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Block bitmap differences end */ |
| - | { PR_5_BLOCK_BITMAP_END, |
| - | "\n", |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Inode bitmap differences header */ |
| - | { PR_5_INODE_BITMAP_HEADER, |
| - | N_("@i @B differences: "), |
| - | PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Inode not used, but marked in bitmap */ |
| - | { PR_5_INODE_UNUSED, |
| - | " -%i", |
| - | PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Inode used, but not marked used in bitmap */ |
| - | { PR_5_INODE_USED, |
| - | " +%i", |
| - | PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Inode bitmap differences end */ |
| - | { PR_5_INODE_BITMAP_END, |
| - | "\n", |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Free inodes count for group wrong */ |
| - | { PR_5_FREE_INODE_COUNT_GROUP, |
| - | N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Directories count for group wrong */ |
| - | { PR_5_FREE_DIR_COUNT_GROUP, |
| - | N_("Directories count wrong for @g #%g (%i, counted=%j).\n"), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Free inodes count wrong */ |
| - | { PR_5_FREE_INODE_COUNT, |
| - | N_("Free @is count wrong (%i, counted=%j).\n"), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Free blocks count for group wrong */ |
| - | { PR_5_FREE_BLOCK_COUNT_GROUP, |
| - | N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Free blocks count wrong */ |
| - | { PR_5_FREE_BLOCK_COUNT, |
| - | N_("Free @bs count wrong (%b, counted=%c).\n"), |
| - | PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Programming error: bitmap endpoints don't match */ |
| - | { PR_5_BMAP_ENDPOINTS, |
| - | N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't " |
| - | "match calculated @B endpoints (%i, %j)\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Internal error: fudging end of bitmap */ |
| - | { PR_5_FUDGE_BITMAP_ERROR, |
| - | N_("Internal error: fudging end of bitmap (%N)\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error copying in replacement inode bitmap */ |
| - | { PR_5_COPY_IBITMAP_ERROR, |
| - | N_("Error copying in replacement @i @B: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Error copying in replacement block bitmap */ |
| - | { PR_5_COPY_BBITMAP_ERROR, |
| - | N_("Error copying in replacement @b @B: %m\n"), |
| - | PROMPT_NONE, PR_FATAL }, |
| - | |
| - | /* Block range not used, but marked in bitmap */ |
| - | { PR_5_BLOCK_RANGE_UNUSED, |
| - | " -(%b--%c)", |
| - | PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Block range used, but not marked used in bitmap */ |
| - | { PR_5_BLOCK_RANGE_USED, |
| - | " +(%b--%c)", |
| - | PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Inode range not used, but marked in bitmap */ |
| - | { PR_5_INODE_RANGE_UNUSED, |
| - | " -(%i--%j)", |
| - | PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | /* Inode range used, but not marked used in bitmap */ |
| - | { PR_5_INODE_RANGE_USED, |
| - | " +(%i--%j)", |
| - | PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG }, |
| - | |
| - | { 0 } |
| - | }; |
| - | |
| - | /* |
| - | * This is the latch flags register. It allows several problems to be |
| - | * "latched" together. This means that the user has to answer but one |
| - | * question for the set of problems, and all of the associated |
| - | * problems will be either fixed or not fixed. |
| - | */ |
| - | static struct latch_descr pr_latch_info[] = { |
| - | { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 }, |
| - | { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 }, |
| - | { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END }, |
| - | { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END }, |
| - | { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 }, |
| - | { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END }, |
| - | { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 }, |
| - | { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 }, |
| - | { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END }, |
| - | { -1, 0, 0 }, |
| - | }; |
| - | |
| - | static const struct e2fsck_problem *find_problem(problem_t code) |
| - | { |
| - | int i; |
| - | |
| - | for (i=0; problem_table[i].e2p_code; i++) { |
| - | if (problem_table[i].e2p_code == code) |
| - | return &problem_table[i]; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static struct latch_descr *find_latch(int code) |
| - | { |
| - | int i; |
| - | |
| - | for (i=0; pr_latch_info[i].latch_code >= 0; i++) { |
| - | if (pr_latch_info[i].latch_code == code) |
| - | return &pr_latch_info[i]; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | int end_problem_latch(e2fsck_t ctx, int mask) |
| - | { |
| - | struct latch_descr *ldesc; |
| - | struct problem_context pctx; |
| - | int answer = -1; |
| - | |
| - | ldesc = find_latch(mask); |
| - | if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) { |
| - | clear_problem_context(&pctx); |
| - | answer = fix_problem(ctx, ldesc->end_message, &pctx); |
| - | } |
| - | ldesc->flags &= ~(PRL_VARIABLE); |
| - | return answer; |
| - | } |
| - | |
| - | int set_latch_flags(int mask, int setflags, int clearflags) |
| - | { |
| - | struct latch_descr *ldesc; |
| - | |
| - | ldesc = find_latch(mask); |
| - | if (!ldesc) |
| - | return -1; |
| - | ldesc->flags |= setflags; |
| - | ldesc->flags &= ~clearflags; |
| - | return 0; |
| - | } |
| - | |
| - | void clear_problem_context(struct problem_context *ctx) |
| - | { |
| - | memset(ctx, 0, sizeof(struct problem_context)); |
| - | ctx->blkcount = -1; |
| - | ctx->group = -1; |
| - | } |
| - | |
| - | int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | const struct e2fsck_problem *ptr; |
| - | struct latch_descr *ldesc = NULL; |
| - | const char *message; |
| - | int def_yn, answer, ans; |
| - | int print_answer = 0; |
| - | int suppress = 0; |
| - | |
| - | ptr = find_problem(code); |
| - | if (!ptr) { |
| - | printf(_("Unhandled error code (0x%x)!\n"), code); |
| - | return 0; |
| - | } |
| - | def_yn = 1; |
| - | if ((ptr->flags & PR_NO_DEFAULT) || |
| - | ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) || |
| - | (ctx->options & E2F_OPT_NO)) |
| - | def_yn= 0; |
| - | |
| - | /* |
| - | * Do special latch processing. This is where we ask the |
| - | * latch question, if it exists |
| - | */ |
| - | if (ptr->flags & PR_LATCH_MASK) { |
| - | ldesc = find_latch(ptr->flags & PR_LATCH_MASK); |
| - | if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) { |
| - | ans = fix_problem(ctx, ldesc->question, pctx); |
| - | if (ans == 1) |
| - | ldesc->flags |= PRL_YES; |
| - | if (ans == 0) |
| - | ldesc->flags |= PRL_NO; |
| - | ldesc->flags |= PRL_LATCHED; |
| - | } |
| - | if (ldesc->flags & PRL_SUPPRESS) |
| - | suppress++; |
| - | } |
| - | if ((ptr->flags & PR_PREEN_NOMSG) && |
| - | (ctx->options & E2F_OPT_PREEN)) |
| - | suppress++; |
| - | if ((ptr->flags & PR_NO_NOMSG) && |
| - | (ctx->options & E2F_OPT_NO)) |
| - | suppress++; |
| - | if (!suppress) { |
| - | message = ptr->e2p_description; |
| - | if ((ctx->options & E2F_OPT_PREEN) && |
| - | !(ptr->flags & PR_PREEN_NOHDR)) { |
| - | printf("%s: ", ctx->device_name ? |
| - | ctx->device_name : ctx->filesystem_name); |
| - | } |
| - | if (*message) |
| - | print_e2fsck_message(ctx, _(message), pctx, 1); |
| - | } |
| - | if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE)) |
| - | preenhalt(ctx); |
| - | |
| - | if (ptr->flags & PR_FATAL) |
| - | bb_error_msg_and_die(0); |
| - | |
| - | if (ptr->prompt == PROMPT_NONE) { |
| - | if (ptr->flags & PR_NOCOLLATE) |
| - | answer = -1; |
| - | else |
| - | answer = def_yn; |
| - | } else { |
| - | if (ctx->options & E2F_OPT_PREEN) { |
| - | answer = def_yn; |
| - | if (!(ptr->flags & PR_PREEN_NOMSG)) |
| - | print_answer = 1; |
| - | } else if ((ptr->flags & PR_LATCH_MASK) && |
| - | (ldesc->flags & (PRL_YES | PRL_NO))) { |
| - | if (!suppress) |
| - | print_answer = 1; |
| - | if (ldesc->flags & PRL_YES) |
| - | answer = 1; |
| - | else |
| - | answer = 0; |
| - | } else |
| - | answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn); |
| - | if (!answer && !(ptr->flags & PR_NO_OK)) |
| - | ext2fs_unmark_valid(fs); |
| - | |
| - | if (print_answer) |
| - | printf("%s.\n", answer ? |
| - | _(preen_msg[(int) ptr->prompt]) : _("IGNORED")); |
| - | } |
| - | |
| - | if ((ptr->prompt == PROMPT_ABORT) && answer) |
| - | bb_error_msg_and_die(0); |
| - | |
| - | if (ptr->flags & PR_AFTER_CODE) |
| - | answer = fix_problem(ctx, ptr->second_code, pctx); |
| - | |
| - | return answer; |
| - | } |
| - | |
| - | /* |
| - | * linux/fs/recovery.c |
| - | * |
| - | * Written by Stephen C. Tweedie <[email protected]>, 1999 |
| - | */ |
| - | |
| - | /* |
| - | * Maintain information about the progress of the recovery job, so that |
| - | * the different passes can carry information between them. |
| - | */ |
| - | struct recovery_info |
| - | { |
| - | tid_t start_transaction; |
| - | tid_t end_transaction; |
| - | |
| - | int nr_replays; |
| - | int nr_revokes; |
| - | int nr_revoke_hits; |
| - | }; |
| - | |
| - | enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY}; |
| - | static int do_one_pass(journal_t *journal, |
| - | struct recovery_info *info, enum passtype pass); |
| - | static int scan_revoke_records(journal_t *, struct buffer_head *, |
| - | tid_t, struct recovery_info *); |
| - | |
| - | /* |
| - | * Read a block from the journal |
| - | */ |
| - | |
| - | static int jread(struct buffer_head **bhp, journal_t *journal, |
| - | unsigned int offset) |
| - | { |
| - | int err; |
| - | unsigned long blocknr; |
| - | struct buffer_head *bh; |
| - | |
| - | *bhp = NULL; |
| - | |
| - | err = journal_bmap(journal, offset, &blocknr); |
| - | |
| - | if (err) { |
| - | printf("JBD: bad block at offset %u\n", offset); |
| - | return err; |
| - | } |
| - | |
| - | bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); |
| - | if (!bh) |
| - | return -ENOMEM; |
| - | |
| - | if (!buffer_uptodate(bh)) { |
| - | /* If this is a brand new buffer, start readahead. |
| - | Otherwise, we assume we are already reading it. */ |
| - | if (!buffer_req(bh)) |
| - | do_readahead(journal, offset); |
| - | wait_on_buffer(bh); |
| - | } |
| - | |
| - | if (!buffer_uptodate(bh)) { |
| - | printf("JBD: Failed to read block at offset %u\n", offset); |
| - | brelse(bh); |
| - | return -EIO; |
| - | } |
| - | |
| - | *bhp = bh; |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Count the number of in-use tags in a journal descriptor block. |
| - | */ |
| - | |
| - | static int count_tags(struct buffer_head *bh, int size) |
| - | { |
| - | char * tagp; |
| - | journal_block_tag_t * tag; |
| - | int nr = 0; |
| - | |
| - | tagp = &bh->b_data[sizeof(journal_header_t)]; |
| - | |
| - | while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) { |
| - | tag = (journal_block_tag_t *) tagp; |
| - | |
| - | nr++; |
| - | tagp += sizeof(journal_block_tag_t); |
| - | if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID))) |
| - | tagp += 16; |
| - | |
| - | if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG)) |
| - | break; |
| - | } |
| - | |
| - | return nr; |
| - | } |
| - | |
| - | |
| - | /* Make sure we wrap around the log correctly! */ |
| - | #define wrap(journal, var) \ |
| - | do { \ |
| - | if (var >= (journal)->j_last) \ |
| - | var -= ((journal)->j_last - (journal)->j_first); \ |
| - | } while (0) |
| - | |
| - | /** |
| - | * int journal_recover(journal_t *journal) - recovers a on-disk journal |
| - | * @journal: the journal to recover |
| - | * |
| - | * The primary function for recovering the log contents when mounting a |
| - | * journaled device. |
| - | * |
| - | * Recovery is done in three passes. In the first pass, we look for the |
| - | * end of the log. In the second, we assemble the list of revoke |
| - | * blocks. In the third and final pass, we replay any un-revoked blocks |
| - | * in the log. |
| - | */ |
| - | int journal_recover(journal_t *journal) |
| - | { |
| - | int err; |
| - | journal_superblock_t * sb; |
| - | |
| - | struct recovery_info info; |
| - | |
| - | memset(&info, 0, sizeof(info)); |
| - | sb = journal->j_superblock; |
| - | |
| - | /* |
| - | * The journal superblock's s_start field (the current log head) |
| - | * is always zero if, and only if, the journal was cleanly |
| - | * unmounted. |
| - | */ |
| - | |
| - | if (!sb->s_start) { |
| - | journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1; |
| - | return 0; |
| - | } |
| - | |
| - | err = do_one_pass(journal, &info, PASS_SCAN); |
| - | if (!err) |
| - | err = do_one_pass(journal, &info, PASS_REVOKE); |
| - | if (!err) |
| - | err = do_one_pass(journal, &info, PASS_REPLAY); |
| - | |
| - | /* Restart the log at the next transaction ID, thus invalidating |
| - | * any existing commit records in the log. */ |
| - | journal->j_transaction_sequence = ++info.end_transaction; |
| - | |
| - | journal_clear_revoke(journal); |
| - | sync_blockdev(journal->j_fs_dev); |
| - | return err; |
| - | } |
| - | |
| - | static int do_one_pass(journal_t *journal, |
| - | struct recovery_info *info, enum passtype pass) |
| - | { |
| - | unsigned int first_commit_ID, next_commit_ID; |
| - | unsigned long next_log_block; |
| - | int err, success = 0; |
| - | journal_superblock_t * sb; |
| - | journal_header_t * tmp; |
| - | struct buffer_head * bh; |
| - | unsigned int sequence; |
| - | int blocktype; |
| - | |
| - | /* Precompute the maximum metadata descriptors in a descriptor block */ |
| - | int MAX_BLOCKS_PER_DESC; |
| - | MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) |
| - | / sizeof(journal_block_tag_t)); |
| - | |
| - | /* |
| - | * First thing is to establish what we expect to find in the log |
| - | * (in terms of transaction IDs), and where (in terms of log |
| - | * block offsets): query the superblock. |
| - | */ |
| - | |
| - | sb = journal->j_superblock; |
| - | next_commit_ID = ntohl(sb->s_sequence); |
| - | next_log_block = ntohl(sb->s_start); |
| - | |
| - | first_commit_ID = next_commit_ID; |
| - | if (pass == PASS_SCAN) |
| - | info->start_transaction = first_commit_ID; |
| - | |
| - | /* |
| - | * Now we walk through the log, transaction by transaction, |
| - | * making sure that each transaction has a commit block in the |
| - | * expected place. Each complete transaction gets replayed back |
| - | * into the main filesystem. |
| - | */ |
| - | |
| - | while (1) { |
| - | int flags; |
| - | char * tagp; |
| - | journal_block_tag_t * tag; |
| - | struct buffer_head * obh; |
| - | struct buffer_head * nbh; |
| - | |
| - | /* If we already know where to stop the log traversal, |
| - | * check right now that we haven't gone past the end of |
| - | * the log. */ |
| - | |
| - | if (pass != PASS_SCAN) |
| - | if (tid_geq(next_commit_ID, info->end_transaction)) |
| - | break; |
| - | |
| - | /* Skip over each chunk of the transaction looking |
| - | * either the next descriptor block or the final commit |
| - | * record. */ |
| - | |
| - | err = jread(&bh, journal, next_log_block); |
| - | if (err) |
| - | goto failed; |
| - | |
| - | next_log_block++; |
| - | wrap(journal, next_log_block); |
| - | |
| - | /* What kind of buffer is it? |
| - | * |
| - | * If it is a descriptor block, check that it has the |
| - | * expected sequence number. Otherwise, we're all done |
| - | * here. */ |
| - | |
| - | tmp = (journal_header_t *)bh->b_data; |
| - | |
| - | if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) { |
| - | brelse(bh); |
| - | break; |
| - | } |
| - | |
| - | blocktype = ntohl(tmp->h_blocktype); |
| - | sequence = ntohl(tmp->h_sequence); |
| - | |
| - | if (sequence != next_commit_ID) { |
| - | brelse(bh); |
| - | break; |
| - | } |
| - | |
| - | /* OK, we have a valid descriptor block which matches |
| - | * all of the sequence number checks. What are we going |
| - | * to do with it? That depends on the pass... */ |
| - | |
| - | switch (blocktype) { |
| - | case JFS_DESCRIPTOR_BLOCK: |
| - | /* If it is a valid descriptor block, replay it |
| - | * in pass REPLAY; otherwise, just skip over the |
| - | * blocks it describes. */ |
| - | if (pass != PASS_REPLAY) { |
| - | next_log_block += |
| - | count_tags(bh, journal->j_blocksize); |
| - | wrap(journal, next_log_block); |
| - | brelse(bh); |
| - | continue; |
| - | } |
| - | |
| - | /* A descriptor block: we can now write all of |
| - | * the data blocks. Yay, useful work is finally |
| - | * getting done here! */ |
| - | |
| - | tagp = &bh->b_data[sizeof(journal_header_t)]; |
| - | while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) |
| - | <= journal->j_blocksize) { |
| - | unsigned long io_block; |
| - | |
| - | tag = (journal_block_tag_t *) tagp; |
| - | flags = ntohl(tag->t_flags); |
| - | |
| - | io_block = next_log_block++; |
| - | wrap(journal, next_log_block); |
| - | err = jread(&obh, journal, io_block); |
| - | if (err) { |
| - | /* Recover what we can, but |
| - | * report failure at the end. */ |
| - | success = err; |
| - | printf("JBD: IO error %d recovering " |
| - | "block %ld in log\n", |
| - | err, io_block); |
| - | } else { |
| - | unsigned long blocknr; |
| - | |
| - | blocknr = ntohl(tag->t_blocknr); |
| - | |
| - | /* If the block has been |
| - | * revoked, then we're all done |
| - | * here. */ |
| - | if (journal_test_revoke |
| - | (journal, blocknr, |
| - | next_commit_ID)) { |
| - | brelse(obh); |
| - | ++info->nr_revoke_hits; |
| - | goto skip_write; |
| - | } |
| - | |
| - | /* Find a buffer for the new |
| - | * data being restored */ |
| - | nbh = getblk(journal->j_fs_dev, |
| - | blocknr, |
| - | journal->j_blocksize); |
| - | if (nbh == NULL) { |
| - | printf("JBD: Out of memory " |
| - | "during recovery.\n"); |
| - | err = -ENOMEM; |
| - | brelse(bh); |
| - | brelse(obh); |
| - | goto failed; |
| - | } |
| - | |
| - | lock_buffer(nbh); |
| - | memcpy(nbh->b_data, obh->b_data, |
| - | journal->j_blocksize); |
| - | if (flags & JFS_FLAG_ESCAPE) { |
| - | *((unsigned int *)bh->b_data) = |
| - | htonl(JFS_MAGIC_NUMBER); |
| - | } |
| - | |
| - | mark_buffer_uptodate(nbh, 1); |
| - | mark_buffer_dirty(nbh); |
| - | ++info->nr_replays; |
| - | /* ll_rw_block(WRITE, 1, &nbh); */ |
| - | unlock_buffer(nbh); |
| - | brelse(obh); |
| - | brelse(nbh); |
| - | } |
| - | |
| - | skip_write: |
| - | tagp += sizeof(journal_block_tag_t); |
| - | if (!(flags & JFS_FLAG_SAME_UUID)) |
| - | tagp += 16; |
| - | |
| - | if (flags & JFS_FLAG_LAST_TAG) |
| - | break; |
| - | } |
| - | |
| - | brelse(bh); |
| - | continue; |
| - | |
| - | case JFS_COMMIT_BLOCK: |
| - | /* Found an expected commit block: not much to |
| - | * do other than move on to the next sequence |
| - | * number. */ |
| - | brelse(bh); |
| - | next_commit_ID++; |
| - | continue; |
| - | |
| - | case JFS_REVOKE_BLOCK: |
| - | /* If we aren't in the REVOKE pass, then we can |
| - | * just skip over this block. */ |
| - | if (pass != PASS_REVOKE) { |
| - | brelse(bh); |
| - | continue; |
| - | } |
| - | |
| - | err = scan_revoke_records(journal, bh, |
| - | next_commit_ID, info); |
| - | brelse(bh); |
| - | if (err) |
| - | goto failed; |
| - | continue; |
| - | |
| - | default: |
| - | goto done; |
| - | } |
| - | } |
| - | |
| - | done: |
| - | /* |
| - | * We broke out of the log scan loop: either we came to the |
| - | * known end of the log or we found an unexpected block in the |
| - | * log. If the latter happened, then we know that the "current" |
| - | * transaction marks the end of the valid log. |
| - | */ |
| - | |
| - | if (pass == PASS_SCAN) |
| - | info->end_transaction = next_commit_ID; |
| - | else { |
| - | /* It's really bad news if different passes end up at |
| - | * different places (but possible due to IO errors). */ |
| - | if (info->end_transaction != next_commit_ID) { |
| - | printf("JBD: recovery pass %d ended at " |
| - | "transaction %u, expected %u\n", |
| - | pass, next_commit_ID, info->end_transaction); |
| - | if (!success) |
| - | success = -EIO; |
| - | } |
| - | } |
| - | |
| - | return success; |
| - | |
| - | failed: |
| - | return err; |
| - | } |
| - | |
| - | |
| - | /* Scan a revoke record, marking all blocks mentioned as revoked. */ |
| - | |
| - | static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, |
| - | tid_t sequence, struct recovery_info *info) |
| - | { |
| - | journal_revoke_header_t *header; |
| - | int offset, max; |
| - | |
| - | header = (journal_revoke_header_t *) bh->b_data; |
| - | offset = sizeof(journal_revoke_header_t); |
| - | max = ntohl(header->r_count); |
| - | |
| - | while (offset < max) { |
| - | unsigned long blocknr; |
| - | int err; |
| - | |
| - | blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset))); |
| - | offset += 4; |
| - | err = journal_set_revoke(journal, blocknr, sequence); |
| - | if (err) |
| - | return err; |
| - | ++info->nr_revokes; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * rehash.c --- rebuild hash tree directories |
| - | * |
| - | * This algorithm is designed for simplicity of implementation and to |
| - | * pack the directory as much as possible. It however requires twice |
| - | * as much memory as the size of the directory. The maximum size |
| - | * directory supported using a 4k blocksize is roughly a gigabyte, and |
| - | * so there may very well be problems with machines that don't have |
| - | * virtual memory, and obscenely large directories. |
| - | * |
| - | * An alternate algorithm which is much more disk intensive could be |
| - | * written, and probably will need to be written in the future. The |
| - | * design goals of such an algorithm are: (a) use (roughly) constant |
| - | * amounts of memory, no matter how large the directory, (b) the |
| - | * directory must be safe at all times, even if e2fsck is interrupted |
| - | * in the middle, (c) we must use minimal amounts of extra disk |
| - | * blocks. This pretty much requires an incremental approach, where |
| - | * we are reading from one part of the directory, and inserting into |
| - | * the front half. So the algorithm will have to keep track of a |
| - | * moving block boundary between the new tree and the old tree, and |
| - | * files will need to be moved from the old directory and inserted |
| - | * into the new tree. If the new directory requires space which isn't |
| - | * yet available, blocks from the beginning part of the old directory |
| - | * may need to be moved to the end of the directory to make room for |
| - | * the new tree: |
| - | * |
| - | * -------------------------------------------------------- |
| - | * | new tree | | old tree | |
| - | * -------------------------------------------------------- |
| - | * ^ ptr ^ptr |
| - | * tail new head old |
| - | * |
| - | * This is going to be a pain in the tuckus to implement, and will |
| - | * require a lot more disk accesses. So I'm going to skip it for now; |
| - | * it's only really going to be an issue for really, really big |
| - | * filesystems (when we reach the level of tens of millions of files |
| - | * in a single directory). It will probably be easier to simply |
| - | * require that e2fsck use VM first. |
| - | */ |
| - | |
| - | struct fill_dir_struct { |
| - | char *buf; |
| - | struct ext2_inode *inode; |
| - | int err; |
| - | e2fsck_t ctx; |
| - | struct hash_entry *harray; |
| - | int max_array, num_array; |
| - | int dir_size; |
| - | int compress; |
| - | ino_t parent; |
| - | }; |
| - | |
| - | struct hash_entry { |
| - | ext2_dirhash_t hash; |
| - | ext2_dirhash_t minor_hash; |
| - | struct ext2_dir_entry *dir; |
| - | }; |
| - | |
| - | struct out_dir { |
| - | int num; |
| - | int max; |
| - | char *buf; |
| - | ext2_dirhash_t *hashes; |
| - | }; |
| - | |
| - | static int fill_dir_block(ext2_filsys fs, |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data; |
| - | struct hash_entry *new_array, *ent; |
| - | struct ext2_dir_entry *dirent; |
| - | char *dir; |
| - | unsigned int offset, dir_offset; |
| - | |
| - | if (blockcnt < 0) |
| - | return 0; |
| - | |
| - | offset = blockcnt * fs->blocksize; |
| - | if (offset + fs->blocksize > fd->inode->i_size) { |
| - | fd->err = EXT2_ET_DIR_CORRUPTED; |
| - | return BLOCK_ABORT; |
| - | } |
| - | dir = (fd->buf+offset); |
| - | if (HOLE_BLKADDR(*block_nr)) { |
| - | memset(dir, 0, fs->blocksize); |
| - | dirent = (struct ext2_dir_entry *) dir; |
| - | dirent->rec_len = fs->blocksize; |
| - | } else { |
| - | fd->err = ext2fs_read_dir_block(fs, *block_nr, dir); |
| - | if (fd->err) |
| - | return BLOCK_ABORT; |
| - | } |
| - | /* While the directory block is "hot", index it. */ |
| - | dir_offset = 0; |
| - | while (dir_offset < fs->blocksize) { |
| - | dirent = (struct ext2_dir_entry *) (dir + dir_offset); |
| - | if (((dir_offset + dirent->rec_len) > fs->blocksize) || |
| - | (dirent->rec_len < 8) || |
| - | ((dirent->rec_len % 4) != 0) || |
| - | (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { |
| - | fd->err = EXT2_ET_DIR_CORRUPTED; |
| - | return BLOCK_ABORT; |
| - | } |
| - | dir_offset += dirent->rec_len; |
| - | if (dirent->inode == 0) |
| - | continue; |
| - | if (!fd->compress && ((dirent->name_len&0xFF) == 1) && |
| - | (dirent->name[0] == '.')) |
| - | continue; |
| - | if (!fd->compress && ((dirent->name_len&0xFF) == 2) && |
| - | (dirent->name[0] == '.') && (dirent->name[1] == '.')) { |
| - | fd->parent = dirent->inode; |
| - | continue; |
| - | } |
| - | if (fd->num_array >= fd->max_array) { |
| - | new_array = xrealloc(fd->harray, |
| - | sizeof(struct hash_entry) * (fd->max_array+500)); |
| - | fd->harray = new_array; |
| - | fd->max_array += 500; |
| - | } |
| - | ent = fd->harray + fd->num_array++; |
| - | ent->dir = dirent; |
| - | fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF); |
| - | if (fd->compress) |
| - | ent->hash = ent->minor_hash = 0; |
| - | else { |
| - | fd->err = ext2fs_dirhash(fs->super->s_def_hash_version, |
| - | dirent->name, |
| - | dirent->name_len & 0xFF, |
| - | fs->super->s_hash_seed, |
| - | &ent->hash, &ent->minor_hash); |
| - | if (fd->err) |
| - | return BLOCK_ABORT; |
| - | } |
| - | } |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* Used for sorting the hash entry */ |
| - | static int name_cmp(const void *a, const void *b) |
| - | { |
| - | const struct hash_entry *he_a = (const struct hash_entry *) a; |
| - | const struct hash_entry *he_b = (const struct hash_entry *) b; |
| - | int ret; |
| - | int min_len; |
| - | |
| - | min_len = he_a->dir->name_len; |
| - | if (min_len > he_b->dir->name_len) |
| - | min_len = he_b->dir->name_len; |
| - | |
| - | ret = strncmp(he_a->dir->name, he_b->dir->name, min_len); |
| - | if (ret == 0) { |
| - | if (he_a->dir->name_len > he_b->dir->name_len) |
| - | ret = 1; |
| - | else if (he_a->dir->name_len < he_b->dir->name_len) |
| - | ret = -1; |
| - | else |
| - | ret = he_b->dir->inode - he_a->dir->inode; |
| - | } |
| - | return ret; |
| - | } |
| - | |
| - | /* Used for sorting the hash entry */ |
| - | static int hash_cmp(const void *a, const void *b) |
| - | { |
| - | const struct hash_entry *he_a = (const struct hash_entry *) a; |
| - | const struct hash_entry *he_b = (const struct hash_entry *) b; |
| - | int ret; |
| - | |
| - | if (he_a->hash > he_b->hash) |
| - | ret = 1; |
| - | else if (he_a->hash < he_b->hash) |
| - | ret = -1; |
| - | else { |
| - | if (he_a->minor_hash > he_b->minor_hash) |
| - | ret = 1; |
| - | else if (he_a->minor_hash < he_b->minor_hash) |
| - | ret = -1; |
| - | else |
| - | ret = name_cmp(a, b); |
| - | } |
| - | return ret; |
| - | } |
| - | |
| - | static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir, |
| - | int blocks) |
| - | { |
| - | void *new_mem; |
| - | |
| - | if (outdir->max) { |
| - | new_mem = xrealloc(outdir->buf, blocks * fs->blocksize); |
| - | outdir->buf = new_mem; |
| - | new_mem = xrealloc(outdir->hashes, |
| - | blocks * sizeof(ext2_dirhash_t)); |
| - | outdir->hashes = new_mem; |
| - | } else { |
| - | outdir->buf = xmalloc(blocks * fs->blocksize); |
| - | outdir->hashes = xmalloc(blocks * sizeof(ext2_dirhash_t)); |
| - | outdir->num = 0; |
| - | } |
| - | outdir->max = blocks; |
| - | return 0; |
| - | } |
| - | |
| - | static void free_out_dir(struct out_dir *outdir) |
| - | { |
| - | free(outdir->buf); |
| - | free(outdir->hashes); |
| - | outdir->max = 0; |
| - | outdir->num =0; |
| - | } |
| - | |
| - | static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir, |
| - | char ** ret) |
| - | { |
| - | errcode_t retval; |
| - | |
| - | if (outdir->num >= outdir->max) { |
| - | retval = alloc_size_dir(fs, outdir, outdir->max + 50); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | *ret = outdir->buf + (outdir->num++ * fs->blocksize); |
| - | memset(*ret, 0, fs->blocksize); |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This function is used to make a unique filename. We do this by |
| - | * appending ~0, and then incrementing the number. However, we cannot |
| - | * expand the length of the filename beyond the padding available in |
| - | * the directory entry. |
| - | */ |
| - | static void mutate_name(char *str, __u16 *len) |
| - | { |
| - | int i; |
| - | __u16 l = *len & 0xFF, h = *len & 0xff00; |
| - | |
| - | /* |
| - | * First check to see if it looks the name has been mutated |
| - | * already |
| - | */ |
| - | for (i = l-1; i > 0; i--) { |
| - | if (!isdigit(str[i])) |
| - | break; |
| - | } |
| - | if ((i == l-1) || (str[i] != '~')) { |
| - | if (((l-1) & 3) < 2) |
| - | l += 2; |
| - | else |
| - | l = (l+3) & ~3; |
| - | str[l-2] = '~'; |
| - | str[l-1] = '0'; |
| - | *len = l | h; |
| - | return; |
| - | } |
| - | for (i = l-1; i >= 0; i--) { |
| - | if (isdigit(str[i])) { |
| - | if (str[i] == '9') |
| - | str[i] = '0'; |
| - | else { |
| - | str[i]++; |
| - | return; |
| - | } |
| - | continue; |
| - | } |
| - | if (i == 1) { |
| - | if (str[0] == 'z') |
| - | str[0] = 'A'; |
| - | else if (str[0] == 'Z') { |
| - | str[0] = '~'; |
| - | str[1] = '0'; |
| - | } else |
| - | str[0]++; |
| - | } else if (i > 0) { |
| - | str[i] = '1'; |
| - | str[i-1] = '~'; |
| - | } else { |
| - | if (str[0] == '~') |
| - | str[0] = 'a'; |
| - | else |
| - | str[0]++; |
| - | } |
| - | break; |
| - | } |
| - | } |
| - | |
| - | static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, |
| - | ext2_ino_t ino, |
| - | struct fill_dir_struct *fd) |
| - | { |
| - | struct problem_context pctx; |
| - | struct hash_entry *ent, *prev; |
| - | int i, j; |
| - | int fixed = 0; |
| - | char new_name[256]; |
| - | __u16 new_len; |
| - | |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | |
| - | for (i=1; i < fd->num_array; i++) { |
| - | ent = fd->harray + i; |
| - | prev = ent - 1; |
| - | if (!ent->dir->inode || |
| - | ((ent->dir->name_len & 0xFF) != |
| - | (prev->dir->name_len & 0xFF)) || |
| - | (strncmp(ent->dir->name, prev->dir->name, |
| - | ent->dir->name_len & 0xFF))) |
| - | continue; |
| - | pctx.dirent = ent->dir; |
| - | if ((ent->dir->inode == prev->dir->inode) && |
| - | fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) { |
| - | e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1); |
| - | ent->dir->inode = 0; |
| - | fixed++; |
| - | continue; |
| - | } |
| - | memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF); |
| - | new_len = ent->dir->name_len; |
| - | mutate_name(new_name, &new_len); |
| - | for (j=0; j < fd->num_array; j++) { |
| - | if ((i==j) || |
| - | ((ent->dir->name_len & 0xFF) != |
| - | (fd->harray[j].dir->name_len & 0xFF)) || |
| - | (strncmp(new_name, fd->harray[j].dir->name, |
| - | new_len & 0xFF))) |
| - | continue; |
| - | mutate_name(new_name, &new_len); |
| - | |
| - | j = -1; |
| - | } |
| - | new_name[new_len & 0xFF] = 0; |
| - | pctx.str = new_name; |
| - | if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) { |
| - | memcpy(ent->dir->name, new_name, new_len & 0xFF); |
| - | ent->dir->name_len = new_len; |
| - | ext2fs_dirhash(fs->super->s_def_hash_version, |
| - | ent->dir->name, |
| - | ent->dir->name_len & 0xFF, |
| - | fs->super->s_hash_seed, |
| - | &ent->hash, &ent->minor_hash); |
| - | fixed++; |
| - | } |
| - | } |
| - | return fixed; |
| - | } |
| - | |
| - | |
| - | static errcode_t copy_dir_entries(ext2_filsys fs, |
| - | struct fill_dir_struct *fd, |
| - | struct out_dir *outdir) |
| - | { |
| - | errcode_t retval; |
| - | char *block_start; |
| - | struct hash_entry *ent; |
| - | struct ext2_dir_entry *dirent; |
| - | int i, rec_len, left; |
| - | ext2_dirhash_t prev_hash; |
| - | int offset; |
| - | |
| - | outdir->max = 0; |
| - | retval = alloc_size_dir(fs, outdir, |
| - | (fd->dir_size / fs->blocksize) + 2); |
| - | if (retval) |
| - | return retval; |
| - | outdir->num = fd->compress ? 0 : 1; |
| - | offset = 0; |
| - | outdir->hashes[0] = 0; |
| - | prev_hash = 1; |
| - | if ((retval = get_next_block(fs, outdir, &block_start))) |
| - | return retval; |
| - | dirent = (struct ext2_dir_entry *) block_start; |
| - | left = fs->blocksize; |
| - | for (i=0; i < fd->num_array; i++) { |
| - | ent = fd->harray + i; |
| - | if (ent->dir->inode == 0) |
| - | continue; |
| - | rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF); |
| - | if (rec_len > left) { |
| - | if (left) |
| - | dirent->rec_len += left; |
| - | if ((retval = get_next_block(fs, outdir, |
| - | &block_start))) |
| - | return retval; |
| - | offset = 0; |
| - | } |
| - | left = fs->blocksize - offset; |
| - | dirent = (struct ext2_dir_entry *) (block_start + offset); |
| - | if (offset == 0) { |
| - | if (ent->hash == prev_hash) |
| - | outdir->hashes[outdir->num-1] = ent->hash | 1; |
| - | else |
| - | outdir->hashes[outdir->num-1] = ent->hash; |
| - | } |
| - | dirent->inode = ent->dir->inode; |
| - | dirent->name_len = ent->dir->name_len; |
| - | dirent->rec_len = rec_len; |
| - | memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF); |
| - | offset += rec_len; |
| - | left -= rec_len; |
| - | if (left < 12) { |
| - | dirent->rec_len += left; |
| - | offset += left; |
| - | left = 0; |
| - | } |
| - | prev_hash = ent->hash; |
| - | } |
| - | if (left) |
| - | dirent->rec_len += left; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf, |
| - | ext2_ino_t ino, ext2_ino_t parent) |
| - | { |
| - | struct ext2_dir_entry *dir; |
| - | struct ext2_dx_root_info *root; |
| - | struct ext2_dx_countlimit *limits; |
| - | int filetype = 0; |
| - | |
| - | if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) |
| - | filetype = EXT2_FT_DIR << 8; |
| - | |
| - | memset(buf, 0, fs->blocksize); |
| - | dir = (struct ext2_dir_entry *) buf; |
| - | dir->inode = ino; |
| - | dir->name[0] = '.'; |
| - | dir->name_len = 1 | filetype; |
| - | dir->rec_len = 12; |
| - | dir = (struct ext2_dir_entry *) (buf + 12); |
| - | dir->inode = parent; |
| - | dir->name[0] = '.'; |
| - | dir->name[1] = '.'; |
| - | dir->name_len = 2 | filetype; |
| - | dir->rec_len = fs->blocksize - 12; |
| - | |
| - | root = (struct ext2_dx_root_info *) (buf+24); |
| - | root->reserved_zero = 0; |
| - | root->hash_version = fs->super->s_def_hash_version; |
| - | root->info_length = 8; |
| - | root->indirect_levels = 0; |
| - | root->unused_flags = 0; |
| - | |
| - | limits = (struct ext2_dx_countlimit *) (buf+32); |
| - | limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry); |
| - | limits->count = 0; |
| - | |
| - | return root; |
| - | } |
| - | |
| - | |
| - | static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf) |
| - | { |
| - | struct ext2_dir_entry *dir; |
| - | struct ext2_dx_countlimit *limits; |
| - | |
| - | memset(buf, 0, fs->blocksize); |
| - | dir = (struct ext2_dir_entry *) buf; |
| - | dir->inode = 0; |
| - | dir->rec_len = fs->blocksize; |
| - | |
| - | limits = (struct ext2_dx_countlimit *) (buf+8); |
| - | limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry); |
| - | limits->count = 0; |
| - | |
| - | return (struct ext2_dx_entry *) limits; |
| - | } |
| - | |
| - | /* |
| - | * This function takes the leaf nodes which have been written in |
| - | * outdir, and populates the root node and any necessary interior nodes. |
| - | */ |
| - | static errcode_t calculate_tree(ext2_filsys fs, |
| - | struct out_dir *outdir, |
| - | ext2_ino_t ino, |
| - | ext2_ino_t parent) |
| - | { |
| - | struct ext2_dx_root_info *root_info; |
| - | struct ext2_dx_entry *root, *dx_ent = NULL; |
| - | struct ext2_dx_countlimit *root_limit, *limit; |
| - | errcode_t retval; |
| - | char * block_start; |
| - | int i, c1, c2, nblks; |
| - | int limit_offset, root_offset; |
| - | |
| - | root_info = set_root_node(fs, outdir->buf, ino, parent); |
| - | root_offset = limit_offset = ((char *) root_info - outdir->buf) + |
| - | root_info->info_length; |
| - | root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset); |
| - | c1 = root_limit->limit; |
| - | nblks = outdir->num; |
| - | |
| - | /* Write out the pointer blocks */ |
| - | if (nblks-1 <= c1) { |
| - | /* Just write out the root block, and we're done */ |
| - | root = (struct ext2_dx_entry *) (outdir->buf + root_offset); |
| - | for (i=1; i < nblks; i++) { |
| - | root->block = ext2fs_cpu_to_le32(i); |
| - | if (i != 1) |
| - | root->hash = |
| - | ext2fs_cpu_to_le32(outdir->hashes[i]); |
| - | root++; |
| - | c1--; |
| - | } |
| - | } else { |
| - | c2 = 0; |
| - | limit = 0; |
| - | root_info->indirect_levels = 1; |
| - | for (i=1; i < nblks; i++) { |
| - | if (c1 == 0) |
| - | return ENOSPC; |
| - | if (c2 == 0) { |
| - | if (limit) |
| - | limit->limit = limit->count = |
| - | ext2fs_cpu_to_le16(limit->limit); |
| - | root = (struct ext2_dx_entry *) |
| - | (outdir->buf + root_offset); |
| - | root->block = ext2fs_cpu_to_le32(outdir->num); |
| - | if (i != 1) |
| - | root->hash = |
| - | ext2fs_cpu_to_le32(outdir->hashes[i]); |
| - | if ((retval = get_next_block(fs, outdir, |
| - | &block_start))) |
| - | return retval; |
| - | dx_ent = set_int_node(fs, block_start); |
| - | limit = (struct ext2_dx_countlimit *) dx_ent; |
| - | c2 = limit->limit; |
| - | root_offset += sizeof(struct ext2_dx_entry); |
| - | c1--; |
| - | } |
| - | dx_ent->block = ext2fs_cpu_to_le32(i); |
| - | if (c2 != limit->limit) |
| - | dx_ent->hash = |
| - | ext2fs_cpu_to_le32(outdir->hashes[i]); |
| - | dx_ent++; |
| - | c2--; |
| - | } |
| - | limit->count = ext2fs_cpu_to_le16(limit->limit - c2); |
| - | limit->limit = ext2fs_cpu_to_le16(limit->limit); |
| - | } |
| - | root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset); |
| - | root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1); |
| - | root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | struct write_dir_struct { |
| - | struct out_dir *outdir; |
| - | errcode_t err; |
| - | e2fsck_t ctx; |
| - | int cleared; |
| - | }; |
| - | |
| - | /* |
| - | * Helper function which writes out a directory block. |
| - | */ |
| - | static int write_dir_block(ext2_filsys fs, |
| - | blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_block FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; |
| - | blk_t blk; |
| - | char *dir; |
| - | |
| - | if (*block_nr == 0) |
| - | return 0; |
| - | if (blockcnt >= wd->outdir->num) { |
| - | e2fsck_read_bitmaps(wd->ctx); |
| - | blk = *block_nr; |
| - | ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk); |
| - | ext2fs_block_alloc_stats(fs, blk, -1); |
| - | *block_nr = 0; |
| - | wd->cleared++; |
| - | return BLOCK_CHANGED; |
| - | } |
| - | if (blockcnt < 0) |
| - | return 0; |
| - | |
| - | dir = wd->outdir->buf + (blockcnt * fs->blocksize); |
| - | wd->err = ext2fs_write_dir_block(fs, *block_nr, dir); |
| - | if (wd->err) |
| - | return BLOCK_ABORT; |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, |
| - | struct out_dir *outdir, |
| - | ext2_ino_t ino, int compress) |
| - | { |
| - | struct write_dir_struct wd; |
| - | errcode_t retval; |
| - | struct ext2_inode inode; |
| - | |
| - | retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | wd.outdir = outdir; |
| - | wd.err = 0; |
| - | wd.ctx = ctx; |
| - | wd.cleared = 0; |
| - | |
| - | retval = ext2fs_block_iterate2(fs, ino, 0, 0, |
| - | write_dir_block, &wd); |
| - | if (retval) |
| - | return retval; |
| - | if (wd.err) |
| - | return wd.err; |
| - | |
| - | e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); |
| - | if (compress) |
| - | inode.i_flags &= ~EXT2_INDEX_FL; |
| - | else |
| - | inode.i_flags |= EXT2_INDEX_FL; |
| - | inode.i_size = outdir->num * fs->blocksize; |
| - | inode.i_blocks -= (fs->blocksize / 512) * wd.cleared; |
| - | e2fsck_write_inode(ctx, ino, &inode, "rehash_dir"); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | struct ext2_inode inode; |
| - | char *dir_buf = NULL; |
| - | struct fill_dir_struct fd; |
| - | struct out_dir outdir; |
| - | |
| - | outdir.max = outdir.num = 0; |
| - | outdir.buf = 0; |
| - | outdir.hashes = 0; |
| - | e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); |
| - | |
| - | retval = ENOMEM; |
| - | fd.harray = 0; |
| - | dir_buf = xmalloc(inode.i_size); |
| - | |
| - | fd.max_array = inode.i_size / 32; |
| - | fd.num_array = 0; |
| - | fd.harray = xmalloc(fd.max_array * sizeof(struct hash_entry)); |
| - | |
| - | fd.ctx = ctx; |
| - | fd.buf = dir_buf; |
| - | fd.inode = &inode; |
| - | fd.err = 0; |
| - | fd.dir_size = 0; |
| - | fd.compress = 0; |
| - | if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) || |
| - | (inode.i_size / fs->blocksize) < 2) |
| - | fd.compress = 1; |
| - | fd.parent = 0; |
| - | |
| - | /* Read in the entire directory into memory */ |
| - | retval = ext2fs_block_iterate2(fs, ino, 0, 0, |
| - | fill_dir_block, &fd); |
| - | if (fd.err) { |
| - | retval = fd.err; |
| - | goto errout; |
| - | } |
| - | |
| - | /* Sort the list */ |
| - | resort: |
| - | if (fd.compress) |
| - | qsort(fd.harray+2, fd.num_array-2, |
| - | sizeof(struct hash_entry), name_cmp); |
| - | else |
| - | qsort(fd.harray, fd.num_array, |
| - | sizeof(struct hash_entry), hash_cmp); |
| - | |
| - | /* |
| - | * Look for duplicates |
| - | */ |
| - | if (duplicate_search_and_fix(ctx, fs, ino, &fd)) |
| - | goto resort; |
| - | |
| - | if (ctx->options & E2F_OPT_NO) { |
| - | retval = 0; |
| - | goto errout; |
| - | } |
| - | |
| - | /* |
| - | * Copy the directory entries. In a htree directory these |
| - | * will become the leaf nodes. |
| - | */ |
| - | retval = copy_dir_entries(fs, &fd, &outdir); |
| - | if (retval) |
| - | goto errout; |
| - | |
| - | free(dir_buf); dir_buf = 0; |
| - | |
| - | if (!fd.compress) { |
| - | /* Calculate the interior nodes */ |
| - | retval = calculate_tree(fs, &outdir, ino, fd.parent); |
| - | if (retval) |
| - | goto errout; |
| - | } |
| - | |
| - | retval = write_directory(ctx, fs, &outdir, ino, fd.compress); |
| - | |
| - | errout: |
| - | free(dir_buf); |
| - | free(fd.harray); |
| - | |
| - | free_out_dir(&outdir); |
| - | return retval; |
| - | } |
| - | |
| - | void e2fsck_rehash_directories(e2fsck_t ctx) |
| - | { |
| - | struct problem_context pctx; |
| - | struct dir_info *dir; |
| - | ext2_u32_iterate iter; |
| - | ext2_ino_t ino; |
| - | errcode_t retval; |
| - | int i, cur, max, all_dirs, dir_index, first = 1; |
| - | |
| - | all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS; |
| - | |
| - | if (!ctx->dirs_to_hash && !all_dirs) |
| - | return; |
| - | |
| - | e2fsck_get_lost_and_found(ctx, 0); |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX; |
| - | cur = 0; |
| - | if (all_dirs) { |
| - | i = 0; |
| - | max = e2fsck_get_num_dirinfo(ctx); |
| - | } else { |
| - | retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash, |
| - | &iter); |
| - | if (retval) { |
| - | pctx.errcode = retval; |
| - | fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx); |
| - | return; |
| - | } |
| - | max = ext2fs_u32_list_count(ctx->dirs_to_hash); |
| - | } |
| - | while (1) { |
| - | if (all_dirs) { |
| - | if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0) |
| - | break; |
| - | ino = dir->ino; |
| - | } else { |
| - | if (!ext2fs_u32_list_iterate(iter, &ino)) |
| - | break; |
| - | } |
| - | if (ino == ctx->lost_and_found) |
| - | continue; |
| - | pctx.dir = ino; |
| - | if (first) { |
| - | fix_problem(ctx, PR_3A_PASS_HEADER, &pctx); |
| - | first = 0; |
| - | } |
| - | pctx.errcode = e2fsck_rehash_dir(ctx, ino); |
| - | if (pctx.errcode) { |
| - | end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR); |
| - | fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx); |
| - | } |
| - | if (ctx->progress && !ctx->progress_fd) |
| - | e2fsck_simple_progress(ctx, "Rebuilding directory", |
| - | 100.0 * (float) (++cur) / (float) max, ino); |
| - | } |
| - | end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR); |
| - | if (!all_dirs) |
| - | ext2fs_u32_list_iterate_end(iter); |
| - | |
| - | ext2fs_u32_list_free(ctx->dirs_to_hash); |
| - | ctx->dirs_to_hash = 0; |
| - | } |
| - | |
| - | /* |
| - | * linux/fs/revoke.c |
| - | * |
| - | * Journal revoke routines for the generic filesystem journaling code; |
| - | * part of the ext2fs journaling system. |
| - | * |
| - | * Revoke is the mechanism used to prevent old log records for deleted |
| - | * metadata from being replayed on top of newer data using the same |
| - | * blocks. The revoke mechanism is used in two separate places: |
| - | * |
| - | * + Commit: during commit we write the entire list of the current |
| - | * transaction's revoked blocks to the journal |
| - | * |
| - | * + Recovery: during recovery we record the transaction ID of all |
| - | * revoked blocks. If there are multiple revoke records in the log |
| - | * for a single block, only the last one counts, and if there is a log |
| - | * entry for a block beyond the last revoke, then that log entry still |
| - | * gets replayed. |
| - | * |
| - | * We can get interactions between revokes and new log data within a |
| - | * single transaction: |
| - | * |
| - | * Block is revoked and then journaled: |
| - | * The desired end result is the journaling of the new block, so we |
| - | * cancel the revoke before the transaction commits. |
| - | * |
| - | * Block is journaled and then revoked: |
| - | * The revoke must take precedence over the write of the block, so we |
| - | * need either to cancel the journal entry or to write the revoke |
| - | * later in the log than the log block. In this case, we choose the |
| - | * latter: journaling a block cancels any revoke record for that block |
| - | * in the current transaction, so any revoke for that block in the |
| - | * transaction must have happened after the block was journaled and so |
| - | * the revoke must take precedence. |
| - | * |
| - | * Block is revoked and then written as data: |
| - | * The data write is allowed to succeed, but the revoke is _not_ |
| - | * cancelled. We still need to prevent old log records from |
| - | * overwriting the new data. We don't even need to clear the revoke |
| - | * bit here. |
| - | * |
| - | * Revoke information on buffers is a tri-state value: |
| - | * |
| - | * RevokeValid clear: no cached revoke status, need to look it up |
| - | * RevokeValid set, Revoked clear: |
| - | * buffer has not been revoked, and cancel_revoke |
| - | * need do nothing. |
| - | * RevokeValid set, Revoked set: |
| - | * buffer has been revoked. |
| - | */ |
| - | |
| - | static kmem_cache_t *revoke_record_cache; |
| - | static kmem_cache_t *revoke_table_cache; |
| - | |
| - | /* Each revoke record represents one single revoked block. During |
| - | journal replay, this involves recording the transaction ID of the |
| - | last transaction to revoke this block. */ |
| - | |
| - | struct jbd_revoke_record_s |
| - | { |
| - | struct list_head hash; |
| - | tid_t sequence; /* Used for recovery only */ |
| - | unsigned long blocknr; |
| - | }; |
| - | |
| - | |
| - | /* The revoke table is just a simple hash table of revoke records. */ |
| - | struct jbd_revoke_table_s |
| - | { |
| - | /* It is conceivable that we might want a larger hash table |
| - | * for recovery. Must be a power of two. */ |
| - | int hash_size; |
| - | int hash_shift; |
| - | struct list_head *hash_table; |
| - | }; |
| - | |
| - | |
| - | /* Utility functions to maintain the revoke table */ |
| - | |
| - | /* Borrowed from buffer.c: this is a tried and tested block hash function */ |
| - | static int hash(journal_t *journal, unsigned long block) |
| - | { |
| - | struct jbd_revoke_table_s *table = journal->j_revoke; |
| - | int hash_shift = table->hash_shift; |
| - | |
| - | return ((block << (hash_shift - 6)) ^ |
| - | (block >> 13) ^ |
| - | (block << (hash_shift - 12))) & (table->hash_size - 1); |
| - | } |
| - | |
| - | static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, |
| - | tid_t seq) |
| - | { |
| - | struct list_head *hash_list; |
| - | struct jbd_revoke_record_s *record; |
| - | |
| - | record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); |
| - | if (!record) |
| - | goto oom; |
| - | |
| - | record->sequence = seq; |
| - | record->blocknr = blocknr; |
| - | hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; |
| - | list_add(&record->hash, hash_list); |
| - | return 0; |
| - | |
| - | oom: |
| - | return -ENOMEM; |
| - | } |
| - | |
| - | /* Find a revoke record in the journal's hash table. */ |
| - | |
| - | static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, |
| - | unsigned long blocknr) |
| - | { |
| - | struct list_head *hash_list; |
| - | struct jbd_revoke_record_s *record; |
| - | |
| - | hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; |
| - | |
| - | record = (struct jbd_revoke_record_s *) hash_list->next; |
| - | while (&(record->hash) != hash_list) { |
| - | if (record->blocknr == blocknr) |
| - | return record; |
| - | record = (struct jbd_revoke_record_s *) record->hash.next; |
| - | } |
| - | return NULL; |
| - | } |
| - | |
| - | int journal_init_revoke_caches(void) |
| - | { |
| - | revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s)); |
| - | if (revoke_record_cache == 0) |
| - | return -ENOMEM; |
| - | |
| - | revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s)); |
| - | if (revoke_table_cache == 0) { |
| - | do_cache_destroy(revoke_record_cache); |
| - | revoke_record_cache = NULL; |
| - | return -ENOMEM; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | void journal_destroy_revoke_caches(void) |
| - | { |
| - | do_cache_destroy(revoke_record_cache); |
| - | revoke_record_cache = 0; |
| - | do_cache_destroy(revoke_table_cache); |
| - | revoke_table_cache = 0; |
| - | } |
| - | |
| - | /* Initialise the revoke table for a given journal to a given size. */ |
| - | |
| - | int journal_init_revoke(journal_t *journal, int hash_size) |
| - | { |
| - | int shift, tmp; |
| - | |
| - | journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); |
| - | if (!journal->j_revoke) |
| - | return -ENOMEM; |
| - | |
| - | /* Check that the hash_size is a power of two */ |
| - | journal->j_revoke->hash_size = hash_size; |
| - | |
| - | shift = 0; |
| - | tmp = hash_size; |
| - | while ((tmp >>= 1UL) != 0UL) |
| - | shift++; |
| - | journal->j_revoke->hash_shift = shift; |
| - | |
| - | journal->j_revoke->hash_table = xmalloc(hash_size * sizeof(struct list_head)); |
| - | |
| - | for (tmp = 0; tmp < hash_size; tmp++) |
| - | INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* Destoy a journal's revoke table. The table must already be empty! */ |
| - | |
| - | void journal_destroy_revoke(journal_t *journal) |
| - | { |
| - | struct jbd_revoke_table_s *table; |
| - | struct list_head *hash_list; |
| - | int i; |
| - | |
| - | table = journal->j_revoke; |
| - | if (!table) |
| - | return; |
| - | |
| - | for (i=0; i<table->hash_size; i++) { |
| - | hash_list = &table->hash_table[i]; |
| - | } |
| - | |
| - | free(table->hash_table); |
| - | free(table); |
| - | journal->j_revoke = NULL; |
| - | } |
| - | |
| - | /* |
| - | * Revoke support for recovery. |
| - | * |
| - | * Recovery needs to be able to: |
| - | * |
| - | * record all revoke records, including the tid of the latest instance |
| - | * of each revoke in the journal |
| - | * |
| - | * check whether a given block in a given transaction should be replayed |
| - | * (ie. has not been revoked by a revoke record in that or a subsequent |
| - | * transaction) |
| - | * |
| - | * empty the revoke table after recovery. |
| - | */ |
| - | |
| - | /* |
| - | * First, setting revoke records. We create a new revoke record for |
| - | * every block ever revoked in the log as we scan it for recovery, and |
| - | * we update the existing records if we find multiple revokes for a |
| - | * single block. |
| - | */ |
| - | |
| - | int journal_set_revoke(journal_t *journal, unsigned long blocknr, |
| - | tid_t sequence) |
| - | { |
| - | struct jbd_revoke_record_s *record; |
| - | |
| - | record = find_revoke_record(journal, blocknr); |
| - | if (record) { |
| - | /* If we have multiple occurences, only record the |
| - | * latest sequence number in the hashed record */ |
| - | if (tid_gt(sequence, record->sequence)) |
| - | record->sequence = sequence; |
| - | return 0; |
| - | } |
| - | return insert_revoke_hash(journal, blocknr, sequence); |
| - | } |
| - | |
| - | /* |
| - | * Test revoke records. For a given block referenced in the log, has |
| - | * that block been revoked? A revoke record with a given transaction |
| - | * sequence number revokes all blocks in that transaction and earlier |
| - | * ones, but later transactions still need replayed. |
| - | */ |
| - | |
| - | int journal_test_revoke(journal_t *journal, unsigned long blocknr, |
| - | tid_t sequence) |
| - | { |
| - | struct jbd_revoke_record_s *record; |
| - | |
| - | record = find_revoke_record(journal, blocknr); |
| - | if (!record) |
| - | return 0; |
| - | if (tid_gt(sequence, record->sequence)) |
| - | return 0; |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * Finally, once recovery is over, we need to clear the revoke table so |
| - | * that it can be reused by the running filesystem. |
| - | */ |
| - | |
| - | void journal_clear_revoke(journal_t *journal) |
| - | { |
| - | int i; |
| - | struct list_head *hash_list; |
| - | struct jbd_revoke_record_s *record; |
| - | struct jbd_revoke_table_s *revoke_var; |
| - | |
| - | revoke_var = journal->j_revoke; |
| - | |
| - | for (i = 0; i < revoke_var->hash_size; i++) { |
| - | hash_list = &revoke_var->hash_table[i]; |
| - | while (!list_empty(hash_list)) { |
| - | record = (struct jbd_revoke_record_s*) hash_list->next; |
| - | list_del(&record->hash); |
| - | free(record); |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * e2fsck.c - superblock checks |
| - | */ |
| - | |
| - | #define MIN_CHECK 1 |
| - | #define MAX_CHECK 2 |
| - | |
| - | static void check_super_value(e2fsck_t ctx, const char *descr, |
| - | unsigned long value, int flags, |
| - | unsigned long min_val, unsigned long max_val) |
| - | { |
| - | struct problem_context pctx; |
| - | |
| - | if (((flags & MIN_CHECK) && (value < min_val)) || |
| - | ((flags & MAX_CHECK) && (value > max_val))) { |
| - | clear_problem_context(&pctx); |
| - | pctx.num = value; |
| - | pctx.str = descr; |
| - | fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * This routine may get stubbed out in special compilations of the |
| - | * e2fsck code.. |
| - | */ |
| - | #ifndef EXT2_SPECIAL_DEVICE_SIZE |
| - | static errcode_t e2fsck_get_device_size(e2fsck_t ctx) |
| - | { |
| - | return (ext2fs_get_device_size(ctx->filesystem_name, |
| - | EXT2_BLOCK_SIZE(ctx->fs->super), |
| - | &ctx->num_blocks)); |
| - | } |
| - | #endif |
| - | |
| - | /* |
| - | * helper function to release an inode |
| - | */ |
| - | struct process_block_struct { |
| - | e2fsck_t ctx; |
| - | char *buf; |
| - | struct problem_context *pctx; |
| - | int truncating; |
| - | int truncate_offset; |
| - | e2_blkcnt_t truncate_block; |
| - | int truncated_blocks; |
| - | int abort; |
| - | errcode_t errcode; |
| - | }; |
| - | |
| - | static int release_inode_block(ext2_filsys fs, blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt, |
| - | blk_t ref_blk FSCK_ATTR((unused)), |
| - | int ref_offset FSCK_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct process_block_struct *pb; |
| - | e2fsck_t ctx; |
| - | struct problem_context *pctx; |
| - | blk_t blk = *block_nr; |
| - | int retval = 0; |
| - | |
| - | pb = (struct process_block_struct *) priv_data; |
| - | ctx = pb->ctx; |
| - | pctx = pb->pctx; |
| - | |
| - | pctx->blk = blk; |
| - | pctx->blkcount = blockcnt; |
| - | |
| - | if (HOLE_BLKADDR(blk)) |
| - | return 0; |
| - | |
| - | if ((blk < fs->super->s_first_data_block) || |
| - | (blk >= fs->super->s_blocks_count)) { |
| - | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx); |
| - | return_abort: |
| - | pb->abort = 1; |
| - | return BLOCK_ABORT; |
| - | } |
| - | |
| - | if (!ext2fs_test_block_bitmap(fs->block_map, blk)) { |
| - | fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx); |
| - | goto return_abort; |
| - | } |
| - | |
| - | /* |
| - | * If we are deleting an orphan, then we leave the fields alone. |
| - | * If we are truncating an orphan, then update the inode fields |
| - | * and clean up any partial block data. |
| - | */ |
| - | if (pb->truncating) { |
| - | /* |
| - | * We only remove indirect blocks if they are |
| - | * completely empty. |
| - | */ |
| - | if (blockcnt < 0) { |
| - | int i, limit; |
| - | blk_t *bp; |
| - | |
| - | pb->errcode = io_channel_read_blk(fs->io, blk, 1, |
| - | pb->buf); |
| - | if (pb->errcode) |
| - | goto return_abort; |
| - | |
| - | limit = fs->blocksize >> 2; |
| - | for (i = 0, bp = (blk_t *) pb->buf; |
| - | i < limit; i++, bp++) |
| - | if (*bp) |
| - | return 0; |
| - | } |
| - | /* |
| - | * We don't remove direct blocks until we've reached |
| - | * the truncation block. |
| - | */ |
| - | if (blockcnt >= 0 && blockcnt < pb->truncate_block) |
| - | return 0; |
| - | /* |
| - | * If part of the last block needs truncating, we do |
| - | * it here. |
| - | */ |
| - | if ((blockcnt == pb->truncate_block) && pb->truncate_offset) { |
| - | pb->errcode = io_channel_read_blk(fs->io, blk, 1, |
| - | pb->buf); |
| - | if (pb->errcode) |
| - | goto return_abort; |
| - | memset(pb->buf + pb->truncate_offset, 0, |
| - | fs->blocksize - pb->truncate_offset); |
| - | pb->errcode = io_channel_write_blk(fs->io, blk, 1, |
| - | pb->buf); |
| - | if (pb->errcode) |
| - | goto return_abort; |
| - | } |
| - | pb->truncated_blocks++; |
| - | *block_nr = 0; |
| - | retval |= BLOCK_CHANGED; |
| - | } |
| - | |
| - | ext2fs_block_alloc_stats(fs, blk, -1); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * This function releases an inode. Returns 1 if an inconsistency was |
| - | * found. If the inode has a link count, then it is being truncated and |
| - | * not deleted. |
| - | */ |
| - | static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, |
| - | struct ext2_inode *inode, char *block_buf, |
| - | struct problem_context *pctx) |
| - | { |
| - | struct process_block_struct pb; |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | __u32 count; |
| - | |
| - | if (!ext2fs_inode_has_valid_blocks(inode)) |
| - | return 0; |
| - | |
| - | pb.buf = block_buf + 3 * ctx->fs->blocksize; |
| - | pb.ctx = ctx; |
| - | pb.abort = 0; |
| - | pb.errcode = 0; |
| - | pb.pctx = pctx; |
| - | if (inode->i_links_count) { |
| - | pb.truncating = 1; |
| - | pb.truncate_block = (e2_blkcnt_t) |
| - | ((((long long)inode->i_size_high << 32) + |
| - | inode->i_size + fs->blocksize - 1) / |
| - | fs->blocksize); |
| - | pb.truncate_offset = inode->i_size % fs->blocksize; |
| - | } else { |
| - | pb.truncating = 0; |
| - | pb.truncate_block = 0; |
| - | pb.truncate_offset = 0; |
| - | } |
| - | pb.truncated_blocks = 0; |
| - | retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE, |
| - | block_buf, release_inode_block, &pb); |
| - | if (retval) { |
| - | bb_error_msg(_("while calling ext2fs_block_iterate for inode %d"), |
| - | ino); |
| - | return 1; |
| - | } |
| - | if (pb.abort) |
| - | return 1; |
| - | |
| - | /* Refresh the inode since ext2fs_block_iterate may have changed it */ |
| - | e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks"); |
| - | |
| - | if (pb.truncated_blocks) |
| - | inode->i_blocks -= pb.truncated_blocks * |
| - | (fs->blocksize / 512); |
| - | |
| - | if (inode->i_file_acl) { |
| - | retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl, |
| - | block_buf, -1, &count); |
| - | if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) { |
| - | retval = 0; |
| - | count = 1; |
| - | } |
| - | if (retval) { |
| - | bb_error_msg(_("while calling ext2fs_adjust_ea_refcount for inode %d"), |
| - | ino); |
| - | return 1; |
| - | } |
| - | if (count == 0) |
| - | ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1); |
| - | inode->i_file_acl = 0; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This function releases all of the orphan inodes. It returns 1 if |
| - | * it hit some error, and 0 on success. |
| - | */ |
| - | static int release_orphan_inodes(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | ext2_ino_t ino, next_ino; |
| - | struct ext2_inode inode; |
| - | struct problem_context pctx; |
| - | char *block_buf; |
| - | |
| - | if ((ino = fs->super->s_last_orphan) == 0) |
| - | return 0; |
| - | |
| - | /* |
| - | * Win or lose, we won't be using the head of the orphan inode |
| - | * list again. |
| - | */ |
| - | fs->super->s_last_orphan = 0; |
| - | ext2fs_mark_super_dirty(fs); |
| - | |
| - | /* |
| - | * If the filesystem contains errors, don't run the orphan |
| - | * list, since the orphan list can't be trusted; and we're |
| - | * going to be running a full e2fsck run anyway... |
| - | */ |
| - | if (fs->super->s_state & EXT2_ERROR_FS) |
| - | return 0; |
| - | |
| - | if ((ino < EXT2_FIRST_INODE(fs->super)) || |
| - | (ino > fs->super->s_inodes_count)) { |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx); |
| - | return 1; |
| - | } |
| - | |
| - | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, |
| - | "block iterate buffer"); |
| - | e2fsck_read_bitmaps(ctx); |
| - | |
| - | while (ino) { |
| - | e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes"); |
| - | clear_problem_context(&pctx); |
| - | pctx.ino = ino; |
| - | pctx.inode = &inode; |
| - | pctx.str = inode.i_links_count ? _("Truncating") : |
| - | _("Clearing"); |
| - | |
| - | fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx); |
| - | |
| - | next_ino = inode.i_dtime; |
| - | if (next_ino && |
| - | ((next_ino < EXT2_FIRST_INODE(fs->super)) || |
| - | (next_ino > fs->super->s_inodes_count))) { |
| - | pctx.ino = next_ino; |
| - | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx); |
| - | goto return_abort; |
| - | } |
| - | |
| - | if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx)) |
| - | goto return_abort; |
| - | |
| - | if (!inode.i_links_count) { |
| - | ext2fs_inode_alloc_stats2(fs, ino, -1, |
| - | LINUX_S_ISDIR(inode.i_mode)); |
| - | inode.i_dtime = time(NULL); |
| - | } else { |
| - | inode.i_dtime = 0; |
| - | } |
| - | e2fsck_write_inode(ctx, ino, &inode, "delete_file"); |
| - | ino = next_ino; |
| - | } |
| - | ext2fs_free_mem(&block_buf); |
| - | return 0; |
| - | return_abort: |
| - | ext2fs_free_mem(&block_buf); |
| - | return 1; |
| - | } |
| - | |
| - | /* |
| - | * Check the resize inode to make sure it is sane. We check both for |
| - | * the case where on-line resizing is not enabled (in which case the |
| - | * resize inode should be cleared) as well as the case where on-line |
| - | * resizing is enabled. |
| - | */ |
| - | static void check_resize_inode(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | struct ext2_inode inode; |
| - | struct problem_context pctx; |
| - | int i, j, gdt_off, ind_off; |
| - | blk_t blk, pblk, expect; |
| - | __u32 *dind_buf = NULL, *ind_buf; |
| - | errcode_t retval; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | /* |
| - | * If the resize inode feature isn't set, then |
| - | * s_reserved_gdt_blocks must be zero. |
| - | */ |
| - | if (!(fs->super->s_feature_compat & |
| - | EXT2_FEATURE_COMPAT_RESIZE_INO)) { |
| - | if (fs->super->s_reserved_gdt_blocks) { |
| - | pctx.num = fs->super->s_reserved_gdt_blocks; |
| - | if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS, |
| - | &pctx)) { |
| - | fs->super->s_reserved_gdt_blocks = 0; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* Read the resize inode */ |
| - | pctx.ino = EXT2_RESIZE_INO; |
| - | retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); |
| - | if (retval) { |
| - | if (fs->super->s_feature_compat & |
| - | EXT2_FEATURE_COMPAT_RESIZE_INO) |
| - | ctx->flags |= E2F_FLAG_RESIZE_INODE; |
| - | return; |
| - | } |
| - | |
| - | /* |
| - | * If the resize inode feature isn't set, check to make sure |
| - | * the resize inode is cleared; then we're done. |
| - | */ |
| - | if (!(fs->super->s_feature_compat & |
| - | EXT2_FEATURE_COMPAT_RESIZE_INO)) { |
| - | for (i=0; i < EXT2_N_BLOCKS; i++) { |
| - | if (inode.i_block[i]) |
| - | break; |
| - | } |
| - | if ((i < EXT2_N_BLOCKS) && |
| - | fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) { |
| - | memset(&inode, 0, sizeof(inode)); |
| - | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode, |
| - | "clear_resize"); |
| - | } |
| - | return; |
| - | } |
| - | |
| - | /* |
| - | * The resize inode feature is enabled; check to make sure the |
| - | * only block in use is the double indirect block |
| - | */ |
| - | blk = inode.i_block[EXT2_DIND_BLOCK]; |
| - | for (i=0; i < EXT2_N_BLOCKS; i++) { |
| - | if (i != EXT2_DIND_BLOCK && inode.i_block[i]) |
| - | break; |
| - | } |
| - | if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count || |
| - | !(inode.i_mode & LINUX_S_IFREG) || |
| - | (blk < fs->super->s_first_data_block || |
| - | blk >= fs->super->s_blocks_count)) { |
| - | resize_inode_invalid: |
| - | if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) { |
| - | memset(&inode, 0, sizeof(inode)); |
| - | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode, |
| - | "clear_resize"); |
| - | ctx->flags |= E2F_FLAG_RESIZE_INODE; |
| - | } |
| - | if (!(ctx->options & E2F_OPT_READONLY)) { |
| - | fs->super->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | goto cleanup; |
| - | } |
| - | dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2, |
| - | "resize dind buffer"); |
| - | ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize); |
| - | |
| - | retval = ext2fs_read_ind_block(fs, blk, dind_buf); |
| - | if (retval) |
| - | goto resize_inode_invalid; |
| - | |
| - | gdt_off = fs->desc_blocks; |
| - | pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks; |
| - | for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4; |
| - | i++, gdt_off++, pblk++) { |
| - | gdt_off %= fs->blocksize/4; |
| - | if (dind_buf[gdt_off] != pblk) |
| - | goto resize_inode_invalid; |
| - | retval = ext2fs_read_ind_block(fs, pblk, ind_buf); |
| - | if (retval) |
| - | goto resize_inode_invalid; |
| - | ind_off = 0; |
| - | for (j = 1; j < fs->group_desc_count; j++) { |
| - | if (!ext2fs_bg_has_super(fs, j)) |
| - | continue; |
| - | expect = pblk + (j * fs->super->s_blocks_per_group); |
| - | if (ind_buf[ind_off] != expect) |
| - | goto resize_inode_invalid; |
| - | ind_off++; |
| - | } |
| - | } |
| - | |
| - | cleanup: |
| - | ext2fs_free_mem(&dind_buf); |
| - | } |
| - | |
| - | static void check_super_block(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | blk_t first_block, last_block; |
| - | struct ext2_super_block *sb = fs->super; |
| - | struct ext2_group_desc *gd; |
| - | blk_t blocks_per_group = fs->super->s_blocks_per_group; |
| - | blk_t bpg_max; |
| - | int inodes_per_block; |
| - | int ipg_max; |
| - | int inode_size; |
| - | dgrp_t i; |
| - | blk_t should_be; |
| - | struct problem_context pctx; |
| - | __u32 free_blocks = 0, free_inodes = 0; |
| - | |
| - | inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super); |
| - | ipg_max = inodes_per_block * (blocks_per_group - 4); |
| - | if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb)) |
| - | ipg_max = EXT2_MAX_INODES_PER_GROUP(sb); |
| - | bpg_max = 8 * EXT2_BLOCK_SIZE(sb); |
| - | if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb)) |
| - | bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb); |
| - | |
| - | ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, |
| - | sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap"); |
| - | ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, |
| - | sizeof(int) * fs->group_desc_count, "invalid_block_bitmap"); |
| - | ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx, |
| - | sizeof(int) * fs->group_desc_count, "invalid_inode_table"); |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | /* |
| - | * Verify the super block constants... |
| - | */ |
| - | check_super_value(ctx, "inodes_count", sb->s_inodes_count, |
| - | MIN_CHECK, 1, 0); |
| - | check_super_value(ctx, "blocks_count", sb->s_blocks_count, |
| - | MIN_CHECK, 1, 0); |
| - | check_super_value(ctx, "first_data_block", sb->s_first_data_block, |
| - | MAX_CHECK, 0, sb->s_blocks_count); |
| - | check_super_value(ctx, "log_block_size", sb->s_log_block_size, |
| - | MIN_CHECK | MAX_CHECK, 0, |
| - | EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE); |
| - | check_super_value(ctx, "log_frag_size", sb->s_log_frag_size, |
| - | MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size); |
| - | check_super_value(ctx, "frags_per_group", sb->s_frags_per_group, |
| - | MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group, |
| - | bpg_max); |
| - | check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group, |
| - | MIN_CHECK | MAX_CHECK, 8, bpg_max); |
| - | check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group, |
| - | MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max); |
| - | check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count, |
| - | MAX_CHECK, 0, sb->s_blocks_count / 2); |
| - | check_super_value(ctx, "reserved_gdt_blocks", |
| - | sb->s_reserved_gdt_blocks, MAX_CHECK, 0, |
| - | fs->blocksize/4); |
| - | inode_size = EXT2_INODE_SIZE(sb); |
| - | check_super_value(ctx, "inode_size", |
| - | inode_size, MIN_CHECK | MAX_CHECK, |
| - | EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize); |
| - | if (inode_size & (inode_size - 1)) { |
| - | pctx.num = inode_size; |
| - | pctx.str = "inode_size"; |
| - | fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ |
| - | return; |
| - | } |
| - | |
| - | if (!ctx->num_blocks) { |
| - | pctx.errcode = e2fsck_get_device_size(ctx); |
| - | if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) { |
| - | fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) && |
| - | (ctx->num_blocks < sb->s_blocks_count)) { |
| - | pctx.blk = sb->s_blocks_count; |
| - | pctx.blk2 = ctx->num_blocks; |
| - | if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) { |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | } |
| - | |
| - | if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) { |
| - | pctx.blk = EXT2_BLOCK_SIZE(sb); |
| - | pctx.blk2 = EXT2_FRAG_SIZE(sb); |
| - | fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | should_be = sb->s_frags_per_group >> |
| - | (sb->s_log_block_size - sb->s_log_frag_size); |
| - | if (sb->s_blocks_per_group != should_be) { |
| - | pctx.blk = sb->s_blocks_per_group; |
| - | pctx.blk2 = should_be; |
| - | fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | should_be = (sb->s_log_block_size == 0) ? 1 : 0; |
| - | if (sb->s_first_data_block != should_be) { |
| - | pctx.blk = sb->s_first_data_block; |
| - | pctx.blk2 = should_be; |
| - | fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | |
| - | should_be = sb->s_inodes_per_group * fs->group_desc_count; |
| - | if (sb->s_inodes_count != should_be) { |
| - | pctx.ino = sb->s_inodes_count; |
| - | pctx.ino2 = should_be; |
| - | if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) { |
| - | sb->s_inodes_count = should_be; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Verify the group descriptors.... |
| - | */ |
| - | first_block = sb->s_first_data_block; |
| - | last_block = first_block + blocks_per_group; |
| - | |
| - | for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) { |
| - | pctx.group = i; |
| - | |
| - | if (i == fs->group_desc_count - 1) |
| - | last_block = sb->s_blocks_count; |
| - | if ((gd->bg_block_bitmap < first_block) || |
| - | (gd->bg_block_bitmap >= last_block)) { |
| - | pctx.blk = gd->bg_block_bitmap; |
| - | if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) |
| - | gd->bg_block_bitmap = 0; |
| - | } |
| - | if (gd->bg_block_bitmap == 0) { |
| - | ctx->invalid_block_bitmap_flag[i]++; |
| - | ctx->invalid_bitmaps++; |
| - | } |
| - | if ((gd->bg_inode_bitmap < first_block) || |
| - | (gd->bg_inode_bitmap >= last_block)) { |
| - | pctx.blk = gd->bg_inode_bitmap; |
| - | if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) |
| - | gd->bg_inode_bitmap = 0; |
| - | } |
| - | if (gd->bg_inode_bitmap == 0) { |
| - | ctx->invalid_inode_bitmap_flag[i]++; |
| - | ctx->invalid_bitmaps++; |
| - | } |
| - | if ((gd->bg_inode_table < first_block) || |
| - | ((gd->bg_inode_table + |
| - | fs->inode_blocks_per_group - 1) >= last_block)) { |
| - | pctx.blk = gd->bg_inode_table; |
| - | if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) |
| - | gd->bg_inode_table = 0; |
| - | } |
| - | if (gd->bg_inode_table == 0) { |
| - | ctx->invalid_inode_table_flag[i]++; |
| - | ctx->invalid_bitmaps++; |
| - | } |
| - | free_blocks += gd->bg_free_blocks_count; |
| - | free_inodes += gd->bg_free_inodes_count; |
| - | first_block += sb->s_blocks_per_group; |
| - | last_block += sb->s_blocks_per_group; |
| - | |
| - | if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) || |
| - | (gd->bg_free_inodes_count > sb->s_inodes_per_group) || |
| - | (gd->bg_used_dirs_count > sb->s_inodes_per_group)) |
| - | ext2fs_unmark_valid(fs); |
| - | } |
| - | |
| - | /* |
| - | * Update the global counts from the block group counts. This |
| - | * is needed for an experimental patch which eliminates |
| - | * locking the entire filesystem when allocating blocks or |
| - | * inodes; if the filesystem is not unmounted cleanly, the |
| - | * global counts may not be accurate. |
| - | */ |
| - | if ((free_blocks != sb->s_free_blocks_count) || |
| - | (free_inodes != sb->s_free_inodes_count)) { |
| - | if (ctx->options & E2F_OPT_READONLY) |
| - | ext2fs_unmark_valid(fs); |
| - | else { |
| - | sb->s_free_blocks_count = free_blocks; |
| - | sb->s_free_inodes_count = free_inodes; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | |
| - | if ((sb->s_free_blocks_count > sb->s_blocks_count) || |
| - | (sb->s_free_inodes_count > sb->s_inodes_count)) |
| - | ext2fs_unmark_valid(fs); |
| - | |
| - | |
| - | /* |
| - | * If we have invalid bitmaps, set the error state of the |
| - | * filesystem. |
| - | */ |
| - | if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) { |
| - | sb->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | /* |
| - | * If the UUID field isn't assigned, assign it. |
| - | */ |
| - | if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) { |
| - | if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) { |
| - | uuid_generate(sb->s_uuid); |
| - | ext2fs_mark_super_dirty(fs); |
| - | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
| - | } |
| - | } |
| - | |
| - | /* FIXME - HURD support? |
| - | * For the Hurd, check to see if the filetype option is set, |
| - | * since it doesn't support it. |
| - | */ |
| - | if (!(ctx->options & E2F_OPT_READONLY) && |
| - | fs->super->s_creator_os == EXT2_OS_HURD && |
| - | (fs->super->s_feature_incompat & |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE)) { |
| - | if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) { |
| - | fs->super->s_feature_incompat &= |
| - | ~EXT2_FEATURE_INCOMPAT_FILETYPE; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * If we have any of the compatibility flags set, we need to have a |
| - | * revision 1 filesystem. Most kernels will not check the flags on |
| - | * a rev 0 filesystem and we may have corruption issues because of |
| - | * the incompatible changes to the filesystem. |
| - | */ |
| - | if (!(ctx->options & E2F_OPT_READONLY) && |
| - | fs->super->s_rev_level == EXT2_GOOD_OLD_REV && |
| - | (fs->super->s_feature_compat || |
| - | fs->super->s_feature_ro_compat || |
| - | fs->super->s_feature_incompat) && |
| - | fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) { |
| - | ext2fs_update_dynamic_rev(fs); |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | check_resize_inode(ctx); |
| - | |
| - | /* |
| - | * Clean up any orphan inodes, if present. |
| - | */ |
| - | if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) { |
| - | fs->super->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | /* |
| - | * Move the ext3 journal file, if necessary. |
| - | */ |
| - | e2fsck_move_ext3_journal(ctx); |
| - | } |
| - | |
| - | /* |
| - | * swapfs.c --- byte-swap an ext2 filesystem |
| - | */ |
| - | |
| - | #ifdef ENABLE_SWAPFS |
| - | |
| - | struct swap_block_struct { |
| - | ext2_ino_t ino; |
| - | int isdir; |
| - | errcode_t errcode; |
| - | char *dir_buf; |
| - | struct ext2_inode *inode; |
| - | }; |
| - | |
| - | /* |
| - | * This is a helper function for block_iterate. We mark all of the |
| - | * indirect and direct blocks as changed, so that block_iterate will |
| - | * write them out. |
| - | */ |
| - | static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt, |
| - | void *priv_data) |
| - | { |
| - | errcode_t retval; |
| - | |
| - | struct swap_block_struct *sb = (struct swap_block_struct *) priv_data; |
| - | |
| - | if (sb->isdir && (blockcnt >= 0) && *block_nr) { |
| - | retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf); |
| - | if (retval) { |
| - | sb->errcode = retval; |
| - | return BLOCK_ABORT; |
| - | } |
| - | retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf); |
| - | if (retval) { |
| - | sb->errcode = retval; |
| - | return BLOCK_ABORT; |
| - | } |
| - | } |
| - | if (blockcnt >= 0) { |
| - | if (blockcnt < EXT2_NDIR_BLOCKS) |
| - | return 0; |
| - | return BLOCK_CHANGED; |
| - | } |
| - | if (blockcnt == BLOCK_COUNT_IND) { |
| - | if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK]) |
| - | return 0; |
| - | return BLOCK_CHANGED; |
| - | } |
| - | if (blockcnt == BLOCK_COUNT_DIND) { |
| - | if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK]) |
| - | return 0; |
| - | return BLOCK_CHANGED; |
| - | } |
| - | if (blockcnt == BLOCK_COUNT_TIND) { |
| - | if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK]) |
| - | return 0; |
| - | return BLOCK_CHANGED; |
| - | } |
| - | return BLOCK_CHANGED; |
| - | } |
| - | |
| - | /* |
| - | * This function is responsible for byte-swapping all of the indirect, |
| - | * block pointers. It is also responsible for byte-swapping directories. |
| - | */ |
| - | static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf, |
| - | struct ext2_inode *inode) |
| - | { |
| - | errcode_t retval; |
| - | struct swap_block_struct sb; |
| - | |
| - | sb.ino = ino; |
| - | sb.inode = inode; |
| - | sb.dir_buf = block_buf + ctx->fs->blocksize*3; |
| - | sb.errcode = 0; |
| - | sb.isdir = 0; |
| - | if (LINUX_S_ISDIR(inode->i_mode)) |
| - | sb.isdir = 1; |
| - | |
| - | retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf, |
| - | swap_block, &sb); |
| - | if (retval) { |
| - | bb_error_msg(_("while calling ext2fs_block_iterate")); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if (sb.errcode) { |
| - | bb_error_msg(_("while calling iterator function")); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | |
| - | static void swap_inodes(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | dgrp_t group; |
| - | unsigned int i; |
| - | ext2_ino_t ino = 1; |
| - | char *buf, *block_buf; |
| - | errcode_t retval; |
| - | struct ext2_inode * inode; |
| - | |
| - | e2fsck_use_inode_shortcuts(ctx, 1); |
| - | |
| - | retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group, |
| - | &buf); |
| - | if (retval) { |
| - | bb_error_msg(_("while allocating inode buffer")); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, |
| - | "block interate buffer"); |
| - | for (group = 0; group < fs->group_desc_count; group++) { |
| - | retval = io_channel_read_blk(fs->io, |
| - | fs->group_desc[group].bg_inode_table, |
| - | fs->inode_blocks_per_group, buf); |
| - | if (retval) { |
| - | bb_error_msg(_("while reading inode table (group %d)"), |
| - | group); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | inode = (struct ext2_inode *) buf; |
| - | for (i=0; i < fs->super->s_inodes_per_group; |
| - | i++, ino++, inode++) { |
| - | ctx->stashed_ino = ino; |
| - | ctx->stashed_inode = inode; |
| - | |
| - | if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ) |
| - | ext2fs_swap_inode(fs, inode, inode, 0); |
| - | |
| - | /* |
| - | * Skip deleted files. |
| - | */ |
| - | if (inode->i_links_count == 0) |
| - | continue; |
| - | |
| - | if (LINUX_S_ISDIR(inode->i_mode) || |
| - | ((inode->i_block[EXT2_IND_BLOCK] || |
| - | inode->i_block[EXT2_DIND_BLOCK] || |
| - | inode->i_block[EXT2_TIND_BLOCK]) && |
| - | ext2fs_inode_has_valid_blocks(inode))) |
| - | swap_inode_blocks(ctx, ino, block_buf, inode); |
| - | |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | |
| - | if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) |
| - | ext2fs_swap_inode(fs, inode, inode, 1); |
| - | } |
| - | retval = io_channel_write_blk(fs->io, |
| - | fs->group_desc[group].bg_inode_table, |
| - | fs->inode_blocks_per_group, buf); |
| - | if (retval) { |
| - | bb_error_msg(_("while writing inode table (group %d)"), |
| - | group); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | } |
| - | ext2fs_free_mem(&buf); |
| - | ext2fs_free_mem(&block_buf); |
| - | e2fsck_use_inode_shortcuts(ctx, 0); |
| - | ext2fs_flush_icache(fs); |
| - | } |
| - | |
| - | #if defined(__powerpc__) && BB_BIG_ENDIAN |
| - | /* |
| - | * On the PowerPC, the big-endian variant of the ext2 filesystem |
| - | * has its bitmaps stored as 32-bit words with bit 0 as the LSB |
| - | * of each word. Thus a bitmap with only bit 0 set would be, as |
| - | * a string of bytes, 00 00 00 01 00 ... |
| - | * To cope with this, we byte-reverse each word of a bitmap if |
| - | * we have a big-endian filesystem, that is, if we are *not* |
| - | * byte-swapping other word-sized numbers. |
| - | */ |
| - | #define EXT2_BIG_ENDIAN_BITMAPS |
| - | #endif |
| - | |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap) |
| - | { |
| - | __u32 *p = (__u32 *) bmap->bitmap; |
| - | int n, nbytes = (bmap->end - bmap->start + 7) / 8; |
| - | |
| - | for (n = nbytes / sizeof(__u32); n > 0; --n, ++p) |
| - | *p = ext2fs_swab32(*p); |
| - | } |
| - | #endif |
| - | |
| - | |
| - | #ifdef ENABLE_SWAPFS |
| - | static void swap_filesys(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | printf(_("Pass 0: Doing byte-swap of filesystem\n")); |
| - | |
| - | /* Byte swap */ |
| - | |
| - | if (fs->super->s_mnt_count) { |
| - | fprintf(stderr, _("%s: the filesystem must be freshly " |
| - | "checked using fsck\n" |
| - | "and not mounted before trying to " |
| - | "byte-swap it.\n"), ctx->device_name); |
| - | ctx->flags |= E2F_FLAG_ABORT; |
| - | return; |
| - | } |
| - | if (fs->flags & EXT2_FLAG_SWAP_BYTES) { |
| - | fs->flags &= ~(EXT2_FLAG_SWAP_BYTES| |
| - | EXT2_FLAG_SWAP_BYTES_WRITE); |
| - | fs->flags |= EXT2_FLAG_SWAP_BYTES_READ; |
| - | } else { |
| - | fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ; |
| - | fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE; |
| - | } |
| - | swap_inodes(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | return; |
| - | if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) |
| - | fs->flags |= EXT2_FLAG_SWAP_BYTES; |
| - | fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ| |
| - | EXT2_FLAG_SWAP_BYTES_WRITE); |
| - | |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | e2fsck_read_bitmaps(ctx); |
| - | ext2fs_swap_bitmap(fs->inode_map); |
| - | ext2fs_swap_bitmap(fs->block_map); |
| - | fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY; |
| - | #endif |
| - | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
| - | ext2fs_flush(fs); |
| - | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; |
| - | } |
| - | #endif /* ENABLE_SWAPFS */ |
| - | |
| - | #endif |
| - | |
| - | /* |
| - | * util.c --- miscellaneous utilities |
| - | */ |
| - | |
| - | |
| - | void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, |
| - | const char *description) |
| - | { |
| - | return xzalloc(size); |
| - | } |
| - | |
| - | static char *string_copy(const char *str, int len) |
| - | { |
| - | char *ret; |
| - | |
| - | if (!str) |
| - | return NULL; |
| - | if (!len) |
| - | len = strlen(str); |
| - | ret = xmalloc(len+1); |
| - | strncpy(ret, str, len); |
| - | ret[len] = 0; |
| - | return ret; |
| - | } |
| - | |
| - | #ifndef HAVE_CONIO_H |
| - | static int read_a_char(void) |
| - | { |
| - | char c; |
| - | int r; |
| - | int fail = 0; |
| - | |
| - | while (1) { |
| - | if (e2fsck_global_ctx && |
| - | (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) { |
| - | return 3; |
| - | } |
| - | r = read(0, &c, 1); |
| - | if (r == 1) |
| - | return c; |
| - | if (fail++ > 100) |
| - | break; |
| - | } |
| - | return EOF; |
| - | } |
| - | #endif |
| - | |
| - | static int ask_yn(const char * string, int def) |
| - | { |
| - | int c; |
| - | const char *defstr; |
| - | static const char short_yes[] = "yY"; |
| - | static const char short_no[] = "nN"; |
| - | |
| - | #ifdef HAVE_TERMIOS_H |
| - | struct termios termios, tmp; |
| - | |
| - | tcgetattr (0, &termios); |
| - | tmp = termios; |
| - | tmp.c_lflag &= ~(ICANON | ECHO); |
| - | tmp.c_cc[VMIN] = 1; |
| - | tmp.c_cc[VTIME] = 0; |
| - | tcsetattr_stdin_TCSANOW(&tmp); |
| - | #endif |
| - | |
| - | if (def == 1) |
| - | defstr = "<y>"; |
| - | else if (def == 0) |
| - | defstr = "<n>"; |
| - | else |
| - | defstr = " (y/n)"; |
| - | printf("%s%s? ", string, defstr); |
| - | while (1) { |
| - | fflush (stdout); |
| - | if ((c = read_a_char()) == EOF) |
| - | break; |
| - | if (c == 3) { |
| - | #ifdef HAVE_TERMIOS_H |
| - | tcsetattr_stdin_TCSANOW(&termios); |
| - | #endif |
| - | if (e2fsck_global_ctx && |
| - | e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) { |
| - | puts("\n"); |
| - | longjmp(e2fsck_global_ctx->abort_loc, 1); |
| - | } |
| - | puts(_("cancelled!\n")); |
| - | return 0; |
| - | } |
| - | if (strchr(short_yes, (char) c)) { |
| - | def = 1; |
| - | break; |
| - | } |
| - | else if (strchr(short_no, (char) c)) { |
| - | def = 0; |
| - | break; |
| - | } |
| - | else if ((c == ' ' || c == '\n') && (def != -1)) |
| - | break; |
| - | } |
| - | if (def) |
| - | puts("yes\n"); |
| - | else |
| - | puts ("no\n"); |
| - | #ifdef HAVE_TERMIOS_H |
| - | tcsetattr_stdin_TCSANOW(&termios); |
| - | #endif |
| - | return def; |
| - | } |
| - | |
| - | int ask (e2fsck_t ctx, const char * string, int def) |
| - | { |
| - | if (ctx->options & E2F_OPT_NO) { |
| - | printf(_("%s? no\n\n"), string); |
| - | return 0; |
| - | } |
| - | if (ctx->options & E2F_OPT_YES) { |
| - | printf(_("%s? yes\n\n"), string); |
| - | return 1; |
| - | } |
| - | if (ctx->options & E2F_OPT_PREEN) { |
| - | printf("%s? %s\n\n", string, def ? _("yes") : _("no")); |
| - | return def; |
| - | } |
| - | return ask_yn(string, def); |
| - | } |
| - | |
| - | void e2fsck_read_bitmaps(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | |
| - | if (ctx->invalid_bitmaps) { |
| - | bb_error_msg(_("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | |
| - | ehandler_operation(_("reading inode and block bitmaps")); |
| - | retval = ext2fs_read_bitmaps(fs); |
| - | ehandler_operation(0); |
| - | if (retval) { |
| - | bb_error_msg(_("while retrying to read bitmaps for %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | |
| - | static void e2fsck_write_bitmaps(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | errcode_t retval; |
| - | |
| - | if (ext2fs_test_bb_dirty(fs)) { |
| - | ehandler_operation(_("writing block bitmaps")); |
| - | retval = ext2fs_write_block_bitmap(fs); |
| - | ehandler_operation(0); |
| - | if (retval) { |
| - | bb_error_msg(_("while retrying to write block bitmaps for %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | |
| - | if (ext2fs_test_ib_dirty(fs)) { |
| - | ehandler_operation(_("writing inode bitmaps")); |
| - | retval = ext2fs_write_inode_bitmap(fs); |
| - | ehandler_operation(0); |
| - | if (retval) { |
| - | bb_error_msg(_("while retrying to write inode bitmaps for %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | } |
| - | |
| - | void preenhalt(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | return; |
| - | fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; " |
| - | "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"), |
| - | ctx->device_name); |
| - | if (fs != NULL) { |
| - | fs->super->s_state |= EXT2_ERROR_FS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | ext2fs_close(fs); |
| - | } |
| - | exit(EXIT_UNCORRECTED); |
| - | } |
| - | |
| - | void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino, |
| - | struct ext2_inode * inode, const char *proc) |
| - | { |
| - | int retval; |
| - | |
| - | retval = ext2fs_read_inode(ctx->fs, ino, inode); |
| - | if (retval) { |
| - | bb_error_msg(_("while reading inode %ld in %s"), ino, proc); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | |
| - | extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino, |
| - | struct ext2_inode * inode, int bufsize, |
| - | const char *proc) |
| - | { |
| - | int retval; |
| - | |
| - | retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize); |
| - | if (retval) { |
| - | bb_error_msg(_("while writing inode %ld in %s"), ino, proc); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | |
| - | extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino, |
| - | struct ext2_inode * inode, const char *proc) |
| - | { |
| - | int retval; |
| - | |
| - | retval = ext2fs_write_inode(ctx->fs, ino, inode); |
| - | if (retval) { |
| - | bb_error_msg(_("while writing inode %ld in %s"), ino, proc); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | |
| - | blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name, |
| - | io_manager manager) |
| - | { |
| - | struct ext2_super_block *sb; |
| - | io_channel io = NULL; |
| - | void *buf = NULL; |
| - | int blocksize; |
| - | blk_t superblock, ret_sb = 8193; |
| - | |
| - | if (fs && fs->super) { |
| - | ret_sb = (fs->super->s_blocks_per_group + |
| - | fs->super->s_first_data_block); |
| - | if (ctx) { |
| - | ctx->superblock = ret_sb; |
| - | ctx->blocksize = fs->blocksize; |
| - | } |
| - | return ret_sb; |
| - | } |
| - | |
| - | if (ctx) { |
| - | if (ctx->blocksize) { |
| - | ret_sb = ctx->blocksize * 8; |
| - | if (ctx->blocksize == 1024) |
| - | ret_sb++; |
| - | ctx->superblock = ret_sb; |
| - | return ret_sb; |
| - | } |
| - | ctx->superblock = ret_sb; |
| - | ctx->blocksize = 1024; |
| - | } |
| - | |
| - | if (!name || !manager) |
| - | goto cleanup; |
| - | |
| - | if (manager->open(name, 0, &io) != 0) |
| - | goto cleanup; |
| - | |
| - | if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf)) |
| - | goto cleanup; |
| - | sb = (struct ext2_super_block *) buf; |
| - | |
| - | for (blocksize = EXT2_MIN_BLOCK_SIZE; |
| - | blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { |
| - | superblock = blocksize*8; |
| - | if (blocksize == 1024) |
| - | superblock++; |
| - | io_channel_set_blksize(io, blocksize); |
| - | if (io_channel_read_blk(io, superblock, |
| - | -SUPERBLOCK_SIZE, buf)) |
| - | continue; |
| - | #if BB_BIG_ENDIAN |
| - | if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) |
| - | ext2fs_swap_super(sb); |
| - | #endif |
| - | if (sb->s_magic == EXT2_SUPER_MAGIC) { |
| - | ret_sb = superblock; |
| - | if (ctx) { |
| - | ctx->superblock = superblock; |
| - | ctx->blocksize = blocksize; |
| - | } |
| - | break; |
| - | } |
| - | } |
| - | |
| - | cleanup: |
| - | if (io) |
| - | io_channel_close(io); |
| - | ext2fs_free_mem(&buf); |
| - | return ret_sb; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * This function runs through the e2fsck passes and calls them all, |
| - | * returning restart, abort, or cancel as necessary... |
| - | */ |
| - | typedef void (*pass_t)(e2fsck_t ctx); |
| - | |
| - | static const pass_t e2fsck_passes[] = { |
| - | e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4, |
| - | e2fsck_pass5, 0 }; |
| - | |
| - | #define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART) |
| - | |
| - | static int e2fsck_run(e2fsck_t ctx) |
| - | { |
| - | int i; |
| - | pass_t e2fsck_pass; |
| - | |
| - | if (setjmp(ctx->abort_loc)) { |
| - | ctx->flags &= ~E2F_FLAG_SETJMP_OK; |
| - | return (ctx->flags & E2F_FLAG_RUN_RETURN); |
| - | } |
| - | ctx->flags |= E2F_FLAG_SETJMP_OK; |
| - | |
| - | for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) { |
| - | if (ctx->flags & E2F_FLAG_RUN_RETURN) |
| - | break; |
| - | e2fsck_pass(ctx); |
| - | if (ctx->progress) |
| - | (void) (ctx->progress)(ctx, 0, 0, 0); |
| - | } |
| - | ctx->flags &= ~E2F_FLAG_SETJMP_OK; |
| - | |
| - | if (ctx->flags & E2F_FLAG_RUN_RETURN) |
| - | return (ctx->flags & E2F_FLAG_RUN_RETURN); |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * unix.c - The unix-specific code for e2fsck |
| - | */ |
| - | |
| - | |
| - | /* Command line options */ |
| - | static int swapfs; |
| - | #ifdef ENABLE_SWAPFS |
| - | static int normalize_swapfs; |
| - | #endif |
| - | static int cflag; /* check disk */ |
| - | static int show_version_only; |
| - | static int verbose; |
| - | |
| - | #define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural) |
| - | |
| - | static void show_stats(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | int inodes, inodes_used, blocks, blocks_used; |
| - | int dir_links; |
| - | int num_files, num_links; |
| - | int frag_percent; |
| - | |
| - | dir_links = 2 * ctx->fs_directory_count - 1; |
| - | num_files = ctx->fs_total_count - dir_links; |
| - | num_links = ctx->fs_links_count - dir_links; |
| - | inodes = fs->super->s_inodes_count; |
| - | inodes_used = (fs->super->s_inodes_count - |
| - | fs->super->s_free_inodes_count); |
| - | blocks = fs->super->s_blocks_count; |
| - | blocks_used = (fs->super->s_blocks_count - |
| - | fs->super->s_free_blocks_count); |
| - | |
| - | frag_percent = (10000 * ctx->fs_fragmented) / inodes_used; |
| - | frag_percent = (frag_percent + 5) / 10; |
| - | |
| - | if (!verbose) { |
| - | printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", |
| - | ctx->device_name, inodes_used, inodes, |
| - | frag_percent / 10, frag_percent % 10, |
| - | blocks_used, blocks); |
| - | return; |
| - | } |
| - | printf("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used), |
| - | 100 * inodes_used / inodes); |
| - | printf("%8d non-contiguous inode%s (%0d.%d%%)\n", |
| - | P_E2("", "s", ctx->fs_fragmented), |
| - | frag_percent / 10, frag_percent % 10); |
| - | printf(_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"), |
| - | ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count); |
| - | printf("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used), |
| - | (int) ((long long) 100 * blocks_used / blocks)); |
| - | printf("%8d large file%s\n", P_E2("", "s", ctx->large_files)); |
| - | printf("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count)); |
| - | printf("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count)); |
| - | printf("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count)); |
| - | printf("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count)); |
| - | printf("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count)); |
| - | printf("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links)); |
| - | printf("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count)); |
| - | printf(" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count)); |
| - | printf("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count)); |
| - | printf("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links)); |
| - | } |
| - | |
| - | static void check_mount(e2fsck_t ctx) |
| - | { |
| - | errcode_t retval; |
| - | int cont; |
| - | |
| - | retval = ext2fs_check_if_mounted(ctx->filesystem_name, |
| - | &ctx->mount_flags); |
| - | if (retval) { |
| - | bb_error_msg(_("while determining whether %s is mounted"), |
| - | ctx->filesystem_name); |
| - | return; |
| - | } |
| - | |
| - | /* |
| - | * If the filesystem isn't mounted, or it's the root filesystem |
| - | * and it's mounted read-only, then everything's fine. |
| - | */ |
| - | if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) || |
| - | ((ctx->mount_flags & EXT2_MF_ISROOT) && |
| - | (ctx->mount_flags & EXT2_MF_READONLY))) |
| - | return; |
| - | |
| - | if (ctx->options & E2F_OPT_READONLY) { |
| - | printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name); |
| - | return; |
| - | } |
| - | |
| - | printf(_("%s is mounted. "), ctx->filesystem_name); |
| - | if (!ctx->interactive) |
| - | bb_error_msg_and_die(_("can't continue, aborting")); |
| - | printf(_("\n\n\007\007\007\007WARNING!!! " |
| - | "Running e2fsck on a mounted filesystem may cause\n" |
| - | "SEVERE filesystem damage.\007\007\007\n\n")); |
| - | cont = ask_yn(_("Do you really want to continue"), -1); |
| - | if (!cont) { |
| - | printf(_("check aborted.\n")); |
| - | exit(0); |
| - | } |
| - | } |
| - | |
| - | static int is_on_batt(void) |
| - | { |
| - | FILE *f; |
| - | DIR *d; |
| - | char tmp[80], tmp2[80], fname[80]; |
| - | unsigned int acflag; |
| - | struct dirent* de; |
| - | |
| - | f = fopen_for_read("/proc/apm"); |
| - | if (f) { |
| - | if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4) |
| - | acflag = 1; |
| - | fclose(f); |
| - | return (acflag != 1); |
| - | } |
| - | d = opendir("/proc/acpi/ac_adapter"); |
| - | if (d) { |
| - | while ((de=readdir(d)) != NULL) { |
| - | if (!strncmp(".", de->d_name, 1)) |
| - | continue; |
| - | snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state", |
| - | de->d_name); |
| - | f = fopen_for_read(fname); |
| - | if (!f) |
| - | continue; |
| - | if (fscanf(f, "%s %s", tmp2, tmp) != 2) |
| - | tmp[0] = 0; |
| - | fclose(f); |
| - | if (strncmp(tmp, "off-line", 8) == 0) { |
| - | closedir(d); |
| - | return 1; |
| - | } |
| - | } |
| - | closedir(d); |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * This routine checks to see if a filesystem can be skipped; if so, |
| - | * it will exit with EXIT_OK. Under some conditions it will print a |
| - | * message explaining why a check is being forced. |
| - | */ |
| - | static void check_if_skip(e2fsck_t ctx) |
| - | { |
| - | ext2_filsys fs = ctx->fs; |
| - | const char *reason = NULL; |
| - | unsigned int reason_arg = 0; |
| - | long next_check; |
| - | int batt = is_on_batt(); |
| - | time_t now = time(NULL); |
| - | |
| - | if ((ctx->options & E2F_OPT_FORCE) || cflag || swapfs) |
| - | return; |
| - | |
| - | if ((fs->super->s_state & EXT2_ERROR_FS) || |
| - | !ext2fs_test_valid(fs)) |
| - | reason = _(" contains a file system with errors"); |
| - | else if ((fs->super->s_state & EXT2_VALID_FS) == 0) |
| - | reason = _(" was not cleanly unmounted"); |
| - | else if ((fs->super->s_max_mnt_count > 0) && |
| - | (fs->super->s_mnt_count >= |
| - | (unsigned) fs->super->s_max_mnt_count)) { |
| - | reason = _(" has been mounted %u times without being checked"); |
| - | reason_arg = fs->super->s_mnt_count; |
| - | if (batt && (fs->super->s_mnt_count < |
| - | (unsigned) fs->super->s_max_mnt_count*2)) |
| - | reason = 0; |
| - | } else if (fs->super->s_checkinterval && |
| - | ((now - fs->super->s_lastcheck) >= |
| - | fs->super->s_checkinterval)) { |
| - | reason = _(" has gone %u days without being checked"); |
| - | reason_arg = (now - fs->super->s_lastcheck)/(3600*24); |
| - | if (batt && ((now - fs->super->s_lastcheck) < |
| - | fs->super->s_checkinterval*2)) |
| - | reason = 0; |
| - | } |
| - | if (reason) { |
| - | fputs(ctx->device_name, stdout); |
| - | printf(reason, reason_arg); |
| - | fputs(_(", check forced.\n"), stdout); |
| - | return; |
| - | } |
| - | printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name, |
| - | fs->super->s_inodes_count - fs->super->s_free_inodes_count, |
| - | fs->super->s_inodes_count, |
| - | fs->super->s_blocks_count - fs->super->s_free_blocks_count, |
| - | fs->super->s_blocks_count); |
| - | next_check = 100000; |
| - | if (fs->super->s_max_mnt_count > 0) { |
| - | next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count; |
| - | if (next_check <= 0) |
| - | next_check = 1; |
| - | } |
| - | if (fs->super->s_checkinterval && |
| - | ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval)) |
| - | next_check = 1; |
| - | if (next_check <= 5) { |
| - | if (next_check == 1) |
| - | fputs(_(" (check after next mount)"), stdout); |
| - | else |
| - | printf(_(" (check in %ld mounts)"), next_check); |
| - | } |
| - | bb_putchar('\n'); |
| - | ext2fs_close(fs); |
| - | ctx->fs = NULL; |
| - | e2fsck_free_context(ctx); |
| - | exit(EXIT_OK); |
| - | } |
| - | |
| - | /* |
| - | * For completion notice |
| - | */ |
| - | struct percent_tbl { |
| - | int max_pass; |
| - | int table[32]; |
| - | }; |
| - | static const struct percent_tbl e2fsck_tbl = { |
| - | 5, { 0, 70, 90, 92, 95, 100 } |
| - | }; |
| - | |
| - | static char bar[128], spaces[128]; |
| - | |
| - | static float calc_percent(const struct percent_tbl *tbl, int pass, int curr, |
| - | int max) |
| - | { |
| - | float percent; |
| - | |
| - | if (pass <= 0) |
| - | return 0.0; |
| - | if (pass > tbl->max_pass || max == 0) |
| - | return 100.0; |
| - | percent = ((float) curr) / ((float) max); |
| - | return ((percent * (tbl->table[pass] - tbl->table[pass-1])) |
| - | + tbl->table[pass-1]); |
| - | } |
| - | |
| - | void e2fsck_clear_progbar(e2fsck_t ctx) |
| - | { |
| - | if (!(ctx->flags & E2F_FLAG_PROG_BAR)) |
| - | return; |
| - | |
| - | printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80), |
| - | ctx->stop_meta); |
| - | fflush(stdout); |
| - | ctx->flags &= ~E2F_FLAG_PROG_BAR; |
| - | } |
| - | |
| - | int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent, |
| - | unsigned int dpynum) |
| - | { |
| - | static const char spinner[] = "\\|/-"; |
| - | int i; |
| - | unsigned int tick; |
| - | struct timeval tv; |
| - | int dpywidth; |
| - | int fixed_percent; |
| - | |
| - | if (ctx->flags & E2F_FLAG_PROG_SUPPRESS) |
| - | return 0; |
| - | |
| - | /* |
| - | * Calculate the new progress position. If the |
| - | * percentage hasn't changed, then we skip out right |
| - | * away. |
| - | */ |
| - | fixed_percent = (int) ((10 * percent) + 0.5); |
| - | if (ctx->progress_last_percent == fixed_percent) |
| - | return 0; |
| - | ctx->progress_last_percent = fixed_percent; |
| - | |
| - | /* |
| - | * If we've already updated the spinner once within |
| - | * the last 1/8th of a second, no point doing it |
| - | * again. |
| - | */ |
| - | gettimeofday(&tv, NULL); |
| - | tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8)); |
| - | if ((tick == ctx->progress_last_time) && |
| - | (fixed_percent != 0) && (fixed_percent != 1000)) |
| - | return 0; |
| - | ctx->progress_last_time = tick; |
| - | |
| - | /* |
| - | * Advance the spinner, and note that the progress bar |
| - | * will be on the screen |
| - | */ |
| - | ctx->progress_pos = (ctx->progress_pos+1) & 3; |
| - | ctx->flags |= E2F_FLAG_PROG_BAR; |
| - | |
| - | dpywidth = 66 - strlen(label); |
| - | dpywidth = 8 * (dpywidth / 8); |
| - | if (dpynum) |
| - | dpywidth -= 8; |
| - | |
| - | i = ((percent * dpywidth) + 50) / 100; |
| - | printf("%s%s: |%s%s", ctx->start_meta, label, |
| - | bar + (sizeof(bar) - (i+1)), |
| - | spaces + (sizeof(spaces) - (dpywidth - i + 1))); |
| - | if (fixed_percent == 1000) |
| - | bb_putchar('|'); |
| - | else |
| - | bb_putchar(spinner[ctx->progress_pos & 3]); |
| - | printf(" %4.1f%% ", percent); |
| - | if (dpynum) |
| - | printf("%u\r", dpynum); |
| - | else |
| - | fputs(" \r", stdout); |
| - | fputs(ctx->stop_meta, stdout); |
| - | |
| - | if (fixed_percent == 1000) |
| - | e2fsck_clear_progbar(ctx); |
| - | fflush(stdout); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | static int e2fsck_update_progress(e2fsck_t ctx, int pass, |
| - | unsigned long cur, unsigned long max) |
| - | { |
| - | char buf[80]; |
| - | float percent; |
| - | |
| - | if (pass == 0) |
| - | return 0; |
| - | |
| - | if (ctx->progress_fd) { |
| - | sprintf(buf, "%d %lu %lu\n", pass, cur, max); |
| - | xwrite_str(ctx->progress_fd, buf); |
| - | } else { |
| - | percent = calc_percent(&e2fsck_tbl, pass, cur, max); |
| - | e2fsck_simple_progress(ctx, ctx->device_name, |
| - | percent, 0); |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static void reserve_stdio_fds(void) |
| - | { |
| - | int fd; |
| - | |
| - | while (1) { |
| - | fd = open(bb_dev_null, O_RDWR); |
| - | if (fd > 2) |
| - | break; |
| - | if (fd < 0) { |
| - | fprintf(stderr, _("ERROR: Cannot open " |
| - | "/dev/null (%s)\n"), |
| - | strerror(errno)); |
| - | break; |
| - | } |
| - | } |
| - | close(fd); |
| - | } |
| - | |
| - | static void signal_progress_on(int sig FSCK_ATTR((unused))) |
| - | { |
| - | e2fsck_t ctx = e2fsck_global_ctx; |
| - | |
| - | if (!ctx) |
| - | return; |
| - | |
| - | ctx->progress = e2fsck_update_progress; |
| - | ctx->progress_fd = 0; |
| - | } |
| - | |
| - | static void signal_progress_off(int sig FSCK_ATTR((unused))) |
| - | { |
| - | e2fsck_t ctx = e2fsck_global_ctx; |
| - | |
| - | if (!ctx) |
| - | return; |
| - | |
| - | e2fsck_clear_progbar(ctx); |
| - | ctx->progress = 0; |
| - | } |
| - | |
| - | static void signal_cancel(int sig FSCK_ATTR((unused))) |
| - | { |
| - | e2fsck_t ctx = e2fsck_global_ctx; |
| - | |
| - | if (!ctx) |
| - | exit(FSCK_CANCELED); |
| - | |
| - | ctx->flags |= E2F_FLAG_CANCEL; |
| - | } |
| - | |
| - | static void parse_extended_opts(e2fsck_t ctx, const char *opts) |
| - | { |
| - | char *buf, *token, *next, *p, *arg; |
| - | int ea_ver; |
| - | int extended_usage = 0; |
| - | |
| - | buf = string_copy(opts, 0); |
| - | for (token = buf; token && *token; token = next) { |
| - | p = strchr(token, ','); |
| - | next = 0; |
| - | if (p) { |
| - | *p = 0; |
| - | next = p+1; |
| - | } |
| - | arg = strchr(token, '='); |
| - | if (arg) { |
| - | *arg = 0; |
| - | arg++; |
| - | } |
| - | if (strcmp(token, "ea_ver") == 0) { |
| - | if (!arg) { |
| - | extended_usage++; |
| - | continue; |
| - | } |
| - | ea_ver = strtoul(arg, &p, 0); |
| - | if (*p || |
| - | ((ea_ver != 1) && (ea_ver != 2))) { |
| - | fprintf(stderr, |
| - | _("Invalid EA version.\n")); |
| - | extended_usage++; |
| - | continue; |
| - | } |
| - | ctx->ext_attr_ver = ea_ver; |
| - | } else { |
| - | fprintf(stderr, _("Unknown extended option: %s\n"), |
| - | token); |
| - | extended_usage++; |
| - | } |
| - | } |
| - | if (extended_usage) { |
| - | bb_error_msg_and_die( |
| - | "Extended options are separated by commas, " |
| - | "and may take an argument which\n" |
| - | "is set off by an equals ('=') sign. " |
| - | "Valid extended options are:\n" |
| - | "\tea_ver=<ea_version (1 or 2)>\n\n"); |
| - | } |
| - | } |
| - | |
| - | |
| - | static errcode_t PRS(int argc, char **argv, e2fsck_t *ret_ctx) |
| - | { |
| - | int flush = 0; |
| - | int c, fd; |
| - | e2fsck_t ctx; |
| - | errcode_t retval; |
| - | struct sigaction sa; |
| - | char *extended_opts = NULL; |
| - | |
| - | retval = e2fsck_allocate_context(&ctx); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | *ret_ctx = ctx; |
| - | |
| - | setvbuf(stdout, NULL, _IONBF, BUFSIZ); |
| - | setvbuf(stderr, NULL, _IONBF, BUFSIZ); |
| - | if (isatty(0) && isatty(1)) { |
| - | ctx->interactive = 1; |
| - | } else { |
| - | ctx->start_meta[0] = '\001'; |
| - | ctx->stop_meta[0] = '\002'; |
| - | } |
| - | memset(bar, '=', sizeof(bar)-1); |
| - | memset(spaces, ' ', sizeof(spaces)-1); |
| - | blkid_get_cache(&ctx->blkid, NULL); |
| - | |
| - | if (argc && *argv) |
| - | ctx->program_name = *argv; |
| - | else |
| - | ctx->program_name = "e2fsck"; |
| - | while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF) |
| - | switch (c) { |
| - | case 'C': |
| - | ctx->progress = e2fsck_update_progress; |
| - | ctx->progress_fd = atoi(optarg); |
| - | if (!ctx->progress_fd) |
| - | break; |
| - | /* Validate the file descriptor to avoid disasters */ |
| - | fd = dup(ctx->progress_fd); |
| - | if (fd < 0) { |
| - | fprintf(stderr, |
| - | _("Error validating file descriptor %d: %s\n"), |
| - | ctx->progress_fd, |
| - | error_message(errno)); |
| - | bb_error_msg_and_die(_("Invalid completion information file descriptor")); |
| - | } else |
| - | close(fd); |
| - | break; |
| - | case 'D': |
| - | ctx->options |= E2F_OPT_COMPRESS_DIRS; |
| - | break; |
| - | case 'E': |
| - | extended_opts = optarg; |
| - | break; |
| - | case 'p': |
| - | case 'a': |
| - | if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) { |
| - | conflict_opt: |
| - | bb_error_msg_and_die(_("only one the options -p/-a, -n or -y may be specified")); |
| - | } |
| - | ctx->options |= E2F_OPT_PREEN; |
| - | break; |
| - | case 'n': |
| - | if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN)) |
| - | goto conflict_opt; |
| - | ctx->options |= E2F_OPT_NO; |
| - | break; |
| - | case 'y': |
| - | if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO)) |
| - | goto conflict_opt; |
| - | ctx->options |= E2F_OPT_YES; |
| - | break; |
| - | case 't': |
| - | /* FIXME - This needs to go away in a future path - will change binary */ |
| - | fprintf(stderr, _("The -t option is not " |
| - | "supported on this version of e2fsck.\n")); |
| - | break; |
| - | case 'c': |
| - | if (cflag++) |
| - | ctx->options |= E2F_OPT_WRITECHECK; |
| - | ctx->options |= E2F_OPT_CHECKBLOCKS; |
| - | break; |
| - | case 'r': |
| - | /* What we do by default, anyway! */ |
| - | break; |
| - | case 'b': |
| - | ctx->use_superblock = atoi(optarg); |
| - | ctx->flags |= E2F_FLAG_SB_SPECIFIED; |
| - | break; |
| - | case 'B': |
| - | ctx->blocksize = atoi(optarg); |
| - | break; |
| - | case 'I': |
| - | ctx->inode_buffer_blocks = atoi(optarg); |
| - | break; |
| - | case 'j': |
| - | ctx->journal_name = string_copy(optarg, 0); |
| - | break; |
| - | case 'P': |
| - | ctx->process_inode_size = atoi(optarg); |
| - | break; |
| - | case 'd': |
| - | ctx->options |= E2F_OPT_DEBUG; |
| - | break; |
| - | case 'f': |
| - | ctx->options |= E2F_OPT_FORCE; |
| - | break; |
| - | case 'F': |
| - | flush = 1; |
| - | break; |
| - | case 'v': |
| - | verbose = 1; |
| - | break; |
| - | case 'V': |
| - | show_version_only = 1; |
| - | break; |
| - | case 'N': |
| - | ctx->device_name = optarg; |
| - | break; |
| - | #ifdef ENABLE_SWAPFS |
| - | case 's': |
| - | normalize_swapfs = 1; |
| - | case 'S': |
| - | swapfs = 1; |
| - | break; |
| - | #else |
| - | case 's': |
| - | case 'S': |
| - | fprintf(stderr, _("Byte-swapping filesystems " |
| - | "not compiled in this version " |
| - | "of e2fsck\n")); |
| - | exit(1); |
| - | #endif |
| - | default: |
| - | bb_show_usage(); |
| - | } |
| - | if (show_version_only) |
| - | return 0; |
| - | if (optind != argc - 1) |
| - | bb_show_usage(); |
| - | if ((ctx->options & E2F_OPT_NO) && |
| - | !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS)) |
| - | ctx->options |= E2F_OPT_READONLY; |
| - | ctx->io_options = strchr(argv[optind], '?'); |
| - | if (ctx->io_options) |
| - | *ctx->io_options++ = 0; |
| - | ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); |
| - | if (!ctx->filesystem_name) { |
| - | bb_error_msg(_("Unable to resolve '%s'"), argv[optind]); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | if (extended_opts) |
| - | parse_extended_opts(ctx, extended_opts); |
| - | |
| - | if (flush) { |
| - | fd = open(ctx->filesystem_name, O_RDONLY, 0); |
| - | if (fd < 0) { |
| - | bb_error_msg(_("while opening %s for flushing"), |
| - | ctx->filesystem_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | if ((retval = ext2fs_sync_device(fd, 1))) { |
| - | bb_error_msg(_("while trying to flush %s"), |
| - | ctx->filesystem_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | close(fd); |
| - | } |
| - | #ifdef ENABLE_SWAPFS |
| - | if (swapfs && cflag) { |
| - | fprintf(stderr, _("Incompatible options not " |
| - | "allowed when byte-swapping.\n")); |
| - | exit(EXIT_USAGE); |
| - | } |
| - | #endif |
| - | /* |
| - | * Set up signal action |
| - | */ |
| - | memset(&sa, 0, sizeof(struct sigaction)); |
| - | sa.sa_handler = signal_cancel; |
| - | sigaction(SIGINT, &sa, 0); |
| - | sigaction(SIGTERM, &sa, 0); |
| - | #ifdef SA_RESTART |
| - | sa.sa_flags = SA_RESTART; |
| - | #endif |
| - | e2fsck_global_ctx = ctx; |
| - | sa.sa_handler = signal_progress_on; |
| - | sigaction(SIGUSR1, &sa, 0); |
| - | sa.sa_handler = signal_progress_off; |
| - | sigaction(SIGUSR2, &sa, 0); |
| - | |
| - | /* Update our PATH to include /sbin if we need to run badblocks */ |
| - | if (cflag) |
| - | e2fs_set_sbin_path(); |
| - | return 0; |
| - | } |
| - | |
| - | static const char my_ver_string[] = E2FSPROGS_VERSION; |
| - | static const char my_ver_date[] = E2FSPROGS_DATE; |
| - | |
| - | int e2fsck_main (int argc, char **argv); |
| - | int e2fsck_main (int argc, char **argv) |
| - | { |
| - | errcode_t retval; |
| - | int exit_value = EXIT_OK; |
| - | ext2_filsys fs = 0; |
| - | io_manager io_ptr; |
| - | struct ext2_super_block *sb; |
| - | const char *lib_ver_date; |
| - | int my_ver, lib_ver; |
| - | e2fsck_t ctx; |
| - | struct problem_context pctx; |
| - | int flags, run_result; |
| - | |
| - | clear_problem_context(&pctx); |
| - | |
| - | my_ver = ext2fs_parse_version_string(my_ver_string); |
| - | lib_ver = ext2fs_get_library_version(0, &lib_ver_date); |
| - | if (my_ver > lib_ver) { |
| - | fprintf( stderr, _("Error: ext2fs library version " |
| - | "out of date!\n")); |
| - | show_version_only++; |
| - | } |
| - | |
| - | retval = PRS(argc, argv, &ctx); |
| - | if (retval) { |
| - | bb_error_msg(_("while trying to initialize program")); |
| - | exit(EXIT_ERROR); |
| - | } |
| - | reserve_stdio_fds(); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) |
| - | fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string, |
| - | my_ver_date); |
| - | |
| - | if (show_version_only) { |
| - | fprintf(stderr, _("\tUsing %s, %s\n"), |
| - | error_message(EXT2_ET_BASE), lib_ver_date); |
| - | exit(EXIT_OK); |
| - | } |
| - | |
| - | check_mount(ctx); |
| - | |
| - | if (!(ctx->options & E2F_OPT_PREEN) && |
| - | !(ctx->options & E2F_OPT_NO) && |
| - | !(ctx->options & E2F_OPT_YES)) { |
| - | if (!ctx->interactive) |
| - | bb_error_msg_and_die(_("need terminal for interactive repairs")); |
| - | } |
| - | ctx->superblock = ctx->use_superblock; |
| - | restart: |
| - | #ifdef CONFIG_TESTIO_DEBUG |
| - | io_ptr = test_io_manager; |
| - | test_io_backing_manager = unix_io_manager; |
| - | #else |
| - | io_ptr = unix_io_manager; |
| - | #endif |
| - | flags = 0; |
| - | if ((ctx->options & E2F_OPT_READONLY) == 0) |
| - | flags |= EXT2_FLAG_RW; |
| - | |
| - | if (ctx->superblock && ctx->blocksize) { |
| - | retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, |
| - | flags, ctx->superblock, ctx->blocksize, |
| - | io_ptr, &fs); |
| - | } else if (ctx->superblock) { |
| - | int blocksize; |
| - | for (blocksize = EXT2_MIN_BLOCK_SIZE; |
| - | blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { |
| - | retval = ext2fs_open2(ctx->filesystem_name, |
| - | ctx->io_options, flags, |
| - | ctx->superblock, blocksize, |
| - | io_ptr, &fs); |
| - | if (!retval) |
| - | break; |
| - | } |
| - | } else |
| - | retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, |
| - | flags, 0, 0, io_ptr, &fs); |
| - | if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && |
| - | !(ctx->flags & E2F_FLAG_SB_SPECIFIED) && |
| - | ((retval == EXT2_ET_BAD_MAGIC) || |
| - | ((retval == 0) && ext2fs_check_desc(fs)))) { |
| - | if (!fs || (fs->group_desc_count > 1)) { |
| - | printf(_("%s trying backup blocks...\n"), |
| - | retval ? _("Couldn't find ext2 superblock,") : |
| - | _("Group descriptors look bad...")); |
| - | get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr); |
| - | if (fs) |
| - | ext2fs_close(fs); |
| - | goto restart; |
| - | } |
| - | } |
| - | if (retval) { |
| - | bb_error_msg(_("while trying to open %s"), |
| - | ctx->filesystem_name); |
| - | if (retval == EXT2_ET_REV_TOO_HIGH) { |
| - | printf(_("The filesystem revision is apparently " |
| - | "too high for this version of e2fsck.\n" |
| - | "(Or the filesystem superblock " |
| - | "is corrupt)\n\n")); |
| - | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); |
| - | } else if (retval == EXT2_ET_SHORT_READ) |
| - | printf(_("Could this be a zero-length partition?\n")); |
| - | else if ((retval == EPERM) || (retval == EACCES)) |
| - | printf(_("You must have %s access to the " |
| - | "filesystem or be root\n"), |
| - | (ctx->options & E2F_OPT_READONLY) ? |
| - | "r/o" : "r/w"); |
| - | else if (retval == ENXIO) |
| - | printf(_("Possibly non-existent or swap device?\n")); |
| - | #ifdef EROFS |
| - | else if (retval == EROFS) |
| - | printf(_("Disk write-protected; use the -n option " |
| - | "to do a read-only\n" |
| - | "check of the device.\n")); |
| - | #endif |
| - | else |
| - | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | ctx->fs = fs; |
| - | fs->priv_data = ctx; |
| - | sb = fs->super; |
| - | if (sb->s_rev_level > E2FSCK_CURRENT_REV) { |
| - | bb_error_msg(_("while trying to open %s"), |
| - | ctx->filesystem_name); |
| - | get_newer: |
| - | bb_error_msg_and_die(_("Get a newer version of e2fsck!")); |
| - | } |
| - | |
| - | /* |
| - | * Set the device name, which is used whenever we print error |
| - | * or informational messages to the user. |
| - | */ |
| - | if (ctx->device_name == 0 && |
| - | (sb->s_volume_name[0] != 0)) { |
| - | ctx->device_name = string_copy(sb->s_volume_name, |
| - | sizeof(sb->s_volume_name)); |
| - | } |
| - | if (ctx->device_name == 0) |
| - | ctx->device_name = ctx->filesystem_name; |
| - | |
| - | /* |
| - | * Make sure the ext3 superblock fields are consistent. |
| - | */ |
| - | retval = e2fsck_check_ext3_journal(ctx); |
| - | if (retval) { |
| - | bb_error_msg(_("while checking ext3 journal for %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | |
| - | /* |
| - | * Check to see if we need to do ext3-style recovery. If so, |
| - | * do it, and then restart the fsck. |
| - | */ |
| - | if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { |
| - | if (ctx->options & E2F_OPT_READONLY) { |
| - | printf(_("Warning: skipping journal recovery " |
| - | "because doing a read-only filesystem " |
| - | "check.\n")); |
| - | io_channel_flush(ctx->fs->io); |
| - | } else { |
| - | if (ctx->flags & E2F_FLAG_RESTARTED) { |
| - | /* |
| - | * Whoops, we attempted to run the |
| - | * journal twice. This should never |
| - | * happen, unless the hardware or |
| - | * device driver is being bogus. |
| - | */ |
| - | bb_error_msg(_("can't set superblock flags on %s"), ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | retval = e2fsck_run_ext3_journal(ctx); |
| - | if (retval) { |
| - | bb_error_msg(_("while recovering ext3 journal of %s"), |
| - | ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | ext2fs_close(ctx->fs); |
| - | ctx->fs = 0; |
| - | ctx->flags |= E2F_FLAG_RESTARTED; |
| - | goto restart; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Check for compatibility with the feature sets. We need to |
| - | * be more stringent than ext2fs_open(). |
| - | */ |
| - | if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) || |
| - | (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) { |
| - | bb_error_msg("(%s)", ctx->device_name); |
| - | goto get_newer; |
| - | } |
| - | if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { |
| - | bb_error_msg("(%s)", ctx->device_name); |
| - | goto get_newer; |
| - | } |
| - | #ifdef ENABLE_COMPRESSION |
| - | /* FIXME - do we support this at all? */ |
| - | if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) |
| - | bb_error_msg(_("warning: compression support is experimental")); |
| - | #endif |
| - | #ifndef ENABLE_HTREE |
| - | if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { |
| - | bb_error_msg(_("E2fsck not compiled with HTREE support,\n\t" |
| - | "but filesystem %s has HTREE directories."), |
| - | ctx->device_name); |
| - | goto get_newer; |
| - | } |
| - | #endif |
| - | |
| - | /* |
| - | * If the user specified a specific superblock, presumably the |
| - | * master superblock has been trashed. So we mark the |
| - | * superblock as dirty, so it can be written out. |
| - | */ |
| - | if (ctx->superblock && |
| - | !(ctx->options & E2F_OPT_READONLY)) |
| - | ext2fs_mark_super_dirty(fs); |
| - | |
| - | /* |
| - | * We only update the master superblock because (a) paranoia; |
| - | * we don't want to corrupt the backup superblocks, and (b) we |
| - | * don't need to update the mount count and last checked |
| - | * fields in the backup superblock (the kernel doesn't |
| - | * update the backup superblocks anyway). |
| - | */ |
| - | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; |
| - | |
| - | ehandler_init(fs->io); |
| - | |
| - | if (ctx->superblock) |
| - | set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); |
| - | ext2fs_mark_valid(fs); |
| - | check_super_block(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | bb_error_msg_and_die(0); |
| - | check_if_skip(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | bb_error_msg_and_die(0); |
| - | #ifdef ENABLE_SWAPFS |
| - | |
| - | #ifdef WORDS_BIGENDIAN |
| - | #define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES |
| - | #else |
| - | #define NATIVE_FLAG 0 |
| - | #endif |
| - | |
| - | |
| - | if (normalize_swapfs) { |
| - | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) { |
| - | fprintf(stderr, _("%s: Filesystem byte order " |
| - | "already normalized.\n"), ctx->device_name); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | } |
| - | if (swapfs) { |
| - | swap_filesys(ctx); |
| - | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | #endif |
| - | |
| - | /* |
| - | * Mark the system as valid, 'til proven otherwise |
| - | */ |
| - | ext2fs_mark_valid(fs); |
| - | |
| - | retval = ext2fs_read_bb_inode(fs, &fs->badblocks); |
| - | if (retval) { |
| - | bb_error_msg(_("while reading bad blocks inode")); |
| - | preenhalt(ctx); |
| - | printf(_("This doesn't bode well," |
| - | " but we'll try to go on...\n")); |
| - | } |
| - | |
| - | run_result = e2fsck_run(ctx); |
| - | e2fsck_clear_progbar(ctx); |
| - | if (run_result == E2F_FLAG_RESTART) { |
| - | printf(_("Restarting e2fsck from the beginning...\n")); |
| - | retval = e2fsck_reset_context(ctx); |
| - | if (retval) { |
| - | bb_error_msg(_("while resetting context")); |
| - | bb_error_msg_and_die(0); |
| - | } |
| - | ext2fs_close(fs); |
| - | goto restart; |
| - | } |
| - | if (run_result & E2F_FLAG_CANCEL) { |
| - | printf(_("%s: e2fsck canceled.\n"), ctx->device_name ? |
| - | ctx->device_name : ctx->filesystem_name); |
| - | exit_value |= FSCK_CANCELED; |
| - | } |
| - | if (run_result & E2F_FLAG_ABORT) |
| - | bb_error_msg_and_die(_("aborted")); |
| - | |
| - | /* Cleanup */ |
| - | if (ext2fs_test_changed(fs)) { |
| - | exit_value |= EXIT_NONDESTRUCT; |
| - | if (!(ctx->options & E2F_OPT_PREEN)) |
| - | printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"), |
| - | ctx->device_name); |
| - | if (ctx->mount_flags & EXT2_MF_ISROOT) { |
| - | printf(_("%s: ***** REBOOT LINUX *****\n"), |
| - | ctx->device_name); |
| - | exit_value |= EXIT_DESTRUCT; |
| - | } |
| - | } |
| - | if (!ext2fs_test_valid(fs)) { |
| - | printf(_("\n%s: ********** WARNING: Filesystem still has " |
| - | "errors **********\n\n"), ctx->device_name); |
| - | exit_value |= EXIT_UNCORRECTED; |
| - | exit_value &= ~EXIT_NONDESTRUCT; |
| - | } |
| - | if (exit_value & FSCK_CANCELED) |
| - | exit_value &= ~EXIT_NONDESTRUCT; |
| - | else { |
| - | show_stats(ctx); |
| - | if (!(ctx->options & E2F_OPT_READONLY)) { |
| - | if (ext2fs_test_valid(fs)) { |
| - | if (!(sb->s_state & EXT2_VALID_FS)) |
| - | exit_value |= EXIT_NONDESTRUCT; |
| - | sb->s_state = EXT2_VALID_FS; |
| - | } else |
| - | sb->s_state &= ~EXT2_VALID_FS; |
| - | sb->s_mnt_count = 0; |
| - | sb->s_lastcheck = time(NULL); |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | } |
| - | |
| - | e2fsck_write_bitmaps(ctx); |
| - | |
| - | ext2fs_close(fs); |
| - | ctx->fs = NULL; |
| - | free(ctx->filesystem_name); |
| - | free(ctx->journal_name); |
| - | e2fsck_free_context(ctx); |
| - | |
| - | return exit_value; |
| - | } |
| @@ -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 <[email protected]> |
| - | # |
| - | # 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 <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * 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 <[email protected]> |
| - | * 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 <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * 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 <[email protected]> |
| - | * Laboratoire MASI, Institut Blaise Pascal |
| - | * Universite Pierre et Marie Curie (Paris VI) |
| - | * |
| - | * Copyright (C) 1995, 1996, 1997 Theodore Ts'o <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * 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 <[email protected]> |
| - | * 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 <[email protected]> |
| - | * 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 <[email protected]> |
| - | # |
| - | # 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 <[email protected]> 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, <[email protected]> |
| - | */ |
| - | |
| - | /* 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 ([email protected]) |
| - | * 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, <[email protected]> |
| - | * |
| - | * 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 <[email protected]> |
| - | * |
| - | * 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 |
| @@ -1,204 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * namei.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 |
| - | |
| - | /* #define NAMEI_DEBUG */ |
| - | |
| - | #include "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | |
| - | static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, |
| - | const char *pathname, size_t pathlen, int follow, |
| - | int link_count, char *buf, ext2_ino_t *res_inode); |
| - | |
| - | static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, |
| - | ext2_ino_t inode, int link_count, |
| - | char *buf, ext2_ino_t *res_inode) |
| - | { |
| - | char *pathname; |
| - | char *buffer = NULL; |
| - | errcode_t retval; |
| - | struct ext2_inode ei; |
| - | |
| - | #ifdef NAMEI_DEBUG |
| - | printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n", |
| - | root, dir, inode, link_count); |
| - | |
| - | #endif |
| - | retval = ext2fs_read_inode (fs, inode, &ei); |
| - | if (retval) return retval; |
| - | if (!LINUX_S_ISLNK (ei.i_mode)) { |
| - | *res_inode = inode; |
| - | return 0; |
| - | } |
| - | if (link_count++ > 5) { |
| - | return EXT2_ET_SYMLINK_LOOP; |
| - | } |
| - | if (ext2fs_inode_data_blocks(fs, &ei)) { |
| - | retval = ext2fs_get_mem(fs->blocksize, &buffer); |
| - | if (retval) |
| - | return retval; |
| - | retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer); |
| - | if (retval) { |
| - | ext2fs_free_mem(&buffer); |
| - | return retval; |
| - | } |
| - | pathname = buffer; |
| - | } else |
| - | pathname = (char *)&(ei.i_block[0]); |
| - | retval = open_namei(fs, root, dir, pathname, ei.i_size, 1, |
| - | link_count, buf, res_inode); |
| - | ext2fs_free_mem(&buffer); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * This routine interprets a pathname in the context of the current |
| - | * directory and the root directory, and returns the inode of the |
| - | * containing directory, and a pointer to the filename of the file |
| - | * (pointing into the pathname) and the length of the filename. |
| - | */ |
| - | static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, |
| - | const char *pathname, int pathlen, |
| - | int link_count, char *buf, |
| - | const char **name, int *namelen, |
| - | ext2_ino_t *res_inode) |
| - | { |
| - | char c; |
| - | const char *thisname; |
| - | int len; |
| - | ext2_ino_t inode; |
| - | errcode_t retval; |
| - | |
| - | if ((c = *pathname) == '/') { |
| - | dir = root; |
| - | pathname++; |
| - | pathlen--; |
| - | } |
| - | while (1) { |
| - | thisname = pathname; |
| - | for (len=0; --pathlen >= 0;len++) { |
| - | c = *(pathname++); |
| - | if (c == '/') |
| - | break; |
| - | } |
| - | if (pathlen < 0) |
| - | break; |
| - | retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode); |
| - | if (retval) return retval; |
| - | retval = follow_link (fs, root, dir, inode, |
| - | link_count, buf, &dir); |
| - | if (retval) return retval; |
| - | } |
| - | *name = thisname; |
| - | *namelen = len; |
| - | *res_inode = dir; |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, |
| - | const char *pathname, size_t pathlen, int follow, |
| - | int link_count, char *buf, ext2_ino_t *res_inode) |
| - | { |
| - | const char *basename; |
| - | int namelen; |
| - | ext2_ino_t dir, inode; |
| - | errcode_t retval; |
| - | |
| - | #ifdef NAMEI_DEBUG |
| - | printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n", |
| - | root, base, pathlen, pathname, link_count); |
| - | #endif |
| - | retval = dir_namei(fs, root, base, pathname, pathlen, |
| - | link_count, buf, &basename, &namelen, &dir); |
| - | if (retval) return retval; |
| - | if (!namelen) { /* special case: '/usr/' etc */ |
| - | *res_inode=dir; |
| - | return 0; |
| - | } |
| - | retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode); |
| - | if (retval) |
| - | return retval; |
| - | if (follow) { |
| - | retval = follow_link(fs, root, dir, inode, link_count, |
| - | buf, &inode); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | #ifdef NAMEI_DEBUG |
| - | printf("open_namei: (link_count=%d) returns %lu\n", |
| - | link_count, inode); |
| - | #endif |
| - | *res_inode = inode; |
| - | return 0; |
| - | } |
| - | |
| - | errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, |
| - | const char *name, ext2_ino_t *inode) |
| - | { |
| - | 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; |
| - | |
| - | retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0, |
| - | buf, inode); |
| - | |
| - | ext2fs_free_mem(&buf); |
| - | return retval; |
| - | } |
| - | |
| - | errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, |
| - | const char *name, ext2_ino_t *inode) |
| - | { |
| - | 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; |
| - | |
| - | retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0, |
| - | buf, inode); |
| - | |
| - | ext2fs_free_mem(&buf); |
| - | return retval; |
| - | } |
| - | |
| - | 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) |
| - | { |
| - | 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; |
| - | |
| - | retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode); |
| - | |
| - | ext2fs_free_mem(&buf); |
| - | return retval; |
| - | } |
| @@ -1,72 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * newdir.c --- create a new directory block |
| - | * |
| - | * 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 "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | |
| - | #ifndef EXT2_FT_DIR |
| - | #define EXT2_FT_DIR 2 |
| - | #endif |
| - | |
| - | /* |
| - | * Create new directory block |
| - | */ |
| - | errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, |
| - | ext2_ino_t parent_ino, char **block) |
| - | { |
| - | struct ext2_dir_entry *dir = NULL; |
| - | errcode_t retval; |
| - | char *buf; |
| - | int rec_len; |
| - | int filetype = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | retval = ext2fs_get_mem(fs->blocksize, &buf); |
| - | if (retval) |
| - | return retval; |
| - | memset(buf, 0, fs->blocksize); |
| - | dir = (struct ext2_dir_entry *) buf; |
| - | dir->rec_len = fs->blocksize; |
| - | |
| - | if (dir_ino) { |
| - | if (fs->super->s_feature_incompat & |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE) |
| - | filetype = EXT2_FT_DIR << 8; |
| - | /* |
| - | * Set up entry for '.' |
| - | */ |
| - | dir->inode = dir_ino; |
| - | dir->name_len = 1 | filetype; |
| - | dir->name[0] = '.'; |
| - | rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1); |
| - | dir->rec_len = EXT2_DIR_REC_LEN(1); |
| - | |
| - | /* |
| - | * Set up entry for '..' |
| - | */ |
| - | dir = (struct ext2_dir_entry *) (buf + dir->rec_len); |
| - | dir->rec_len = rec_len; |
| - | dir->inode = parent_ino; |
| - | dir->name_len = 2 | filetype; |
| - | dir->name[0] = '.'; |
| - | dir->name[1] = '.'; |
| - | } |
| - | *block = buf; |
| - | return 0; |
| - | } |
| @@ -1,330 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * openfs.c --- open 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" |
| - | #include "e2image.h" |
| - | |
| - | blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i) |
| - | { |
| - | int bg; |
| - | int has_super = 0; |
| - | int ret_blk; |
| - | |
| - | if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) || |
| - | (i < fs->super->s_first_meta_bg)) |
| - | return (group_block + i + 1); |
| - | |
| - | bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i; |
| - | if (ext2fs_bg_has_super(fs, bg)) |
| - | has_super = 1; |
| - | ret_blk = (fs->super->s_first_data_block + has_super + |
| - | (bg * fs->super->s_blocks_per_group)); |
| - | /* |
| - | * If group_block is not the normal value, we're trying to use |
| - | * the backup group descriptors and superblock --- so use the |
| - | * alternate location of the second block group in the |
| - | * metablock group. Ideally we should be testing each bg |
| - | * descriptor block individually for correctness, but we don't |
| - | * have the infrastructure in place to do that. |
| - | */ |
| - | if (group_block != fs->super->s_first_data_block && |
| - | ((ret_blk + fs->super->s_blocks_per_group) < |
| - | fs->super->s_blocks_count)) |
| - | ret_blk += fs->super->s_blocks_per_group; |
| - | return ret_blk; |
| - | } |
| - | |
| - | errcode_t ext2fs_open(const char *name, int flags, int superblock, |
| - | unsigned int block_size, io_manager manager, |
| - | ext2_filsys *ret_fs) |
| - | { |
| - | return ext2fs_open2(name, 0, flags, superblock, block_size, |
| - | manager, ret_fs); |
| - | } |
| - | |
| - | /* |
| - | * Note: if superblock is non-zero, block-size must also be non-zero. |
| - | * Superblock and block_size can be zero to use the default size. |
| - | * |
| - | * Valid flags for ext2fs_open() |
| - | * |
| - | * EXT2_FLAG_RW - Open the filesystem for read/write. |
| - | * EXT2_FLAG_FORCE - Open the filesystem even if some of the |
| - | * features aren't supported. |
| - | * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device |
| - | */ |
| - | 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) |
| - | { |
| - | ext2_filsys fs; |
| - | errcode_t retval; |
| - | unsigned long i; |
| - | int groups_per_block, blocks_per_group; |
| - | blk_t group_block, blk; |
| - | char *dest, *cp; |
| - | #if BB_BIG_ENDIAN |
| - | int j; |
| - | struct ext2_group_desc *gdp; |
| - | #endif |
| - | |
| - | EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER); |
| - | |
| - | 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; |
| - | fs->umask = 022; |
| - | retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); |
| - | if (retval) |
| - | goto cleanup; |
| - | strcpy(fs->device_name, name); |
| - | cp = strchr(fs->device_name, '?'); |
| - | if (!io_options && cp) { |
| - | *cp++ = 0; |
| - | io_options = cp; |
| - | } |
| - | |
| - | retval = manager->open(fs->device_name, |
| - | (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0, |
| - | &fs->io); |
| - | if (retval) |
| - | goto cleanup; |
| - | if (io_options && |
| - | (retval = io_channel_set_options(fs->io, io_options))) |
| - | goto cleanup; |
| - | fs->image_io = fs->io; |
| - | fs->io->app_data = fs; |
| - | retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super); |
| - | if (retval) |
| - | goto cleanup; |
| - | if (flags & EXT2_FLAG_IMAGE_FILE) { |
| - | retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr), |
| - | &fs->image_header); |
| - | if (retval) |
| - | goto cleanup; |
| - | retval = io_channel_read_blk(fs->io, 0, |
| - | -(int)sizeof(struct ext2_image_hdr), |
| - | fs->image_header); |
| - | if (retval) |
| - | goto cleanup; |
| - | if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE) |
| - | return EXT2_ET_MAGIC_E2IMAGE; |
| - | superblock = 1; |
| - | block_size = fs->image_header->fs_blocksize; |
| - | } |
| - | |
| - | /* |
| - | * If the user specifies a specific block # for the |
| - | * superblock, then he/she must also specify the block size! |
| - | * Otherwise, read the master superblock located at offset |
| - | * SUPERBLOCK_OFFSET from the start of the partition. |
| - | * |
| - | * Note: we only save a backup copy of the superblock if we |
| - | * are reading the superblock from the primary superblock location. |
| - | */ |
| - | if (superblock) { |
| - | if (!block_size) { |
| - | retval = EXT2_ET_INVALID_ARGUMENT; |
| - | goto cleanup; |
| - | } |
| - | io_channel_set_blksize(fs->io, block_size); |
| - | group_block = superblock; |
| - | fs->orig_super = 0; |
| - | } else { |
| - | io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); |
| - | superblock = 1; |
| - | group_block = 0; |
| - | retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super); |
| - | if (retval) |
| - | goto cleanup; |
| - | } |
| - | retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE, |
| - | fs->super); |
| - | if (retval) |
| - | goto cleanup; |
| - | if (fs->orig_super) |
| - | memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE); |
| - | |
| - | #if BB_BIG_ENDIAN |
| - | if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) || |
| - | (fs->flags & EXT2_FLAG_SWAP_BYTES)) { |
| - | fs->flags |= EXT2_FLAG_SWAP_BYTES; |
| - | |
| - | ext2fs_swap_super(fs->super); |
| - | } |
| - | #endif |
| - | |
| - | if (fs->super->s_magic != EXT2_SUPER_MAGIC) { |
| - | retval = EXT2_ET_BAD_MAGIC; |
| - | goto cleanup; |
| - | } |
| - | if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) { |
| - | retval = EXT2_ET_REV_TOO_HIGH; |
| - | goto cleanup; |
| - | } |
| - | |
| - | /* |
| - | * Check for feature set incompatibility |
| - | */ |
| - | if (!(flags & EXT2_FLAG_FORCE)) { |
| - | if (fs->super->s_feature_incompat & |
| - | ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { |
| - | retval = EXT2_ET_UNSUPP_FEATURE; |
| - | goto cleanup; |
| - | } |
| - | if ((flags & EXT2_FLAG_RW) && |
| - | (fs->super->s_feature_ro_compat & |
| - | ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) { |
| - | retval = EXT2_ET_RO_UNSUPP_FEATURE; |
| - | goto cleanup; |
| - | } |
| - | if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) && |
| - | (fs->super->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { |
| - | retval = EXT2_ET_UNSUPP_FEATURE; |
| - | goto cleanup; |
| - | } |
| - | } |
| - | |
| - | fs->blocksize = EXT2_BLOCK_SIZE(fs->super); |
| - | if (fs->blocksize == 0) { |
| - | retval = EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | goto cleanup; |
| - | } |
| - | fs->fragsize = EXT2_FRAG_SIZE(fs->super); |
| - | fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group * |
| - | EXT2_INODE_SIZE(fs->super) + |
| - | EXT2_BLOCK_SIZE(fs->super) - 1) / |
| - | EXT2_BLOCK_SIZE(fs->super)); |
| - | if (block_size) { |
| - | if (block_size != fs->blocksize) { |
| - | retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE; |
| - | goto cleanup; |
| - | } |
| - | } |
| - | /* |
| - | * Set the blocksize to the filesystem's blocksize. |
| - | */ |
| - | io_channel_set_blksize(fs->io, fs->blocksize); |
| - | |
| - | /* |
| - | * If this is an external journal device, don't try to read |
| - | * the group descriptors, because they're not there. |
| - | */ |
| - | if (fs->super->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { |
| - | fs->group_desc_count = 0; |
| - | *ret_fs = fs; |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Read group descriptors |
| - | */ |
| - | blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super); |
| - | if (blocks_per_group == 0 || |
| - | blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) || |
| - | fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) { |
| - | retval = EXT2_ET_CORRUPT_SUPERBLOCK; |
| - | goto cleanup; |
| - | } |
| - | fs->group_desc_count = (fs->super->s_blocks_count - |
| - | fs->super->s_first_data_block + |
| - | blocks_per_group - 1) / blocks_per_group; |
| - | fs->desc_blocks = (fs->group_desc_count + |
| - | EXT2_DESC_PER_BLOCK(fs->super) - 1) |
| - | / EXT2_DESC_PER_BLOCK(fs->super); |
| - | retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize, |
| - | &fs->group_desc); |
| - | if (retval) |
| - | goto cleanup; |
| - | if (!group_block) |
| - | group_block = fs->super->s_first_data_block; |
| - | dest = (char *) fs->group_desc; |
| - | groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc); |
| - | for (i = 0; i < fs->desc_blocks; i++) { |
| - | blk = ext2fs_descriptor_block_loc(fs, group_block, i); |
| - | retval = io_channel_read_blk(fs->io, blk, 1, dest); |
| - | if (retval) |
| - | goto cleanup; |
| - | #if BB_BIG_ENDIAN |
| - | if (fs->flags & EXT2_FLAG_SWAP_BYTES) { |
| - | gdp = (struct ext2_group_desc *) dest; |
| - | for (j=0; j < groups_per_block; j++) |
| - | ext2fs_swap_group_desc(gdp++); |
| - | } |
| - | #endif |
| - | dest += fs->blocksize; |
| - | } |
| - | |
| - | *ret_fs = fs; |
| - | return 0; |
| - | cleanup: |
| - | ext2fs_free(fs); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * Set/get the filesystem data I/O channel. |
| - | * |
| - | * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true. |
| - | */ |
| - | errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io) |
| - | { |
| - | if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) |
| - | return EXT2_ET_NOT_IMAGE_FILE; |
| - | if (old_io) { |
| - | *old_io = (fs->image_io == fs->io) ? 0 : fs->io; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io) |
| - | { |
| - | if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) |
| - | return EXT2_ET_NOT_IMAGE_FILE; |
| - | fs->io = new_io ? new_io : fs->image_io; |
| - | return 0; |
| - | } |
| - | |
| - | errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io) |
| - | { |
| - | if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) |
| - | return EXT2_ET_NOT_IMAGE_FILE; |
| - | fs->io = fs->image_io = new_io; |
| - | fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW | |
| - | EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY; |
| - | fs->flags &= ~EXT2_FLAG_IMAGE_FILE; |
| - | return 0; |
| - | } |
| @@ -1,96 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * read_bb --- read the bad blocks inode |
| - | * |
| - | * Copyright (C) 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" |
| - | #include "ext2fs.h" |
| - | |
| - | struct read_bb_record { |
| - | ext2_badblocks_list bb_list; |
| - | errcode_t err; |
| - | }; |
| - | |
| - | /* |
| - | * Helper function for ext2fs_read_bb_inode() |
| - | */ |
| - | #ifdef __TURBOC__ |
| - | # pragma argsused |
| - | #endif |
| - | static int mark_bad_block(ext2_filsys fs, blk_t *block_nr, |
| - | e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), |
| - | blk_t ref_block EXT2FS_ATTR((unused)), |
| - | int ref_offset EXT2FS_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | struct read_bb_record *rb = (struct read_bb_record *) priv_data; |
| - | |
| - | if (blockcnt < 0) |
| - | return 0; |
| - | |
| - | if ((*block_nr < fs->super->s_first_data_block) || |
| - | (*block_nr >= fs->super->s_blocks_count)) |
| - | return 0; /* Ignore illegal blocks */ |
| - | |
| - | rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr); |
| - | if (rb->err) |
| - | return BLOCK_ABORT; |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Reads the current bad blocks from the bad blocks inode. |
| - | */ |
| - | errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list) |
| - | { |
| - | errcode_t retval; |
| - | struct read_bb_record rb; |
| - | struct ext2_inode inode; |
| - | blk_t numblocks; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (!*bb_list) { |
| - | retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode); |
| - | if (retval) |
| - | return retval; |
| - | if (inode.i_blocks < 500) |
| - | numblocks = (inode.i_blocks / |
| - | (fs->blocksize / 512)) + 20; |
| - | else |
| - | numblocks = 500; |
| - | retval = ext2fs_badblocks_list_create(bb_list, numblocks); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | |
| - | rb.bb_list = *bb_list; |
| - | rb.err = 0; |
| - | retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0, |
| - | mark_bad_block, &rb); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | return rb.err; |
| - | } |
| @@ -1,96 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * read_bb_file.c --- read a list of bad blocks from a FILE * |
| - | * |
| - | * Copyright (C) 1994, 1995, 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 |
| - | #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" |
| - | |
| - | /* |
| - | * Reads a list of bad blocks from a FILE * |
| - | */ |
| - | 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)) |
| - | { |
| - | errcode_t retval; |
| - | blk_t blockno; |
| - | int count; |
| - | char buf[128]; |
| - | |
| - | if (fs) |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (!*bb_list) { |
| - | retval = ext2fs_badblocks_list_create(bb_list, 10); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | |
| - | while (!feof (f)) { |
| - | if (fgets(buf, sizeof(buf), f) == NULL) |
| - | break; |
| - | count = sscanf(buf, "%u", &blockno); |
| - | if (count <= 0) |
| - | continue; |
| - | if (fs && |
| - | ((blockno < fs->super->s_first_data_block) || |
| - | (blockno >= fs->super->s_blocks_count))) { |
| - | if (invalid) |
| - | (invalid)(fs, blockno, buf, priv_data); |
| - | continue; |
| - | } |
| - | retval = ext2fs_badblocks_list_add(*bb_list, blockno); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static void call_compat_invalid(ext2_filsys fs, blk_t blk, |
| - | char *badstr EXT2FS_ATTR((unused)), |
| - | void *priv_data) |
| - | { |
| - | void (*invalid)(ext2_filsys, blk_t); |
| - | |
| - | invalid = (void (*)(ext2_filsys, blk_t)) priv_data; |
| - | if (invalid) |
| - | invalid(fs, blk); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Reads a list of bad blocks from a FILE * |
| - | */ |
| - | errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, |
| - | ext2_badblocks_list *bb_list, |
| - | void (*invalid)(ext2_filsys fs, blk_t blk)) |
| - | { |
| - | return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid, |
| - | call_compat_invalid); |
| - | } |
| @@ -1,220 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * res_gdt.c --- reserve blocks for growing the group descriptor table |
| - | * during online resizing. |
| - | * |
| - | * Copyright (C) 2002 Andreas Dilger |
| - | * |
| - | * %Begin-Header% |
| - | * This file may be redistributed under the terms of the GNU Public |
| - | * License. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <stdio.h> |
| - | #include <string.h> |
| - | #include <time.h> |
| - | #include "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | |
| - | /* |
| - | * Iterate through the groups which hold BACKUP superblock/GDT copies in an |
| - | * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before |
| - | * calling this for the first time. In a sparse filesystem it will be the |
| - | * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... |
| - | * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... |
| - | */ |
| - | static unsigned int list_backups(ext2_filsys fs, unsigned int *three, |
| - | unsigned int *five, unsigned int *seven) |
| - | { |
| - | unsigned int *min = three; |
| - | int mult = 3; |
| - | unsigned int ret; |
| - | |
| - | if (!(fs->super->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) { |
| - | ret = *min; |
| - | *min += 1; |
| - | return ret; |
| - | } |
| - | |
| - | if (*five < *min) { |
| - | min = five; |
| - | mult = 5; |
| - | } |
| - | if (*seven < *min) { |
| - | min = seven; |
| - | mult = 7; |
| - | } |
| - | |
| - | ret = *min; |
| - | *min *= mult; |
| - | |
| - | return ret; |
| - | } |
| - | |
| - | /* |
| - | * This code assumes that the reserved blocks have already been marked in-use |
| - | * during ext2fs_initialize(), so that they are not allocated for other |
| - | * uses before we can add them to the resize inode (which has to come |
| - | * after the creation of the inode table). |
| - | */ |
| - | errcode_t ext2fs_create_resize_inode(ext2_filsys fs) |
| - | { |
| - | errcode_t retval, retval2; |
| - | struct ext2_super_block *sb; |
| - | struct ext2_inode inode; |
| - | __u32 *dindir_buf, *gdt_buf; |
| - | int rsv_add; |
| - | unsigned long long apb, inode_size; |
| - | blk_t dindir_blk, rsv_off, gdt_off, gdt_blk; |
| - | int dindir_dirty = 0, inode_dirty = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | sb = fs->super; |
| - | |
| - | retval = ext2fs_get_mem(2 * fs->blocksize, (void *)&dindir_buf); |
| - | if (retval) |
| - | goto out_free; |
| - | gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize); |
| - | |
| - | retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); |
| - | if (retval) |
| - | goto out_free; |
| - | |
| - | /* Maximum possible file size (we donly use the dindirect blocks) */ |
| - | apb = EXT2_ADDR_PER_BLOCK(sb); |
| - | rsv_add = fs->blocksize / 512; |
| - | if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) { |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("reading GDT dindir %u\n", dindir_blk); |
| - | #endif |
| - | retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf); |
| - | if (retval) |
| - | goto out_inode; |
| - | } else { |
| - | blk_t goal = 3 + sb->s_reserved_gdt_blocks + |
| - | fs->desc_blocks + fs->inode_blocks_per_group; |
| - | |
| - | retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk); |
| - | if (retval) |
| - | goto out_free; |
| - | inode.i_mode = LINUX_S_IFREG | 0600; |
| - | inode.i_links_count = 1; |
| - | inode.i_block[EXT2_DIND_BLOCK] = dindir_blk; |
| - | inode.i_blocks = rsv_add; |
| - | memset(dindir_buf, 0, fs->blocksize); |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("allocated GDT dindir %u\n", dindir_blk); |
| - | #endif |
| - | dindir_dirty = inode_dirty = 1; |
| - | inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS; |
| - | inode_size *= fs->blocksize; |
| - | inode.i_size = inode_size & 0xFFFFFFFF; |
| - | inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; |
| - | if (inode.i_size_high) { |
| - | sb->s_feature_ro_compat |= |
| - | EXT2_FEATURE_RO_COMPAT_LARGE_FILE; |
| - | } |
| - | inode.i_ctime = time(NULL); |
| - | } |
| - | |
| - | for (rsv_off = 0, gdt_off = fs->desc_blocks, |
| - | gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks; |
| - | rsv_off < sb->s_reserved_gdt_blocks; |
| - | rsv_off++, gdt_off++, gdt_blk++) { |
| - | unsigned int three = 1, five = 5, seven = 7; |
| - | unsigned int grp, last = 0; |
| - | int gdt_dirty = 0; |
| - | |
| - | gdt_off %= apb; |
| - | if (!dindir_buf[gdt_off]) { |
| - | /* FIXME XXX XXX |
| - | blk_t new_blk; |
| - | |
| - | retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk); |
| - | if (retval) |
| - | goto out_free; |
| - | if (new_blk != gdt_blk) { |
| - | // XXX free block |
| - | retval = -1; // XXX |
| - | } |
| - | */ |
| - | gdt_dirty = dindir_dirty = inode_dirty = 1; |
| - | memset(gdt_buf, 0, fs->blocksize); |
| - | dindir_buf[gdt_off] = gdt_blk; |
| - | inode.i_blocks += rsv_add; |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("added primary GDT block %u at %u[%u]\n", |
| - | gdt_blk, dindir_blk, gdt_off); |
| - | #endif |
| - | } else if (dindir_buf[gdt_off] == gdt_blk) { |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("reading primary GDT block %u\n", gdt_blk); |
| - | #endif |
| - | retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf); |
| - | if (retval) |
| - | goto out_dindir; |
| - | } else { |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("bad primary GDT %u != %u at %u[%u]\n", |
| - | dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off); |
| - | #endif |
| - | retval = EXT2_ET_RESIZE_INODE_CORRUPT; |
| - | goto out_dindir; |
| - | } |
| - | |
| - | while ((grp = list_backups(fs, &three, &five, &seven)) < |
| - | fs->group_desc_count) { |
| - | blk_t expect = gdt_blk + grp * sb->s_blocks_per_group; |
| - | |
| - | if (!gdt_buf[last]) { |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("added backup GDT %u grp %u@%u[%u]\n", |
| - | expect, grp, gdt_blk, last); |
| - | #endif |
| - | gdt_buf[last] = expect; |
| - | inode.i_blocks += rsv_add; |
| - | gdt_dirty = inode_dirty = 1; |
| - | } else if (gdt_buf[last] != expect) { |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("bad backup GDT %u != %u at %u[%u]\n", |
| - | gdt_buf[last], expect, gdt_blk, last); |
| - | #endif |
| - | retval = EXT2_ET_RESIZE_INODE_CORRUPT; |
| - | goto out_dindir; |
| - | } |
| - | last++; |
| - | } |
| - | if (gdt_dirty) { |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("writing primary GDT block %u\n", gdt_blk); |
| - | #endif |
| - | retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf); |
| - | if (retval) |
| - | goto out_dindir; |
| - | } |
| - | } |
| - | |
| - | out_dindir: |
| - | if (dindir_dirty) { |
| - | retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf); |
| - | if (!retval) |
| - | retval = retval2; |
| - | } |
| - | out_inode: |
| - | #ifdef RES_GDT_DEBUG |
| - | printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks, |
| - | inode.i_size); |
| - | #endif |
| - | if (inode_dirty) { |
| - | inode.i_atime = inode.i_mtime = time(NULL); |
| - | retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode); |
| - | if (!retval) |
| - | retval = retval2; |
| - | } |
| - | out_free: |
| - | ext2fs_free_mem((void *)&dindir_buf); |
| - | return retval; |
| - | } |
| @@ -1,106 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * rs_bitmap.c --- routine for changing the size of a bitmap |
| - | * |
| - | * 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 <stdio.h> |
| - | #include <string.h> |
| - | #if HAVE_UNISTD_H |
| - | #include <unistd.h> |
| - | #endif |
| - | #include <fcntl.h> |
| - | #include <time.h> |
| - | #ifdef HAVE_SYS_STAT_H |
| - | #include <sys/stat.h> |
| - | #endif |
| - | #ifdef HAVE_SYS_TYPES_H |
| - | #include <sys/types.h> |
| - | #endif |
| - | |
| - | #include "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | |
| - | errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end, |
| - | ext2fs_generic_bitmap bmap) |
| - | { |
| - | errcode_t retval; |
| - | size_t size, new_size; |
| - | __u32 bitno; |
| - | |
| - | if (!bmap) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | |
| - | EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP); |
| - | |
| - | /* |
| - | * If we're expanding the bitmap, make sure all of the new |
| - | * parts of the bitmap are zero. |
| - | */ |
| - | if (new_end > bmap->end) { |
| - | bitno = bmap->real_end; |
| - | if (bitno > new_end) |
| - | bitno = new_end; |
| - | for (; bitno > bmap->end; bitno--) |
| - | ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap); |
| - | } |
| - | if (new_real_end == bmap->real_end) { |
| - | bmap->end = new_end; |
| - | return 0; |
| - | } |
| - | |
| - | size = ((bmap->real_end - bmap->start) / 8) + 1; |
| - | new_size = ((new_real_end - bmap->start) / 8) + 1; |
| - | |
| - | if (size != new_size) { |
| - | retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | if (new_size > size) |
| - | memset(bmap->bitmap + size, 0, new_size - size); |
| - | |
| - | bmap->end = new_end; |
| - | bmap->real_end = new_real_end; |
| - | return 0; |
| - | } |
| - | |
| - | errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, |
| - | ext2fs_inode_bitmap bmap) |
| - | { |
| - | errcode_t retval; |
| - | |
| - | if (!bmap) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | |
| - | EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP); |
| - | |
| - | bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP; |
| - | retval = ext2fs_resize_generic_bitmap(new_end, new_real_end, |
| - | bmap); |
| - | bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP; |
| - | return retval; |
| - | } |
| - | |
| - | errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, |
| - | ext2fs_block_bitmap bmap) |
| - | { |
| - | errcode_t retval; |
| - | |
| - | if (!bmap) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | |
| - | EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP); |
| - | |
| - | bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP; |
| - | retval = ext2fs_resize_generic_bitmap(new_end, new_real_end, |
| - | bmap); |
| - | bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP; |
| - | return retval; |
| - | } |
| @@ -1,294 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * rw_bitmaps.c --- routines to read and write the inode and block bitmaps. |
| - | * |
| - | * Copyright (C) 1993, 1994, 1994, 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> |
| - | #ifdef HAVE_SYS_STAT_H |
| - | #include <sys/stat.h> |
| - | #endif |
| - | #ifdef HAVE_SYS_TYPES_H |
| - | #include <sys/types.h> |
| - | #endif |
| - | |
| - | #include "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | #include "e2image.h" |
| - | |
| - | #if defined(__powerpc__) && BB_BIG_ENDIAN |
| - | /* |
| - | * On the PowerPC, the big-endian variant of the ext2 filesystem |
| - | * has its bitmaps stored as 32-bit words with bit 0 as the LSB |
| - | * of each word. Thus a bitmap with only bit 0 set would be, as |
| - | * a string of bytes, 00 00 00 01 00 ... |
| - | * To cope with this, we byte-reverse each word of a bitmap if |
| - | * we have a big-endian filesystem, that is, if we are *not* |
| - | * byte-swapping other word-sized numbers. |
| - | */ |
| - | #define EXT2_BIG_ENDIAN_BITMAPS |
| - | #endif |
| - | |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes) |
| - | { |
| - | __u32 *p = (__u32 *) bitmap; |
| - | int n; |
| - | |
| - | for (n = nbytes / sizeof(__u32); n > 0; --n, ++p) |
| - | *p = ext2fs_swab32(*p); |
| - | } |
| - | #endif |
| - | |
| - | errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs) |
| - | { |
| - | dgrp_t i; |
| - | size_t nbytes; |
| - | errcode_t retval; |
| - | char * inode_bitmap = fs->inode_map->bitmap; |
| - | char * bitmap_block = NULL; |
| - | blk_t blk; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (!(fs->flags & EXT2_FLAG_RW)) |
| - | return EXT2_ET_RO_FILSYS; |
| - | if (!inode_bitmap) |
| - | return 0; |
| - | nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); |
| - | |
| - | retval = ext2fs_get_mem(fs->blocksize, &bitmap_block); |
| - | if (retval) |
| - | return retval; |
| - | memset(bitmap_block, 0xff, fs->blocksize); |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | memcpy(bitmap_block, inode_bitmap, nbytes); |
| - | blk = fs->group_desc[i].bg_inode_bitmap; |
| - | if (blk) { |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || |
| - | (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) |
| - | ext2fs_swap_bitmap(fs, bitmap_block, nbytes); |
| - | #endif |
| - | retval = io_channel_write_blk(fs->io, blk, 1, |
| - | bitmap_block); |
| - | if (retval) |
| - | return EXT2_ET_INODE_BITMAP_WRITE; |
| - | } |
| - | inode_bitmap += nbytes; |
| - | } |
| - | fs->flags &= ~EXT2_FLAG_IB_DIRTY; |
| - | ext2fs_free_mem(&bitmap_block); |
| - | return 0; |
| - | } |
| - | |
| - | errcode_t ext2fs_write_block_bitmap (ext2_filsys fs) |
| - | { |
| - | dgrp_t i; |
| - | unsigned int j; |
| - | int nbytes; |
| - | unsigned int nbits; |
| - | errcode_t retval; |
| - | char * block_bitmap = fs->block_map->bitmap; |
| - | char * bitmap_block = NULL; |
| - | blk_t blk; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (!(fs->flags & EXT2_FLAG_RW)) |
| - | return EXT2_ET_RO_FILSYS; |
| - | if (!block_bitmap) |
| - | return 0; |
| - | nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; |
| - | retval = ext2fs_get_mem(fs->blocksize, &bitmap_block); |
| - | if (retval) |
| - | return retval; |
| - | memset(bitmap_block, 0xff, fs->blocksize); |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | memcpy(bitmap_block, block_bitmap, nbytes); |
| - | if (i == fs->group_desc_count - 1) { |
| - | /* Force bitmap padding for the last group */ |
| - | nbits = ((fs->super->s_blocks_count |
| - | - fs->super->s_first_data_block) |
| - | % EXT2_BLOCKS_PER_GROUP(fs->super)); |
| - | if (nbits) |
| - | for (j = nbits; j < fs->blocksize * 8; j++) |
| - | ext2fs_set_bit(j, bitmap_block); |
| - | } |
| - | blk = fs->group_desc[i].bg_block_bitmap; |
| - | if (blk) { |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || |
| - | (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) |
| - | ext2fs_swap_bitmap(fs, bitmap_block, nbytes); |
| - | #endif |
| - | retval = io_channel_write_blk(fs->io, blk, 1, |
| - | bitmap_block); |
| - | if (retval) |
| - | return EXT2_ET_BLOCK_BITMAP_WRITE; |
| - | } |
| - | block_bitmap += nbytes; |
| - | } |
| - | fs->flags &= ~EXT2_FLAG_BB_DIRTY; |
| - | ext2fs_free_mem(&bitmap_block); |
| - | return 0; |
| - | } |
| - | |
| - | static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) |
| - | { |
| - | dgrp_t i; |
| - | char *block_bitmap = NULL, *inode_bitmap = NULL; |
| - | char *buf; |
| - | errcode_t retval; |
| - | int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8; |
| - | int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8; |
| - | blk_t blk; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | fs->write_bitmaps = ext2fs_write_bitmaps; |
| - | |
| - | retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); |
| - | if (retval) |
| - | return retval; |
| - | if (do_block) { |
| - | ext2fs_free_block_bitmap(fs->block_map); |
| - | sprintf(buf, "block bitmap for %s", fs->device_name); |
| - | retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); |
| - | if (retval) |
| - | goto cleanup; |
| - | block_bitmap = fs->block_map->bitmap; |
| - | } |
| - | if (do_inode) { |
| - | ext2fs_free_inode_bitmap(fs->inode_map); |
| - | sprintf(buf, "inode bitmap for %s", fs->device_name); |
| - | retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); |
| - | if (retval) |
| - | goto cleanup; |
| - | inode_bitmap = fs->inode_map->bitmap; |
| - | } |
| - | ext2fs_free_mem(&buf); |
| - | |
| - | if (fs->flags & EXT2_FLAG_IMAGE_FILE) { |
| - | if (inode_bitmap) { |
| - | blk = (fs->image_header->offset_inodemap / |
| - | fs->blocksize); |
| - | retval = io_channel_read_blk(fs->image_io, blk, |
| - | -(inode_nbytes * fs->group_desc_count), |
| - | inode_bitmap); |
| - | if (retval) |
| - | goto cleanup; |
| - | } |
| - | if (block_bitmap) { |
| - | blk = (fs->image_header->offset_blockmap / |
| - | fs->blocksize); |
| - | retval = io_channel_read_blk(fs->image_io, blk, |
| - | -(block_nbytes * fs->group_desc_count), |
| - | block_bitmap); |
| - | if (retval) |
| - | goto cleanup; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | if (block_bitmap) { |
| - | blk = fs->group_desc[i].bg_block_bitmap; |
| - | if (blk) { |
| - | retval = io_channel_read_blk(fs->io, blk, |
| - | -block_nbytes, block_bitmap); |
| - | if (retval) { |
| - | retval = EXT2_ET_BLOCK_BITMAP_READ; |
| - | goto cleanup; |
| - | } |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || |
| - | (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))) |
| - | ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes); |
| - | #endif |
| - | } else |
| - | memset(block_bitmap, 0, block_nbytes); |
| - | block_bitmap += block_nbytes; |
| - | } |
| - | if (inode_bitmap) { |
| - | blk = fs->group_desc[i].bg_inode_bitmap; |
| - | if (blk) { |
| - | retval = io_channel_read_blk(fs->io, blk, |
| - | -inode_nbytes, inode_bitmap); |
| - | if (retval) { |
| - | retval = EXT2_ET_INODE_BITMAP_READ; |
| - | goto cleanup; |
| - | } |
| - | #ifdef EXT2_BIG_ENDIAN_BITMAPS |
| - | if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || |
| - | (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))) |
| - | ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes); |
| - | #endif |
| - | } else |
| - | memset(inode_bitmap, 0, inode_nbytes); |
| - | inode_bitmap += inode_nbytes; |
| - | } |
| - | } |
| - | return 0; |
| - | |
| - | cleanup: |
| - | if (do_block) { |
| - | ext2fs_free_mem(&fs->block_map); |
| - | } |
| - | if (do_inode) { |
| - | ext2fs_free_mem(&fs->inode_map); |
| - | } |
| - | ext2fs_free_mem(&buf); |
| - | return retval; |
| - | } |
| - | |
| - | errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs) |
| - | { |
| - | return read_bitmaps(fs, 1, 0); |
| - | } |
| - | |
| - | errcode_t ext2fs_read_block_bitmap(ext2_filsys fs) |
| - | { |
| - | return read_bitmaps(fs, 0, 1); |
| - | } |
| - | |
| - | errcode_t ext2fs_read_bitmaps(ext2_filsys fs) |
| - | { |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (fs->inode_map && fs->block_map) |
| - | return 0; |
| - | |
| - | return read_bitmaps(fs, !fs->inode_map, !fs->block_map); |
| - | } |
| - | |
| - | errcode_t ext2fs_write_bitmaps(ext2_filsys fs) |
| - | { |
| - | errcode_t retval; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (fs->block_map && ext2fs_test_bb_dirty(fs)) { |
| - | retval = ext2fs_write_block_bitmap(fs); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | if (fs->inode_map && ext2fs_test_ib_dirty(fs)) { |
| - | retval = ext2fs_write_inode_bitmap(fs); |
| - | if (retval) |
| - | return retval; |
| - | } |
| - | return 0; |
| - | } |
| @@ -1,79 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * sparse.c --- find the groups in an ext2 filesystem with metadata backups |
| - | * |
| - | * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. |
| - | * Copyright (C) 2002 Andreas Dilger. |
| - | * |
| - | * %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 "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; |
| - | } |
| - | |
| - | /* |
| - | * Iterate through the groups which hold BACKUP superblock/GDT copies in an |
| - | * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before |
| - | * calling this for the first time. In a sparse filesystem it will be the |
| - | * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... |
| - | * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... |
| - | */ |
| - | unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three, |
| - | unsigned int *five, unsigned int *seven) |
| - | { |
| - | unsigned int *min = three; |
| - | int mult = 3; |
| - | unsigned int ret; |
| - | |
| - | if (!(fs->super->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) { |
| - | ret = *min; |
| - | *min += 1; |
| - | return ret; |
| - | } |
| - | |
| - | if (*five < *min) { |
| - | min = five; |
| - | mult = 5; |
| - | } |
| - | if (*seven < *min) { |
| - | min = seven; |
| - | mult = 7; |
| - | } |
| - | |
| - | ret = *min; |
| - | *min *= mult; |
| - | |
| - | return ret; |
| - | } |
| @@ -1,234 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * swapfs.c --- swap ext2 filesystem data structures |
| - | * |
| - | * Copyright (C) 1995, 1996, 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 "ext2fs.h" |
| - | #include "ext2_ext_attr.h" |
| - | |
| - | #if BB_BIG_ENDIAN |
| - | void ext2fs_swap_super(struct ext2_super_block * sb) |
| - | { |
| - | int i; |
| - | sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count); |
| - | sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count); |
| - | sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count); |
| - | sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count); |
| - | sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count); |
| - | sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block); |
| - | sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size); |
| - | sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size); |
| - | sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group); |
| - | sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group); |
| - | sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group); |
| - | sb->s_mtime = ext2fs_swab32(sb->s_mtime); |
| - | sb->s_wtime = ext2fs_swab32(sb->s_wtime); |
| - | sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count); |
| - | sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count); |
| - | sb->s_magic = ext2fs_swab16(sb->s_magic); |
| - | sb->s_state = ext2fs_swab16(sb->s_state); |
| - | sb->s_errors = ext2fs_swab16(sb->s_errors); |
| - | sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level); |
| - | sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck); |
| - | sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval); |
| - | sb->s_creator_os = ext2fs_swab32(sb->s_creator_os); |
| - | sb->s_rev_level = ext2fs_swab32(sb->s_rev_level); |
| - | sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid); |
| - | sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid); |
| - | sb->s_first_ino = ext2fs_swab32(sb->s_first_ino); |
| - | sb->s_inode_size = ext2fs_swab16(sb->s_inode_size); |
| - | sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr); |
| - | sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat); |
| - | sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat); |
| - | sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat); |
| - | sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap); |
| - | sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks); |
| - | sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum); |
| - | sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev); |
| - | sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan); |
| - | sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts); |
| - | sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg); |
| - | sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time); |
| - | for (i=0; i < 4; i++) |
| - | sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]); |
| - | for (i=0; i < 17; i++) |
| - | sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]); |
| - | } |
| - | |
| - | void ext2fs_swap_group_desc(struct ext2_group_desc *gdp) |
| - | { |
| - | gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap); |
| - | gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap); |
| - | gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table); |
| - | gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count); |
| - | gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count); |
| - | gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count); |
| - | } |
| - | |
| - | void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header) |
| - | { |
| - | struct ext2_ext_attr_header *from_header = |
| - | (struct ext2_ext_attr_header *)from; |
| - | struct ext2_ext_attr_header *to_header = |
| - | (struct ext2_ext_attr_header *)to; |
| - | struct ext2_ext_attr_entry *from_entry, *to_entry; |
| - | char *from_end = (char *)from_header + bufsize; |
| - | int n; |
| - | |
| - | if (to_header != from_header) |
| - | memcpy(to_header, from_header, bufsize); |
| - | |
| - | from_entry = (struct ext2_ext_attr_entry *)from_header; |
| - | to_entry = (struct ext2_ext_attr_entry *)to_header; |
| - | |
| - | if (has_header) { |
| - | to_header->h_magic = ext2fs_swab32(from_header->h_magic); |
| - | to_header->h_blocks = ext2fs_swab32(from_header->h_blocks); |
| - | to_header->h_refcount = ext2fs_swab32(from_header->h_refcount); |
| - | for (n=0; n<4; n++) |
| - | to_header->h_reserved[n] = |
| - | ext2fs_swab32(from_header->h_reserved[n]); |
| - | from_entry = (struct ext2_ext_attr_entry *)(from_header+1); |
| - | to_entry = (struct ext2_ext_attr_entry *)(to_header+1); |
| - | } |
| - | |
| - | while ((char *)from_entry < from_end && *(__u32 *)from_entry) { |
| - | to_entry->e_value_offs = |
| - | ext2fs_swab16(from_entry->e_value_offs); |
| - | to_entry->e_value_block = |
| - | ext2fs_swab32(from_entry->e_value_block); |
| - | to_entry->e_value_size = |
| - | ext2fs_swab32(from_entry->e_value_size); |
| - | from_entry = EXT2_EXT_ATTR_NEXT(from_entry); |
| - | to_entry = EXT2_EXT_ATTR_NEXT(to_entry); |
| - | } |
| - | } |
| - | |
| - | void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, |
| - | struct ext2_inode_large *f, int hostorder, |
| - | int bufsize) |
| - | { |
| - | unsigned i; |
| - | int islnk = 0; |
| - | __u32 *eaf, *eat; |
| - | |
| - | if (hostorder && LINUX_S_ISLNK(f->i_mode)) |
| - | islnk = 1; |
| - | t->i_mode = ext2fs_swab16(f->i_mode); |
| - | if (!hostorder && LINUX_S_ISLNK(t->i_mode)) |
| - | islnk = 1; |
| - | t->i_uid = ext2fs_swab16(f->i_uid); |
| - | t->i_size = ext2fs_swab32(f->i_size); |
| - | t->i_atime = ext2fs_swab32(f->i_atime); |
| - | t->i_ctime = ext2fs_swab32(f->i_ctime); |
| - | t->i_mtime = ext2fs_swab32(f->i_mtime); |
| - | t->i_dtime = ext2fs_swab32(f->i_dtime); |
| - | t->i_gid = ext2fs_swab16(f->i_gid); |
| - | t->i_links_count = ext2fs_swab16(f->i_links_count); |
| - | t->i_blocks = ext2fs_swab32(f->i_blocks); |
| - | t->i_flags = ext2fs_swab32(f->i_flags); |
| - | t->i_file_acl = ext2fs_swab32(f->i_file_acl); |
| - | t->i_dir_acl = ext2fs_swab32(f->i_dir_acl); |
| - | if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) { |
| - | for (i = 0; i < EXT2_N_BLOCKS; i++) |
| - | t->i_block[i] = ext2fs_swab32(f->i_block[i]); |
| - | } else if (t != f) { |
| - | for (i = 0; i < EXT2_N_BLOCKS; i++) |
| - | t->i_block[i] = f->i_block[i]; |
| - | } |
| - | t->i_generation = ext2fs_swab32(f->i_generation); |
| - | t->i_faddr = ext2fs_swab32(f->i_faddr); |
| - | |
| - | switch (fs->super->s_creator_os) { |
| - | case EXT2_OS_LINUX: |
| - | t->osd1.linux1.l_i_reserved1 = |
| - | ext2fs_swab32(f->osd1.linux1.l_i_reserved1); |
| - | t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag; |
| - | t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize; |
| - | t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1); |
| - | t->osd2.linux2.l_i_uid_high = |
| - | ext2fs_swab16 (f->osd2.linux2.l_i_uid_high); |
| - | t->osd2.linux2.l_i_gid_high = |
| - | ext2fs_swab16 (f->osd2.linux2.l_i_gid_high); |
| - | t->osd2.linux2.l_i_reserved2 = |
| - | ext2fs_swab32(f->osd2.linux2.l_i_reserved2); |
| - | break; |
| - | case EXT2_OS_HURD: |
| - | t->osd1.hurd1.h_i_translator = |
| - | ext2fs_swab32 (f->osd1.hurd1.h_i_translator); |
| - | t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag; |
| - | t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize; |
| - | t->osd2.hurd2.h_i_mode_high = |
| - | ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high); |
| - | t->osd2.hurd2.h_i_uid_high = |
| - | ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high); |
| - | t->osd2.hurd2.h_i_gid_high = |
| - | ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high); |
| - | t->osd2.hurd2.h_i_author = |
| - | ext2fs_swab32 (f->osd2.hurd2.h_i_author); |
| - | break; |
| - | case EXT2_OS_MASIX: |
| - | t->osd1.masix1.m_i_reserved1 = |
| - | ext2fs_swab32(f->osd1.masix1.m_i_reserved1); |
| - | t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag; |
| - | t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize; |
| - | t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1); |
| - | t->osd2.masix2.m_i_reserved2[0] = |
| - | ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]); |
| - | t->osd2.masix2.m_i_reserved2[1] = |
| - | ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]); |
| - | break; |
| - | } |
| - | |
| - | if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16))) |
| - | return; /* no i_extra_isize field */ |
| - | |
| - | t->i_extra_isize = ext2fs_swab16(f->i_extra_isize); |
| - | if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) - |
| - | sizeof(struct ext2_inode)) { |
| - | /* this is error case: i_extra_size is too large */ |
| - | return; |
| - | } |
| - | |
| - | i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32); |
| - | if (bufsize < (int) i) |
| - | return; /* no space for EA magic */ |
| - | |
| - | eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) + |
| - | f->i_extra_isize); |
| - | |
| - | if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC) |
| - | return; /* it seems no magic here */ |
| - | |
| - | eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) + |
| - | f->i_extra_isize); |
| - | *eat = ext2fs_swab32(*eaf); |
| - | |
| - | /* convert EA(s) */ |
| - | ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1), |
| - | bufsize - sizeof(struct ext2_inode) - |
| - | t->i_extra_isize - sizeof(__u32), 0); |
| - | } |
| - | |
| - | void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t, |
| - | struct ext2_inode *f, int hostorder) |
| - | { |
| - | ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t, |
| - | (struct ext2_inode_large *) f, hostorder, |
| - | sizeof(struct ext2_inode)); |
| - | } |
| - | |
| - | #endif |
| @@ -1,380 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * test_io.c --- This is the Test I/O interface. |
| - | * |
| - | * 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" |
| - | |
| - | /* |
| - | * For checking structure magic numbers... |
| - | */ |
| - | |
| - | #define EXT2_CHECK_MAGIC(struct, code) \ |
| - | if ((struct)->magic != (code)) return (code) |
| - | |
| - | struct test_private_data { |
| - | int magic; |
| - | io_channel real; |
| - | int flags; |
| - | FILE *outfile; |
| - | unsigned long block; |
| - | int read_abort_count, write_abort_count; |
| - | void (*read_blk)(unsigned long block, int count, errcode_t err); |
| - | void (*write_blk)(unsigned long block, int count, errcode_t err); |
| - | void (*set_blksize)(int blksize, errcode_t err); |
| - | void (*write_byte)(unsigned long block, int count, errcode_t err); |
| - | }; |
| - | |
| - | static errcode_t test_open(const char *name, int flags, io_channel *channel); |
| - | static errcode_t test_close(io_channel channel); |
| - | static errcode_t test_set_blksize(io_channel channel, int blksize); |
| - | static errcode_t test_read_blk(io_channel channel, unsigned long block, |
| - | int count, void *data); |
| - | static errcode_t test_write_blk(io_channel channel, unsigned long block, |
| - | int count, const void *data); |
| - | static errcode_t test_flush(io_channel channel); |
| - | static errcode_t test_write_byte(io_channel channel, unsigned long offset, |
| - | int count, const void *buf); |
| - | static errcode_t test_set_option(io_channel channel, const char *option, |
| - | const char *arg); |
| - | |
| - | static struct struct_io_manager struct_test_manager = { |
| - | EXT2_ET_MAGIC_IO_MANAGER, |
| - | "Test I/O Manager", |
| - | test_open, |
| - | test_close, |
| - | test_set_blksize, |
| - | test_read_blk, |
| - | test_write_blk, |
| - | test_flush, |
| - | test_write_byte, |
| - | test_set_option |
| - | }; |
| - | |
| - | io_manager test_io_manager = &struct_test_manager; |
| - | |
| - | /* |
| - | * These global variable can be set by the test program as |
| - | * necessary *before* calling test_open |
| - | */ |
| - | io_manager test_io_backing_manager = 0; |
| - | void (*test_io_cb_read_blk) |
| - | (unsigned long block, int count, errcode_t err) = 0; |
| - | void (*test_io_cb_write_blk) |
| - | (unsigned long block, int count, errcode_t err) = 0; |
| - | void (*test_io_cb_set_blksize) |
| - | (int blksize, errcode_t err) = 0; |
| - | void (*test_io_cb_write_byte) |
| - | (unsigned long block, int count, errcode_t err) = 0; |
| - | |
| - | /* |
| - | * Test flags |
| - | */ |
| - | #define TEST_FLAG_READ 0x01 |
| - | #define TEST_FLAG_WRITE 0x02 |
| - | #define TEST_FLAG_SET_BLKSIZE 0x04 |
| - | #define TEST_FLAG_FLUSH 0x08 |
| - | #define TEST_FLAG_DUMP 0x10 |
| - | #define TEST_FLAG_SET_OPTION 0x20 |
| - | |
| - | static void test_dump_block(io_channel channel, |
| - | struct test_private_data *data, |
| - | unsigned long block, const void *buf) |
| - | { |
| - | const unsigned char *cp; |
| - | FILE *f = data->outfile; |
| - | int i; |
| - | unsigned long cksum = 0; |
| - | |
| - | for (i=0, cp = buf; i < channel->block_size; i++, cp++) { |
| - | cksum += *cp; |
| - | } |
| - | fprintf(f, "Contents of block %lu, checksum %08lu:\n", block, cksum); |
| - | for (i=0, cp = buf; i < channel->block_size; i++, cp++) { |
| - | if ((i % 16) == 0) |
| - | fprintf(f, "%04x: ", i); |
| - | fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' '); |
| - | } |
| - | } |
| - | |
| - | static void test_abort(io_channel channel, unsigned long block) |
| - | { |
| - | struct test_private_data *data; |
| - | FILE *f; |
| - | |
| - | data = (struct test_private_data *) channel->private_data; |
| - | f = data->outfile; |
| - | test_flush(channel); |
| - | |
| - | fprintf(f, "Aborting due to I/O to block %lu\n", block); |
| - | fflush(f); |
| - | abort(); |
| - | } |
| - | |
| - | static errcode_t test_open(const char *name, int flags, io_channel *channel) |
| - | { |
| - | io_channel io = NULL; |
| - | struct test_private_data *data = NULL; |
| - | errcode_t retval; |
| - | char *value; |
| - | |
| - | if (name == 0) |
| - | return EXT2_ET_BAD_DEVICE_NAME; |
| - | retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); |
| - | if (retval) |
| - | return retval; |
| - | memset(io, 0, sizeof(struct struct_io_channel)); |
| - | io->magic = EXT2_ET_MAGIC_IO_CHANNEL; |
| - | retval = ext2fs_get_mem(sizeof(struct test_private_data), &data); |
| - | if (retval) { |
| - | retval = EXT2_ET_NO_MEMORY; |
| - | goto cleanup; |
| - | } |
| - | io->manager = test_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; |
| - | |
| - | memset(data, 0, sizeof(struct test_private_data)); |
| - | data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL; |
| - | if (test_io_backing_manager) { |
| - | retval = test_io_backing_manager->open(name, flags, |
| - | &data->real); |
| - | if (retval) |
| - | goto cleanup; |
| - | } else |
| - | data->real = 0; |
| - | data->read_blk = test_io_cb_read_blk; |
| - | data->write_blk = test_io_cb_write_blk; |
| - | data->set_blksize = test_io_cb_set_blksize; |
| - | data->write_byte = test_io_cb_write_byte; |
| - | |
| - | data->outfile = NULL; |
| - | if ((value = getenv("TEST_IO_LOGFILE")) != NULL) |
| - | data->outfile = fopen_for_write(value); |
| - | if (!data->outfile) |
| - | data->outfile = stderr; |
| - | |
| - | data->flags = 0; |
| - | if ((value = getenv("TEST_IO_FLAGS")) != NULL) |
| - | data->flags = strtoul(value, NULL, 0); |
| - | |
| - | data->block = 0; |
| - | if ((value = getenv("TEST_IO_BLOCK")) != NULL) |
| - | data->block = strtoul(value, NULL, 0); |
| - | |
| - | data->read_abort_count = 0; |
| - | if ((value = getenv("TEST_IO_READ_ABORT")) != NULL) |
| - | data->read_abort_count = strtoul(value, NULL, 0); |
| - | |
| - | data->write_abort_count = 0; |
| - | if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL) |
| - | data->write_abort_count = strtoul(value, NULL, 0); |
| - | |
| - | *channel = io; |
| - | return 0; |
| - | |
| - | cleanup: |
| - | ext2fs_free_mem(&io); |
| - | ext2fs_free_mem(&data); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t test_close(io_channel channel) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | if (--channel->refcount > 0) |
| - | return 0; |
| - | |
| - | if (data->real) |
| - | retval = io_channel_close(data->real); |
| - | |
| - | if (data->outfile && data->outfile != stderr) |
| - | fclose(data->outfile); |
| - | |
| - | ext2fs_free_mem(&channel->private_data); |
| - | ext2fs_free_mem(&channel->name); |
| - | ext2fs_free_mem(&channel); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t test_set_blksize(io_channel channel, int blksize) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | if (data->real) |
| - | retval = io_channel_set_blksize(data->real, blksize); |
| - | if (data->set_blksize) |
| - | data->set_blksize(blksize, retval); |
| - | if (data->flags & TEST_FLAG_SET_BLKSIZE) |
| - | fprintf(data->outfile, |
| - | "Test_io: set_blksize(%d) returned %s\n", |
| - | blksize, retval ? error_message(retval) : "OK"); |
| - | channel->block_size = blksize; |
| - | return retval; |
| - | } |
| - | |
| - | |
| - | static errcode_t test_read_blk(io_channel channel, unsigned long block, |
| - | int count, void *buf) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | if (data->real) |
| - | retval = io_channel_read_blk(data->real, block, count, buf); |
| - | if (data->read_blk) |
| - | data->read_blk(block, count, retval); |
| - | if (data->flags & TEST_FLAG_READ) |
| - | fprintf(data->outfile, |
| - | "Test_io: read_blk(%lu, %d) returned %s\n", |
| - | block, count, retval ? error_message(retval) : "OK"); |
| - | if (data->block && data->block == block) { |
| - | if (data->flags & TEST_FLAG_DUMP) |
| - | test_dump_block(channel, data, block, buf); |
| - | if (--data->read_abort_count == 0) |
| - | test_abort(channel, block); |
| - | } |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t test_write_blk(io_channel channel, unsigned long block, |
| - | int count, const void *buf) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | if (data->real) |
| - | retval = io_channel_write_blk(data->real, block, count, buf); |
| - | if (data->write_blk) |
| - | data->write_blk(block, count, retval); |
| - | if (data->flags & TEST_FLAG_WRITE) |
| - | fprintf(data->outfile, |
| - | "Test_io: write_blk(%lu, %d) returned %s\n", |
| - | block, count, retval ? error_message(retval) : "OK"); |
| - | if (data->block && data->block == block) { |
| - | if (data->flags & TEST_FLAG_DUMP) |
| - | test_dump_block(channel, data, block, buf); |
| - | if (--data->write_abort_count == 0) |
| - | test_abort(channel, block); |
| - | } |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t test_write_byte(io_channel channel, unsigned long offset, |
| - | int count, const void *buf) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | if (data->real && data->real->manager->write_byte) |
| - | retval = io_channel_write_byte(data->real, offset, count, buf); |
| - | if (data->write_byte) |
| - | data->write_byte(offset, count, retval); |
| - | if (data->flags & TEST_FLAG_WRITE) |
| - | fprintf(data->outfile, |
| - | "Test_io: write_byte(%lu, %d) returned %s\n", |
| - | offset, count, retval ? error_message(retval) : "OK"); |
| - | return retval; |
| - | } |
| - | |
| - | /* |
| - | * Flush data buffers to disk. |
| - | */ |
| - | static errcode_t test_flush(io_channel channel) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | if (data->real) |
| - | retval = io_channel_flush(data->real); |
| - | |
| - | if (data->flags & TEST_FLAG_FLUSH) |
| - | fprintf(data->outfile, "Test_io: flush() returned %s\n", |
| - | retval ? error_message(retval) : "OK"); |
| - | |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t test_set_option(io_channel channel, const char *option, |
| - | const char *arg) |
| - | { |
| - | struct test_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct test_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); |
| - | |
| - | |
| - | if (data->flags & TEST_FLAG_SET_OPTION) |
| - | fprintf(data->outfile, "Test_io: set_option(%s, %s) ", |
| - | option, arg); |
| - | if (data->real && data->real->manager->set_option) { |
| - | retval = (data->real->manager->set_option)(data->real, |
| - | option, arg); |
| - | if (data->flags & TEST_FLAG_SET_OPTION) |
| - | fprintf(data->outfile, "returned %s\n", |
| - | retval ? error_message(retval) : "OK"); |
| - | } else { |
| - | if (data->flags & TEST_FLAG_SET_OPTION) |
| - | fprintf(data->outfile, "not implemented\n"); |
| - | } |
| - | return retval; |
| - | } |
| @@ -1,703 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * unix_io.c --- This is the Unix (well, really POSIX) implementation |
| - | * of the I/O manager. |
| - | * |
| - | * Implements a one-block write-through cache. |
| - | * |
| - | * Includes support for Windows NT support under Cygwin. |
| - | * |
| - | * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, |
| - | * 2002 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 |
| - | #if HAVE_ERRNO_H |
| - | #include <errno.h> |
| - | #endif |
| - | #include <fcntl.h> |
| - | #include <time.h> |
| - | #ifdef __linux__ |
| - | #include <sys/utsname.h> |
| - | #endif |
| - | #if HAVE_SYS_STAT_H |
| - | #include <sys/stat.h> |
| - | #endif |
| - | #if HAVE_SYS_TYPES_H |
| - | #include <sys/types.h> |
| - | #endif |
| - | #include <sys/resource.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 unix_cache { |
| - | char *buf; |
| - | unsigned long block; |
| - | int access_time; |
| - | unsigned dirty:1; |
| - | unsigned in_use:1; |
| - | }; |
| - | |
| - | #define CACHE_SIZE 8 |
| - | #define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ |
| - | #define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ |
| - | |
| - | struct unix_private_data { |
| - | int magic; |
| - | int dev; |
| - | int flags; |
| - | int access_time; |
| - | ext2_loff_t offset; |
| - | struct unix_cache cache[CACHE_SIZE]; |
| - | }; |
| - | |
| - | static errcode_t unix_open(const char *name, int flags, io_channel *channel); |
| - | static errcode_t unix_close(io_channel channel); |
| - | static errcode_t unix_set_blksize(io_channel channel, int blksize); |
| - | static errcode_t unix_read_blk(io_channel channel, unsigned long block, |
| - | int count, void *data); |
| - | static errcode_t unix_write_blk(io_channel channel, unsigned long block, |
| - | int count, const void *data); |
| - | static errcode_t unix_flush(io_channel channel); |
| - | static errcode_t unix_write_byte(io_channel channel, unsigned long offset, |
| - | int size, const void *data); |
| - | static errcode_t unix_set_option(io_channel channel, const char *option, |
| - | const char *arg); |
| - | |
| - | static void reuse_cache(io_channel channel, struct unix_private_data *data, |
| - | struct unix_cache *cache, unsigned long block); |
| - | |
| - | /* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel |
| - | * does not know buffered block devices - everything is raw. */ |
| - | #if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
| - | #define NEED_BOUNCE_BUFFER |
| - | #else |
| - | #undef NEED_BOUNCE_BUFFER |
| - | #endif |
| - | |
| - | static struct struct_io_manager struct_unix_manager = { |
| - | EXT2_ET_MAGIC_IO_MANAGER, |
| - | "Unix I/O Manager", |
| - | unix_open, |
| - | unix_close, |
| - | unix_set_blksize, |
| - | unix_read_blk, |
| - | unix_write_blk, |
| - | unix_flush, |
| - | #ifdef NEED_BOUNCE_BUFFER |
| - | 0, |
| - | #else |
| - | unix_write_byte, |
| - | #endif |
| - | unix_set_option |
| - | }; |
| - | |
| - | io_manager unix_io_manager = &struct_unix_manager; |
| - | |
| - | /* |
| - | * Here are the raw I/O functions |
| - | */ |
| - | #ifndef NEED_BOUNCE_BUFFER |
| - | static errcode_t raw_read_blk(io_channel channel, |
| - | struct unix_private_data *data, |
| - | unsigned long block, |
| - | int count, void *buf) |
| - | { |
| - | errcode_t retval; |
| - | ssize_t size; |
| - | ext2_loff_t location; |
| - | int actual = 0; |
| - | |
| - | size = (count < 0) ? -count : count * channel->block_size; |
| - | location = ((ext2_loff_t) block * channel->block_size) + data->offset; |
| - | if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { |
| - | retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; |
| - | goto error_out; |
| - | } |
| - | actual = read(data->dev, buf, size); |
| - | if (actual != size) { |
| - | if (actual < 0) |
| - | actual = 0; |
| - | retval = EXT2_ET_SHORT_READ; |
| - | goto error_out; |
| - | } |
| - | return 0; |
| - | |
| - | error_out: |
| - | memset((char *) buf+actual, 0, size-actual); |
| - | if (channel->read_error) |
| - | retval = (channel->read_error)(channel, block, count, buf, |
| - | size, actual, retval); |
| - | return retval; |
| - | } |
| - | #else /* NEED_BOUNCE_BUFFER */ |
| - | /* |
| - | * Windows and FreeBSD block devices only allow sector alignment IO in offset and size |
| - | */ |
| - | static errcode_t raw_read_blk(io_channel channel, |
| - | struct unix_private_data *data, |
| - | unsigned long block, |
| - | int count, void *buf) |
| - | { |
| - | errcode_t retval; |
| - | size_t size, alignsize, fragment; |
| - | ext2_loff_t location; |
| - | int total = 0, actual; |
| - | #define BLOCKALIGN 512 |
| - | char sector[BLOCKALIGN]; |
| - | |
| - | size = (count < 0) ? -count : count * channel->block_size; |
| - | location = ((ext2_loff_t) block * channel->block_size) + data->offset; |
| - | #ifdef DEBUG |
| - | printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n", |
| - | count, size, block, channel->block_size, location); |
| - | #endif |
| - | if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { |
| - | retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; |
| - | goto error_out; |
| - | } |
| - | fragment = size % BLOCKALIGN; |
| - | alignsize = size - fragment; |
| - | if (alignsize) { |
| - | actual = read(data->dev, buf, alignsize); |
| - | if (actual != alignsize) |
| - | goto short_read; |
| - | } |
| - | if (fragment) { |
| - | actual = read(data->dev, sector, BLOCKALIGN); |
| - | if (actual != BLOCKALIGN) |
| - | goto short_read; |
| - | memcpy(buf+alignsize, sector, fragment); |
| - | } |
| - | return 0; |
| - | |
| - | short_read: |
| - | if (actual>0) |
| - | total += actual; |
| - | retval = EXT2_ET_SHORT_READ; |
| - | |
| - | error_out: |
| - | memset((char *) buf+total, 0, size-actual); |
| - | if (channel->read_error) |
| - | retval = (channel->read_error)(channel, block, count, buf, |
| - | size, actual, retval); |
| - | return retval; |
| - | } |
| - | #endif |
| - | |
| - | static errcode_t raw_write_blk(io_channel channel, |
| - | struct unix_private_data *data, |
| - | unsigned long block, |
| - | int count, const void *buf) |
| - | { |
| - | ssize_t size; |
| - | ext2_loff_t location; |
| - | int actual = 0; |
| - | errcode_t retval; |
| - | |
| - | if (count == 1) |
| - | size = channel->block_size; |
| - | else { |
| - | if (count < 0) |
| - | size = -count; |
| - | else |
| - | size = count * channel->block_size; |
| - | } |
| - | |
| - | location = ((ext2_loff_t) block * channel->block_size) + data->offset; |
| - | if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { |
| - | retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; |
| - | goto error_out; |
| - | } |
| - | |
| - | actual = write(data->dev, buf, size); |
| - | if (actual != size) { |
| - | retval = EXT2_ET_SHORT_WRITE; |
| - | goto error_out; |
| - | } |
| - | return 0; |
| - | |
| - | error_out: |
| - | if (channel->write_error) |
| - | retval = (channel->write_error)(channel, block, count, buf, |
| - | size, actual, retval); |
| - | return retval; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Here we implement the cache functions |
| - | */ |
| - | |
| - | /* Allocate the cache buffers */ |
| - | static errcode_t alloc_cache(io_channel channel, |
| - | struct unix_private_data *data) |
| - | { |
| - | errcode_t retval; |
| - | struct unix_cache *cache; |
| - | int i; |
| - | |
| - | data->access_time = 0; |
| - | for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { |
| - | cache->block = 0; |
| - | cache->access_time = 0; |
| - | cache->dirty = 0; |
| - | cache->in_use = 0; |
| - | if ((retval = ext2fs_get_mem(channel->block_size, |
| - | &cache->buf))) |
| - | return retval; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* Free the cache buffers */ |
| - | static void free_cache(struct unix_private_data *data) |
| - | { |
| - | struct unix_cache *cache; |
| - | int i; |
| - | |
| - | data->access_time = 0; |
| - | for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { |
| - | cache->block = 0; |
| - | cache->access_time = 0; |
| - | cache->dirty = 0; |
| - | cache->in_use = 0; |
| - | ext2fs_free_mem(&cache->buf); |
| - | cache->buf = 0; |
| - | } |
| - | } |
| - | |
| - | #ifndef NO_IO_CACHE |
| - | /* |
| - | * Try to find a block in the cache. If the block is not found, and |
| - | * eldest is a non-zero pointer, then fill in eldest with the cache |
| - | * entry to that should be reused. |
| - | */ |
| - | static struct unix_cache *find_cached_block(struct unix_private_data *data, |
| - | unsigned long block, |
| - | struct unix_cache **eldest) |
| - | { |
| - | struct unix_cache *cache, *unused_cache, *oldest_cache; |
| - | int i; |
| - | |
| - | unused_cache = oldest_cache = 0; |
| - | for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { |
| - | if (!cache->in_use) { |
| - | if (!unused_cache) |
| - | unused_cache = cache; |
| - | continue; |
| - | } |
| - | if (cache->block == block) { |
| - | cache->access_time = ++data->access_time; |
| - | return cache; |
| - | } |
| - | if (!oldest_cache || |
| - | (cache->access_time < oldest_cache->access_time)) |
| - | oldest_cache = cache; |
| - | } |
| - | if (eldest) |
| - | *eldest = (unused_cache) ? unused_cache : oldest_cache; |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Reuse a particular cache entry for another block. |
| - | */ |
| - | static void reuse_cache(io_channel channel, struct unix_private_data *data, |
| - | struct unix_cache *cache, unsigned long block) |
| - | { |
| - | if (cache->dirty && cache->in_use) |
| - | raw_write_blk(channel, data, cache->block, 1, cache->buf); |
| - | |
| - | cache->in_use = 1; |
| - | cache->dirty = 0; |
| - | cache->block = block; |
| - | cache->access_time = ++data->access_time; |
| - | } |
| - | |
| - | /* |
| - | * Flush all of the blocks in the cache |
| - | */ |
| - | static errcode_t flush_cached_blocks(io_channel channel, |
| - | struct unix_private_data *data, |
| - | int invalidate) |
| - | |
| - | { |
| - | struct unix_cache *cache; |
| - | errcode_t retval, retval2; |
| - | int i; |
| - | |
| - | retval2 = 0; |
| - | for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { |
| - | if (!cache->in_use) |
| - | continue; |
| - | |
| - | if (invalidate) |
| - | cache->in_use = 0; |
| - | |
| - | if (!cache->dirty) |
| - | continue; |
| - | |
| - | retval = raw_write_blk(channel, data, |
| - | cache->block, 1, cache->buf); |
| - | if (retval) |
| - | retval2 = retval; |
| - | else |
| - | cache->dirty = 0; |
| - | } |
| - | return retval2; |
| - | } |
| - | #endif /* NO_IO_CACHE */ |
| - | |
| - | static errcode_t unix_open(const char *name, int flags, io_channel *channel) |
| - | { |
| - | io_channel io = NULL; |
| - | struct unix_private_data *data = NULL; |
| - | errcode_t retval; |
| - | int open_flags; |
| - | struct stat st; |
| - | #ifdef __linux__ |
| - | struct utsname ut; |
| - | #endif |
| - | |
| - | if (name == 0) |
| - | return EXT2_ET_BAD_DEVICE_NAME; |
| - | retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); |
| - | if (retval) |
| - | return retval; |
| - | memset(io, 0, sizeof(struct struct_io_channel)); |
| - | io->magic = EXT2_ET_MAGIC_IO_CHANNEL; |
| - | retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); |
| - | if (retval) |
| - | goto cleanup; |
| - | |
| - | io->manager = unix_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; |
| - | |
| - | memset(data, 0, sizeof(struct unix_private_data)); |
| - | data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; |
| - | |
| - | if ((retval = alloc_cache(io, data))) |
| - | goto cleanup; |
| - | |
| - | open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; |
| - | #ifdef CONFIG_LFS |
| - | data->dev = open64(io->name, open_flags); |
| - | #else |
| - | data->dev = open(io->name, open_flags); |
| - | #endif |
| - | if (data->dev < 0) { |
| - | retval = errno; |
| - | goto cleanup; |
| - | } |
| - | |
| - | #ifdef __linux__ |
| - | #undef RLIM_INFINITY |
| - | #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) |
| - | #define RLIM_INFINITY ((unsigned long)(~0UL>>1)) |
| - | #else |
| - | #define RLIM_INFINITY (~0UL) |
| - | #endif |
| - | /* |
| - | * Work around a bug in 2.4.10-2.4.18 kernels where writes to |
| - | * block devices are wrongly getting hit by the filesize |
| - | * limit. This workaround isn't perfect, since it won't work |
| - | * if glibc wasn't built against 2.2 header files. (Sigh.) |
| - | * |
| - | */ |
| - | if ((flags & IO_FLAG_RW) && |
| - | (uname(&ut) == 0) && |
| - | ((ut.release[0] == '2') && (ut.release[1] == '.') && |
| - | (ut.release[2] == '4') && (ut.release[3] == '.') && |
| - | (ut.release[4] == '1') && (ut.release[5] >= '0') && |
| - | (ut.release[5] < '8')) && |
| - | (fstat(data->dev, &st) == 0) && |
| - | (S_ISBLK(st.st_mode))) { |
| - | struct rlimit rlim; |
| - | |
| - | rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; |
| - | setrlimit(RLIMIT_FSIZE, &rlim); |
| - | getrlimit(RLIMIT_FSIZE, &rlim); |
| - | if (((unsigned long) rlim.rlim_cur) < |
| - | ((unsigned long) rlim.rlim_max)) { |
| - | rlim.rlim_cur = rlim.rlim_max; |
| - | setrlimit(RLIMIT_FSIZE, &rlim); |
| - | } |
| - | } |
| - | #endif |
| - | *channel = io; |
| - | return 0; |
| - | |
| - | cleanup: |
| - | if (data) { |
| - | free_cache(data); |
| - | ext2fs_free_mem(&data); |
| - | } |
| - | ext2fs_free_mem(&io); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t unix_close(io_channel channel) |
| - | { |
| - | struct unix_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | if (--channel->refcount > 0) |
| - | return 0; |
| - | |
| - | #ifndef NO_IO_CACHE |
| - | retval = flush_cached_blocks(channel, data, 0); |
| - | #endif |
| - | |
| - | if (close(data->dev) < 0) |
| - | retval = errno; |
| - | free_cache(data); |
| - | |
| - | ext2fs_free_mem(&channel->private_data); |
| - | ext2fs_free_mem(&channel->name); |
| - | ext2fs_free_mem(&channel); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t unix_set_blksize(io_channel channel, int blksize) |
| - | { |
| - | struct unix_private_data *data; |
| - | errcode_t retval; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | if (channel->block_size != blksize) { |
| - | #ifndef NO_IO_CACHE |
| - | if ((retval = flush_cached_blocks(channel, data, 0))) |
| - | return retval; |
| - | #endif |
| - | |
| - | channel->block_size = blksize; |
| - | free_cache(data); |
| - | if ((retval = alloc_cache(channel, data))) |
| - | return retval; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | |
| - | static errcode_t unix_read_blk(io_channel channel, unsigned long block, |
| - | int count, void *buf) |
| - | { |
| - | struct unix_private_data *data; |
| - | struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; |
| - | errcode_t retval; |
| - | char *cp; |
| - | int i, j; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | #ifdef NO_IO_CACHE |
| - | return raw_read_blk(channel, data, block, count, buf); |
| - | #else |
| - | /* |
| - | * If we're doing an odd-sized read or a very large read, |
| - | * flush out the cache and then do a direct read. |
| - | */ |
| - | if (count < 0 || count > WRITE_DIRECT_SIZE) { |
| - | if ((retval = flush_cached_blocks(channel, data, 0))) |
| - | return retval; |
| - | return raw_read_blk(channel, data, block, count, buf); |
| - | } |
| - | |
| - | cp = buf; |
| - | while (count > 0) { |
| - | /* If it's in the cache, use it! */ |
| - | if ((cache = find_cached_block(data, block, &reuse[0]))) { |
| - | #ifdef DEBUG |
| - | printf("Using cached block %lu\n", block); |
| - | #endif |
| - | memcpy(cp, cache->buf, channel->block_size); |
| - | count--; |
| - | block++; |
| - | cp += channel->block_size; |
| - | continue; |
| - | } |
| - | /* |
| - | * Find the number of uncached blocks so we can do a |
| - | * single read request |
| - | */ |
| - | for (i=1; i < count; i++) |
| - | if (find_cached_block(data, block+i, &reuse[i])) |
| - | break; |
| - | #ifdef DEBUG |
| - | printf("Reading %d blocks starting at %lu\n", i, block); |
| - | #endif |
| - | if ((retval = raw_read_blk(channel, data, block, i, cp))) |
| - | return retval; |
| - | |
| - | /* Save the results in the cache */ |
| - | for (j=0; j < i; j++) { |
| - | count--; |
| - | cache = reuse[j]; |
| - | reuse_cache(channel, data, cache, block++); |
| - | memcpy(cache->buf, cp, channel->block_size); |
| - | cp += channel->block_size; |
| - | } |
| - | } |
| - | return 0; |
| - | #endif /* NO_IO_CACHE */ |
| - | } |
| - | |
| - | static errcode_t unix_write_blk(io_channel channel, unsigned long block, |
| - | int count, const void *buf) |
| - | { |
| - | struct unix_private_data *data; |
| - | struct unix_cache *cache, *reuse; |
| - | errcode_t retval = 0; |
| - | const char *cp; |
| - | int writethrough; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | #ifdef NO_IO_CACHE |
| - | return raw_write_blk(channel, data, block, count, buf); |
| - | #else |
| - | /* |
| - | * If we're doing an odd-sized write or a very large write, |
| - | * flush out the cache completely and then do a direct write. |
| - | */ |
| - | if (count < 0 || count > WRITE_DIRECT_SIZE) { |
| - | if ((retval = flush_cached_blocks(channel, data, 1))) |
| - | return retval; |
| - | return raw_write_blk(channel, data, block, count, buf); |
| - | } |
| - | |
| - | /* |
| - | * For a moderate-sized multi-block write, first force a write |
| - | * if we're in write-through cache mode, and then fill the |
| - | * cache with the blocks. |
| - | */ |
| - | writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; |
| - | if (writethrough) |
| - | retval = raw_write_blk(channel, data, block, count, buf); |
| - | |
| - | cp = buf; |
| - | while (count > 0) { |
| - | cache = find_cached_block(data, block, &reuse); |
| - | if (!cache) { |
| - | cache = reuse; |
| - | reuse_cache(channel, data, cache, block); |
| - | } |
| - | memcpy(cache->buf, cp, channel->block_size); |
| - | cache->dirty = !writethrough; |
| - | count--; |
| - | block++; |
| - | cp += channel->block_size; |
| - | } |
| - | return retval; |
| - | #endif /* NO_IO_CACHE */ |
| - | } |
| - | |
| - | static errcode_t unix_write_byte(io_channel channel, unsigned long offset, |
| - | int size, const void *buf) |
| - | { |
| - | struct unix_private_data *data; |
| - | errcode_t retval = 0; |
| - | ssize_t actual; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | #ifndef NO_IO_CACHE |
| - | /* |
| - | * Flush out the cache completely |
| - | */ |
| - | if ((retval = flush_cached_blocks(channel, data, 1))) |
| - | return retval; |
| - | #endif |
| - | |
| - | if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) |
| - | return errno; |
| - | |
| - | actual = write(data->dev, buf, size); |
| - | if (actual != size) |
| - | return EXT2_ET_SHORT_WRITE; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Flush data buffers to disk. |
| - | */ |
| - | static errcode_t unix_flush(io_channel channel) |
| - | { |
| - | struct unix_private_data *data; |
| - | errcode_t retval = 0; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | #ifndef NO_IO_CACHE |
| - | retval = flush_cached_blocks(channel, data, 0); |
| - | #endif |
| - | fsync(data->dev); |
| - | return retval; |
| - | } |
| - | |
| - | static errcode_t unix_set_option(io_channel channel, const char *option, |
| - | const char *arg) |
| - | { |
| - | struct unix_private_data *data; |
| - | unsigned long tmp; |
| - | char *end; |
| - | |
| - | EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); |
| - | data = (struct unix_private_data *) channel->private_data; |
| - | EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); |
| - | |
| - | if (!strcmp(option, "offset")) { |
| - | if (!arg) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | |
| - | tmp = strtoul(arg, &end, 0); |
| - | if (*end) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | data->offset = tmp; |
| - | return 0; |
| - | } |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | } |
| @@ -1,99 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * unlink.c --- delete links in a ext2fs directory |
| - | * |
| - | * Copyright (C) 1993, 1994, 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 link_struct { |
| - | const char *name; |
| - | int namelen; |
| - | ext2_ino_t inode; |
| - | int flags; |
| - | struct ext2_dir_entry *prev; |
| - | int done; |
| - | }; |
| - | |
| - | #ifdef __TURBOC__ |
| - | # pragma argsused |
| - | #endif |
| - | static int unlink_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 link_struct *ls = (struct link_struct *) priv_data; |
| - | struct ext2_dir_entry *prev; |
| - | |
| - | prev = ls->prev; |
| - | ls->prev = dirent; |
| - | |
| - | if (ls->name) { |
| - | if ((dirent->name_len & 0xFF) != ls->namelen) |
| - | return 0; |
| - | if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF)) |
| - | return 0; |
| - | } |
| - | if (ls->inode) { |
| - | if (dirent->inode != ls->inode) |
| - | return 0; |
| - | } else { |
| - | if (!dirent->inode) |
| - | return 0; |
| - | } |
| - | |
| - | if (prev) |
| - | prev->rec_len += dirent->rec_len; |
| - | else |
| - | dirent->inode = 0; |
| - | ls->done++; |
| - | return DIRENT_ABORT|DIRENT_CHANGED; |
| - | } |
| - | |
| - | #ifdef __TURBOC__ |
| - | #pragma argsused |
| - | #endif |
| - | errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, |
| - | const char *name, ext2_ino_t ino, |
| - | int flags EXT2FS_ATTR((unused))) |
| - | { |
| - | errcode_t retval; |
| - | struct link_struct ls; |
| - | |
| - | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| - | |
| - | if (!name && !ino) |
| - | return EXT2_ET_INVALID_ARGUMENT; |
| - | |
| - | 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 = 0; |
| - | ls.done = 0; |
| - | ls.prev = 0; |
| - | |
| - | retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, |
| - | 0, unlink_proc, &ls); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE; |
| - | } |
| @@ -1,57 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * valid_blk.c --- does the inode have valid blocks? |
| - | * |
| - | * 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 "ext2fs.h" |
| - | |
| - | /* |
| - | * This function returns 1 if the inode's block entries actually |
| - | * contain block entries. |
| - | */ |
| - | int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode) |
| - | { |
| - | /* |
| - | * Only directories, regular files, and some symbolic links |
| - | * have valid block entries. |
| - | */ |
| - | if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) && |
| - | !LINUX_S_ISLNK(inode->i_mode)) |
| - | return 0; |
| - | |
| - | /* |
| - | * If the symbolic link is a "fast symlink", then the symlink |
| - | * target is stored in the block entries. |
| - | */ |
| - | if (LINUX_S_ISLNK (inode->i_mode)) { |
| - | if (inode->i_file_acl == 0) { |
| - | /* With no EA block, we can rely on i_blocks */ |
| - | if (inode->i_blocks == 0) |
| - | return 0; |
| - | } else { |
| - | /* With an EA block, life gets more tricky */ |
| - | if (inode->i_size >= EXT2_N_BLOCKS*4) |
| - | return 1; /* definitely using i_block[] */ |
| - | if (inode->i_size > 4 && inode->i_block[1] == 0) |
| - | return 1; /* definitely using i_block[] */ |
| - | return 0; /* Probably a fast symlink */ |
| - | } |
| - | } |
| - | return 1; |
| - | } |
| @@ -1,51 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * version.c --- Return the version of the 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% |
| - | */ |
| - | |
| - | #if HAVE_UNISTD_H |
| - | #include <unistd.h> |
| - | #endif |
| - | #include <string.h> |
| - | #include <stdio.h> |
| - | #include <ctype.h> |
| - | |
| - | #include "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | |
| - | static const char *lib_version = E2FSPROGS_VERSION; |
| - | static const char *lib_date = E2FSPROGS_DATE; |
| - | |
| - | int ext2fs_parse_version_string(const char *ver_string) |
| - | { |
| - | const char *cp; |
| - | int version = 0; |
| - | |
| - | for (cp = ver_string; *cp; cp++) { |
| - | if (*cp == '.') |
| - | continue; |
| - | if (!isdigit(*cp)) |
| - | break; |
| - | version = (version * 10) + (*cp - '0'); |
| - | } |
| - | return version; |
| - | } |
| - | |
| - | |
| - | int ext2fs_get_library_version(const char **ver_string, |
| - | const char **date_string) |
| - | { |
| - | if (ver_string) |
| - | *ver_string = lib_version; |
| - | if (date_string) |
| - | *date_string = lib_date; |
| - | |
| - | return ext2fs_parse_version_string(lib_version); |
| - | } |
| @@ -1,35 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * write_bb_file.c --- write a list of bad blocks to a FILE * |
| - | * |
| - | * 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 "ext2_fs.h" |
| - | #include "ext2fs.h" |
| - | |
| - | errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, |
| - | unsigned int flags EXT2FS_ATTR((unused)), |
| - | FILE *f) |
| - | { |
| - | badblocks_iterate bb_iter; |
| - | blk_t blk; |
| - | errcode_t retval; |
| - | |
| - | retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter); |
| - | if (retval) |
| - | return retval; |
| - | |
| - | while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) { |
| - | fprintf(f, "%d\n", blk); |
| - | } |
| - | ext2fs_badblocks_list_iterate_end(bb_iter); |
| - | return 0; |
| - | } |
| @@ -1,1371 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * pfsck --- A generic, parallelizing front-end for the fsck program. |
| - | * It will automatically try to run fsck programs in parallel if the |
| - | * devices are on separate spindles. It is based on the same ideas as |
| - | * the generic front end for fsck by David Engel and Fred van Kempen, |
| - | * but it has been completely rewritten from scratch to support |
| - | * parallel execution. |
| - | * |
| - | * Written by Theodore Ts'o, <[email protected]> |
| - | * |
| - | * Miquel van Smoorenburg ([email protected]) 20-Oct-1994: |
| - | * o Changed -t fstype to behave like with mount when -A (all file |
| - | * systems) or -M (like mount) is specified. |
| - | * o fsck looks if it can find the fsck.type program to decide |
| - | * if it should ignore the fs type. This way more fsck programs |
| - | * can be added without changing this front-end. |
| - | * o -R flag skip root file system. |
| - | * |
| - | * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
| - | * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. |
| - | * |
| - | * Licensed under GPLv2, see file LICENSE in this source tree. |
| - | */ |
| - | |
| - | #include <sys/types.h> |
| - | #include <sys/wait.h> |
| - | #include <sys/stat.h> |
| - | #include <limits.h> |
| - | #include <stdio.h> |
| - | #include <ctype.h> |
| - | #include <string.h> |
| - | #include <time.h> |
| - | #include <stdlib.h> |
| - | #include <errno.h> |
| - | #include <paths.h> |
| - | #include <unistd.h> |
| - | #include <errno.h> |
| - | #include <signal.h> |
| - | |
| - | #include "fsck.h" |
| - | #include "blkid/blkid.h" |
| - | |
| - | #include "e2fsbb.h" |
| - | |
| - | #include "libbb.h" |
| - | |
| - | #ifndef _PATH_MNTTAB |
| - | #define _PATH_MNTTAB "/etc/fstab" |
| - | #endif |
| - | |
| - | /* |
| - | * fsck.h |
| - | */ |
| - | |
| - | #ifndef DEFAULT_FSTYPE |
| - | #define DEFAULT_FSTYPE "ext2" |
| - | #endif |
| - | |
| - | #define MAX_DEVICES 32 |
| - | #define MAX_ARGS 32 |
| - | |
| - | /* |
| - | * Internal structure for mount tabel entries. |
| - | */ |
| - | |
| - | struct fs_info { |
| - | char *device; |
| - | char *mountpt; |
| - | char *type; |
| - | char *opts; |
| - | int freq; |
| - | int passno; |
| - | int flags; |
| - | struct fs_info *next; |
| - | }; |
| - | |
| - | #define FLAG_DONE 1 |
| - | #define FLAG_PROGRESS 2 |
| - | |
| - | /* |
| - | * Structure to allow exit codes to be stored |
| - | */ |
| - | struct fsck_instance { |
| - | int pid; |
| - | int flags; |
| - | int exit_status; |
| - | time_t start_time; |
| - | char * prog; |
| - | char * type; |
| - | char * device; |
| - | char * base_device; |
| - | struct fsck_instance *next; |
| - | }; |
| - | |
| - | /* |
| - | * base_device.c |
| - | * |
| - | * Return the "base device" given a particular device; this is used to |
| - | * assure that we only fsck one partition on a particular drive at any |
| - | * one time. Otherwise, the disk heads will be seeking all over the |
| - | * place. If the base device cannot be determined, return NULL. |
| - | * |
| - | * The base_device() function returns an allocated string which must |
| - | * be freed. |
| - | * |
| - | */ |
| - | |
| - | |
| - | #ifdef CONFIG_FEATURE_DEVFS |
| - | /* |
| - | * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3 |
| - | * pathames. |
| - | */ |
| - | static const char *const devfs_hier[] = { |
| - | "host", "bus", "target", "lun", 0 |
| - | }; |
| - | #endif |
| - | |
| - | static char *base_device(const char *device) |
| - | { |
| - | char *str, *cp; |
| - | #ifdef CONFIG_FEATURE_DEVFS |
| - | const char *const *hier; |
| - | const char *disk; |
| - | int len; |
| - | #endif |
| - | |
| - | cp = str = xstrdup(device); |
| - | |
| - | /* Skip over /dev/; if it's not present, give up. */ |
| - | if (strncmp(cp, "/dev/", 5) != 0) |
| - | goto errout; |
| - | cp += 5; |
| - | |
| - | /* |
| - | * For md devices, we treat them all as if they were all |
| - | * on one disk, since we don't know how to parallelize them. |
| - | */ |
| - | if (cp[0] == 'm' && cp[1] == 'd') { |
| - | *(cp+2) = 0; |
| - | return str; |
| - | } |
| - | |
| - | /* Handle DAC 960 devices */ |
| - | if (strncmp(cp, "rd/", 3) == 0) { |
| - | cp += 3; |
| - | if (cp[0] != 'c' || cp[2] != 'd' || |
| - | !isdigit(cp[1]) || !isdigit(cp[3])) |
| - | goto errout; |
| - | *(cp+4) = 0; |
| - | return str; |
| - | } |
| - | |
| - | /* Now let's handle /dev/hd* and /dev/sd* devices.... */ |
| - | if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) { |
| - | cp += 2; |
| - | /* If there's a single number after /dev/hd, skip it */ |
| - | if (isdigit(*cp)) |
| - | cp++; |
| - | /* What follows must be an alpha char, or give up */ |
| - | if (!isalpha(*cp)) |
| - | goto errout; |
| - | *(cp + 1) = 0; |
| - | return str; |
| - | } |
| - | |
| - | #ifdef CONFIG_FEATURE_DEVFS |
| - | /* Now let's handle devfs (ugh) names */ |
| - | len = 0; |
| - | if (strncmp(cp, "ide/", 4) == 0) |
| - | len = 4; |
| - | if (strncmp(cp, "scsi/", 5) == 0) |
| - | len = 5; |
| - | if (len) { |
| - | cp += len; |
| - | /* |
| - | * Now we proceed down the expected devfs hierarchy. |
| - | * i.e., .../host1/bus2/target3/lun4/... |
| - | * If we don't find the expected token, followed by |
| - | * some number of digits at each level, abort. |
| - | */ |
| - | for (hier = devfs_hier; *hier; hier++) { |
| - | len = strlen(*hier); |
| - | if (strncmp(cp, *hier, len) != 0) |
| - | goto errout; |
| - | cp += len; |
| - | while (*cp != '/' && *cp != 0) { |
| - | if (!isdigit(*cp)) |
| - | goto errout; |
| - | cp++; |
| - | } |
| - | cp++; |
| - | } |
| - | *(cp - 1) = 0; |
| - | return str; |
| - | } |
| - | |
| - | /* Now handle devfs /dev/disc or /dev/disk names */ |
| - | disk = 0; |
| - | if (strncmp(cp, "discs/", 6) == 0) |
| - | disk = "disc"; |
| - | else if (strncmp(cp, "disks/", 6) == 0) |
| - | disk = "disk"; |
| - | if (disk) { |
| - | cp += 6; |
| - | if (strncmp(cp, disk, 4) != 0) |
| - | goto errout; |
| - | cp += 4; |
| - | while (*cp != '/' && *cp != 0) { |
| - | if (!isdigit(*cp)) |
| - | goto errout; |
| - | cp++; |
| - | } |
| - | *cp = 0; |
| - | return str; |
| - | } |
| - | #endif |
| - | |
| - | errout: |
| - | free(str); |
| - | return NULL; |
| - | } |
| - | |
| - | |
| - | static const char *const ignored_types[] = { |
| - | "ignore", |
| - | "iso9660", |
| - | "nfs", |
| - | "proc", |
| - | "sw", |
| - | "swap", |
| - | "tmpfs", |
| - | "devpts", |
| - | NULL |
| - | }; |
| - | |
| - | static const char *const really_wanted[] = { |
| - | "minix", |
| - | "ext2", |
| - | "ext3", |
| - | "jfs", |
| - | "reiserfs", |
| - | "xiafs", |
| - | "xfs", |
| - | NULL |
| - | }; |
| - | |
| - | #define BASE_MD "/dev/md" |
| - | |
| - | /* |
| - | * Global variables for options |
| - | */ |
| - | static char *devices[MAX_DEVICES]; |
| - | static char *args[MAX_ARGS]; |
| - | static int num_devices, num_args; |
| - | |
| - | static int verbose; |
| - | static int doall; |
| - | static int noexecute; |
| - | static int serialize; |
| - | static int skip_root; |
| - | static int like_mount; |
| - | static int notitle; |
| - | static int parallel_root; |
| - | static int progress; |
| - | static int progress_fd; |
| - | static int force_all_parallel; |
| - | static int num_running; |
| - | static int max_running; |
| - | static volatile int cancel_requested; |
| - | static int kill_sent; |
| - | static char *fstype; |
| - | static struct fs_info *filesys_info, *filesys_last; |
| - | static struct fsck_instance *instance_list; |
| - | static char *fsck_path; |
| - | static blkid_cache cache; |
| - | |
| - | static char *string_copy(const char *s) |
| - | { |
| - | char *ret; |
| - | |
| - | if (!s) |
| - | return 0; |
| - | ret = xstrdup(s); |
| - | return ret; |
| - | } |
| - | |
| - | static int string_to_int(const char *s) |
| - | { |
| - | long l; |
| - | char *p; |
| - | |
| - | l = strtol(s, &p, 0); |
| - | if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX) |
| - | return -1; |
| - | else |
| - | return (int) l; |
| - | } |
| - | |
| - | static char *skip_over_blank(char *cp) |
| - | { |
| - | while (*cp && isspace(*cp)) |
| - | cp++; |
| - | return cp; |
| - | } |
| - | |
| - | static char *skip_over_word(char *cp) |
| - | { |
| - | while (*cp && !isspace(*cp)) |
| - | cp++; |
| - | return cp; |
| - | } |
| - | |
| - | static void strip_line(char *line) |
| - | { |
| - | char *p; |
| - | |
| - | while (*line) { |
| - | p = line + strlen(line) - 1; |
| - | if ((*p == '\n') || (*p == '\r')) |
| - | *p = 0; |
| - | else |
| - | break; |
| - | } |
| - | } |
| - | |
| - | static char *parse_word(char **buf) |
| - | { |
| - | char *word, *next; |
| - | |
| - | word = *buf; |
| - | if (*word == 0) |
| - | return 0; |
| - | |
| - | word = skip_over_blank(word); |
| - | next = skip_over_word(word); |
| - | if (*next) |
| - | *next++ = 0; |
| - | *buf = next; |
| - | return word; |
| - | } |
| - | |
| - | static void parse_escape(char *word) |
| - | { |
| - | char *q, c; |
| - | const char *p; |
| - | |
| - | if (!word) |
| - | return; |
| - | |
| - | strcpy_and_process_escape_sequences(word, word); |
| - | } |
| - | |
| - | static void free_instance(struct fsck_instance *i) |
| - | { |
| - | free(i->prog); |
| - | free(i->device); |
| - | free(i->base_device); |
| - | free(i); |
| - | } |
| - | |
| - | static struct fs_info *create_fs_device(const char *device, const char *mntpnt, |
| - | const char *type, const char *opts, |
| - | int freq, int passno) |
| - | { |
| - | struct fs_info *fs; |
| - | |
| - | fs = xmalloc(sizeof(struct fs_info)); |
| - | |
| - | fs->device = string_copy(device); |
| - | fs->mountpt = string_copy(mntpnt); |
| - | fs->type = string_copy(type); |
| - | fs->opts = string_copy(opts ? opts : ""); |
| - | fs->freq = freq; |
| - | fs->passno = passno; |
| - | fs->flags = 0; |
| - | fs->next = NULL; |
| - | |
| - | if (!filesys_info) |
| - | filesys_info = fs; |
| - | else |
| - | filesys_last->next = fs; |
| - | filesys_last = fs; |
| - | |
| - | return fs; |
| - | } |
| - | |
| - | |
| - | |
| - | static int parse_fstab_line(char *line, struct fs_info **ret_fs) |
| - | { |
| - | char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp; |
| - | struct fs_info *fs; |
| - | |
| - | *ret_fs = 0; |
| - | strip_line(line); |
| - | if ((cp = strchr(line, '#'))) |
| - | *cp = 0; /* Ignore everything after the comment char */ |
| - | cp = line; |
| - | |
| - | device = parse_word(&cp); |
| - | mntpnt = parse_word(&cp); |
| - | type = parse_word(&cp); |
| - | opts = parse_word(&cp); |
| - | freq = parse_word(&cp); |
| - | passno = parse_word(&cp); |
| - | |
| - | if (!device) |
| - | return 0; /* Allow blank lines */ |
| - | |
| - | if (!mntpnt || !type) |
| - | return -1; |
| - | |
| - | parse_escape(device); |
| - | parse_escape(mntpnt); |
| - | parse_escape(type); |
| - | parse_escape(opts); |
| - | parse_escape(freq); |
| - | parse_escape(passno); |
| - | |
| - | dev = blkid_get_devname(cache, device, NULL); |
| - | if (dev) |
| - | device = dev; |
| - | |
| - | if (strchr(type, ',')) |
| - | type = 0; |
| - | |
| - | fs = create_fs_device(device, mntpnt, type ? type : "auto", opts, |
| - | freq ? atoi(freq) : -1, |
| - | passno ? atoi(passno) : -1); |
| - | free(dev); |
| - | |
| - | if (!fs) |
| - | return -1; |
| - | *ret_fs = fs; |
| - | return 0; |
| - | } |
| - | |
| - | static void interpret_type(struct fs_info *fs) |
| - | { |
| - | char *t; |
| - | |
| - | if (strcmp(fs->type, "auto") != 0) |
| - | return; |
| - | t = blkid_get_tag_value(cache, "TYPE", fs->device); |
| - | if (t) { |
| - | free(fs->type); |
| - | fs->type = t; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Load the filesystem database from /etc/fstab |
| - | */ |
| - | static void load_fs_info(const char *filename) |
| - | { |
| - | FILE *f; |
| - | char buf[1024]; |
| - | int lineno = 0; |
| - | int old_fstab = 1; |
| - | struct fs_info *fs; |
| - | |
| - | if ((f = fopen_or_warn(filename, "r")) == NULL) { |
| - | return; |
| - | } |
| - | while (!feof(f)) { |
| - | lineno++; |
| - | if (!fgets(buf, sizeof(buf), f)) |
| - | break; |
| - | buf[sizeof(buf)-1] = 0; |
| - | if (parse_fstab_line(buf, &fs) < 0) { |
| - | bb_error_msg("WARNING: bad format " |
| - | "on line %d of %s\n", lineno, filename); |
| - | continue; |
| - | } |
| - | if (!fs) |
| - | continue; |
| - | if (fs->passno < 0) |
| - | fs->passno = 0; |
| - | else |
| - | old_fstab = 0; |
| - | } |
| - | |
| - | fclose(f); |
| - | |
| - | if (old_fstab) { |
| - | fputs("\007\007\007" |
| - | "WARNING: Your /etc/fstab does not contain the fsck passno\n" |
| - | " field. I will kludge around things for you, but you\n" |
| - | " should fix your /etc/fstab file as soon as you can.\n\n", stderr); |
| - | |
| - | for (fs = filesys_info; fs; fs = fs->next) { |
| - | fs->passno = 1; |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* Lookup filesys in /etc/fstab and return the corresponding entry. */ |
| - | static struct fs_info *lookup(char *filesys) |
| - | { |
| - | struct fs_info *fs; |
| - | |
| - | /* No filesys name given. */ |
| - | if (filesys == NULL) |
| - | return NULL; |
| - | |
| - | for (fs = filesys_info; fs; fs = fs->next) { |
| - | if (!strcmp(filesys, fs->device) || |
| - | (fs->mountpt && !strcmp(filesys, fs->mountpt))) |
| - | break; |
| - | } |
| - | |
| - | return fs; |
| - | } |
| - | |
| - | /* Find fsck program for a given fs type. */ |
| - | static char *find_fsck(char *type) |
| - | { |
| - | char *s; |
| - | const char *tpl; |
| - | char *p = string_copy(fsck_path); |
| - | struct stat st; |
| - | |
| - | /* Are we looking for a program or just a type? */ |
| - | tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s"); |
| - | |
| - | for (s = strtok(p, ":"); s; s = strtok(NULL, ":")) { |
| - | s = xasprintf(tpl, s, type); |
| - | if (stat(s, &st) == 0) break; |
| - | free(s); |
| - | } |
| - | free(p); |
| - | return s; |
| - | } |
| - | |
| - | static int progress_active(void) |
| - | { |
| - | struct fsck_instance *inst; |
| - | |
| - | for (inst = instance_list; inst; inst = inst->next) { |
| - | if (inst->flags & FLAG_DONE) |
| - | continue; |
| - | if (inst->flags & FLAG_PROGRESS) |
| - | return 1; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Execute a particular fsck program, and link it into the list of |
| - | * child processes we are waiting for. |
| - | */ |
| - | static int execute(const char *type, const char *device, const char *mntpt, |
| - | int interactive) |
| - | { |
| - | char *s, *argv[80]; |
| - | char *prog; |
| - | int argc, i; |
| - | struct fsck_instance *inst, *p; |
| - | pid_t pid; |
| - | |
| - | inst = xzalloc(sizeof(struct fsck_instance)); |
| - | |
| - | prog = xasprintf("fsck.%s", type); |
| - | argv[0] = prog; |
| - | argc = 1; |
| - | |
| - | for (i=0; i <num_args; i++) |
| - | argv[argc++] = string_copy(args[i]); |
| - | |
| - | if (progress && !progress_active()) { |
| - | if ((strcmp(type, "ext2") == 0) || |
| - | (strcmp(type, "ext3") == 0)) { |
| - | char tmp[80]; |
| - | snprintf(tmp, 80, "-C%d", progress_fd); |
| - | argv[argc++] = string_copy(tmp); |
| - | inst->flags |= FLAG_PROGRESS; |
| - | } |
| - | } |
| - | |
| - | argv[argc++] = string_copy(device); |
| - | argv[argc] = 0; |
| - | |
| - | s = find_fsck(prog); |
| - | if (s == NULL) { |
| - | bb_error_msg("%s: not found", prog); |
| - | return ENOENT; |
| - | } |
| - | |
| - | if (verbose || noexecute) { |
| - | printf("[%s (%d) -- %s] ", s, num_running, |
| - | mntpt ? mntpt : device); |
| - | for (i=0; i < argc; i++) |
| - | printf("%s ", argv[i]); |
| - | bb_putchar('\n'); |
| - | } |
| - | |
| - | /* Fork and execute the correct program. */ |
| - | if (noexecute) |
| - | pid = -1; |
| - | else if ((pid = fork()) < 0) { |
| - | perror("vfork"+1); |
| - | return errno; |
| - | } else if (pid == 0) { |
| - | if (!interactive) |
| - | close(0); |
| - | (void) execv(s, argv); |
| - | bb_simple_perror_msg_and_die(argv[0]); |
| - | } |
| - | |
| - | for (i = 1; i < argc; i++) |
| - | free(argv[i]); |
| - | |
| - | free(s); |
| - | inst->pid = pid; |
| - | inst->prog = prog; |
| - | inst->type = string_copy(type); |
| - | inst->device = string_copy(device); |
| - | inst->base_device = base_device(device); |
| - | inst->start_time = time(0); |
| - | inst->next = NULL; |
| - | |
| - | /* |
| - | * Find the end of the list, so we add the instance on at the end. |
| - | */ |
| - | for (p = instance_list; p && p->next; p = p->next); |
| - | |
| - | if (p) |
| - | p->next = inst; |
| - | else |
| - | instance_list = inst; |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Send a signal to all outstanding fsck child processes |
| - | */ |
| - | static int kill_all(int signum) |
| - | { |
| - | struct fsck_instance *inst; |
| - | int n = 0; |
| - | |
| - | for (inst = instance_list; inst; inst = inst->next) { |
| - | if (inst->flags & FLAG_DONE) |
| - | continue; |
| - | kill(inst->pid, signum); |
| - | n++; |
| - | } |
| - | return n; |
| - | } |
| - | |
| - | /* |
| - | * Wait for one child process to exit; when it does, unlink it from |
| - | * the list of executing child processes, and return it. |
| - | */ |
| - | static struct fsck_instance *wait_one(int flags) |
| - | { |
| - | int status; |
| - | int sig; |
| - | struct fsck_instance *inst, *inst2, *prev; |
| - | pid_t pid; |
| - | |
| - | if (!instance_list) |
| - | return NULL; |
| - | |
| - | if (noexecute) { |
| - | inst = instance_list; |
| - | prev = 0; |
| - | #ifdef RANDOM_DEBUG |
| - | while (inst->next && (random() & 1)) { |
| - | prev = inst; |
| - | inst = inst->next; |
| - | } |
| - | #endif |
| - | inst->exit_status = 0; |
| - | goto ret_inst; |
| - | } |
| - | |
| - | /* |
| - | * gcc -Wall fails saving throw against stupidity |
| - | * (inst and prev are thought to be uninitialized variables) |
| - | */ |
| - | inst = prev = NULL; |
| - | |
| - | do { |
| - | pid = waitpid(-1, &status, flags); |
| - | if (cancel_requested && !kill_sent) { |
| - | kill_all(SIGTERM); |
| - | kill_sent++; |
| - | } |
| - | if ((pid == 0) && (flags & WNOHANG)) |
| - | return NULL; |
| - | if (pid < 0) { |
| - | if ((errno == EINTR) || (errno == EAGAIN)) |
| - | continue; |
| - | if (errno == ECHILD) { |
| - | bb_error_msg("wait: no more child process?!?"); |
| - | return NULL; |
| - | } |
| - | perror("wait"); |
| - | continue; |
| - | } |
| - | for (prev = 0, inst = instance_list; |
| - | inst; |
| - | prev = inst, inst = inst->next) { |
| - | if (inst->pid == pid) |
| - | break; |
| - | } |
| - | } while (!inst); |
| - | |
| - | if (WIFEXITED(status)) |
| - | status = WEXITSTATUS(status); |
| - | else if (WIFSIGNALED(status)) { |
| - | sig = WTERMSIG(status); |
| - | if (sig == SIGINT) { |
| - | status = EXIT_UNCORRECTED; |
| - | } else { |
| - | printf("Warning... %s for device %s exited " |
| - | "with signal %d.\n", |
| - | inst->prog, inst->device, sig); |
| - | status = EXIT_ERROR; |
| - | } |
| - | } else { |
| - | printf("%s %s: status is %x, should never happen.\n", |
| - | inst->prog, inst->device, status); |
| - | status = EXIT_ERROR; |
| - | } |
| - | inst->exit_status = status; |
| - | if (progress && (inst->flags & FLAG_PROGRESS) && |
| - | !progress_active()) { |
| - | for (inst2 = instance_list; inst2; inst2 = inst2->next) { |
| - | if (inst2->flags & FLAG_DONE) |
| - | continue; |
| - | if (strcmp(inst2->type, "ext2") && |
| - | strcmp(inst2->type, "ext3")) |
| - | continue; |
| - | /* |
| - | * If we've just started the fsck, wait a tiny |
| - | * bit before sending the kill, to give it |
| - | * time to set up the signal handler |
| - | */ |
| - | if (inst2->start_time < time(0)+2) { |
| - | if (fork() == 0) { |
| - | sleep(1); |
| - | kill(inst2->pid, SIGUSR1); |
| - | exit(0); |
| - | } |
| - | } else |
| - | kill(inst2->pid, SIGUSR1); |
| - | inst2->flags |= FLAG_PROGRESS; |
| - | break; |
| - | } |
| - | } |
| - | ret_inst: |
| - | if (prev) |
| - | prev->next = inst->next; |
| - | else |
| - | instance_list = inst->next; |
| - | if (verbose > 1) |
| - | printf("Finished with %s (exit status %d)\n", |
| - | inst->device, inst->exit_status); |
| - | num_running--; |
| - | return inst; |
| - | } |
| - | |
| - | #define FLAG_WAIT_ALL 0 |
| - | #define FLAG_WAIT_ATLEAST_ONE 1 |
| - | /* |
| - | * Wait until all executing child processes have exited; return the |
| - | * logical OR of all of their exit code values. |
| - | */ |
| - | static int wait_many(int flags) |
| - | { |
| - | struct fsck_instance *inst; |
| - | int global_status = 0; |
| - | int wait_flags = 0; |
| - | |
| - | while ((inst = wait_one(wait_flags))) { |
| - | global_status |= inst->exit_status; |
| - | free_instance(inst); |
| - | #ifdef RANDOM_DEBUG |
| - | if (noexecute && (flags & WNOHANG) && !(random() % 3)) |
| - | break; |
| - | #endif |
| - | if (flags & FLAG_WAIT_ATLEAST_ONE) |
| - | wait_flags = WNOHANG; |
| - | } |
| - | return global_status; |
| - | } |
| - | |
| - | /* |
| - | * Run the fsck program on a particular device |
| - | * |
| - | * If the type is specified using -t, and it isn't prefixed with "no" |
| - | * (as in "noext2") and only one filesystem type is specified, then |
| - | * use that type regardless of what is specified in /etc/fstab. |
| - | * |
| - | * If the type isn't specified by the user, then use either the type |
| - | * specified in /etc/fstab, or DEFAULT_FSTYPE. |
| - | */ |
| - | static void fsck_device(struct fs_info *fs, int interactive) |
| - | { |
| - | const char *type; |
| - | int retval; |
| - | |
| - | interpret_type(fs); |
| - | |
| - | if (strcmp(fs->type, "auto") != 0) |
| - | type = fs->type; |
| - | else if (fstype && strncmp(fstype, "no", 2) && |
| - | strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && |
| - | !strchr(fstype, ',')) |
| - | type = fstype; |
| - | else |
| - | type = DEFAULT_FSTYPE; |
| - | |
| - | num_running++; |
| - | retval = execute(type, fs->device, fs->mountpt, interactive); |
| - | if (retval) { |
| - | bb_error_msg("error %d while executing fsck.%s for %s", |
| - | retval, type, fs->device); |
| - | num_running--; |
| - | } |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Deal with the fsck -t argument. |
| - | */ |
| - | struct fs_type_compile { |
| - | char **list; |
| - | int *type; |
| - | int negate; |
| - | } fs_type_compiled; |
| - | |
| - | #define FS_TYPE_NORMAL 0 |
| - | #define FS_TYPE_OPT 1 |
| - | #define FS_TYPE_NEGOPT 2 |
| - | |
| - | static const char fs_type_syntax_error[] = |
| - | "Either all or none of the filesystem types passed to -t must be prefixed\n" |
| - | "with 'no' or '!'."; |
| - | |
| - | static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) |
| - | { |
| - | char *cp, *list, *s; |
| - | int num = 2; |
| - | int negate, first_negate = 1; |
| - | |
| - | if (fs_type) { |
| - | for (cp=fs_type; *cp; cp++) { |
| - | if (*cp == ',') |
| - | num++; |
| - | } |
| - | } |
| - | |
| - | cmp->list = xzalloc(num * sizeof(char *)); |
| - | cmp->type = xzalloc(num * sizeof(int)); |
| - | cmp->negate = 0; |
| - | |
| - | if (!fs_type) |
| - | return; |
| - | |
| - | list = string_copy(fs_type); |
| - | num = 0; |
| - | s = strtok(list, ","); |
| - | while (s) { |
| - | negate = 0; |
| - | if (strncmp(s, "no", 2) == 0) { |
| - | s += 2; |
| - | negate = 1; |
| - | } else if (*s == '!') { |
| - | s++; |
| - | negate = 1; |
| - | } |
| - | if (strcmp(s, "loop") == 0) |
| - | /* loop is really short-hand for opts=loop */ |
| - | goto loop_special_case; |
| - | else if (strncmp(s, "opts=", 5) == 0) { |
| - | s += 5; |
| - | loop_special_case: |
| - | cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT; |
| - | } else { |
| - | if (first_negate) { |
| - | cmp->negate = negate; |
| - | first_negate = 0; |
| - | } |
| - | if ((negate && !cmp->negate) || |
| - | (!negate && cmp->negate)) { |
| - | bb_error_msg_and_die("%s", fs_type_syntax_error); |
| - | } |
| - | } |
| - | cmp->list[num++] = string_copy(s); |
| - | s = strtok(NULL, ","); |
| - | } |
| - | free(list); |
| - | } |
| - | |
| - | /* |
| - | * This function returns true if a particular option appears in a |
| - | * comma-delimited options list |
| - | */ |
| - | static int opt_in_list(char *opt, char *optlist) |
| - | { |
| - | char *list, *s; |
| - | |
| - | if (!optlist) |
| - | return 0; |
| - | list = string_copy(optlist); |
| - | |
| - | s = strtok(list, ","); |
| - | while (s) { |
| - | if (strcmp(s, opt) == 0) { |
| - | free(list); |
| - | return 1; |
| - | } |
| - | s = strtok(NULL, ","); |
| - | } |
| - | free(list); |
| - | return 0; |
| - | } |
| - | |
| - | /* See if the filesystem matches the criteria given by the -t option */ |
| - | static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp) |
| - | { |
| - | int n, ret = 0, checked_type = 0; |
| - | char *cp; |
| - | |
| - | if (cmp->list == 0 || cmp->list[0] == 0) |
| - | return 1; |
| - | |
| - | for (n=0; (cp = cmp->list[n]); n++) { |
| - | switch (cmp->type[n]) { |
| - | case FS_TYPE_NORMAL: |
| - | checked_type++; |
| - | if (strcmp(cp, fs->type) == 0) { |
| - | ret = 1; |
| - | } |
| - | break; |
| - | case FS_TYPE_NEGOPT: |
| - | if (opt_in_list(cp, fs->opts)) |
| - | return 0; |
| - | break; |
| - | case FS_TYPE_OPT: |
| - | if (!opt_in_list(cp, fs->opts)) |
| - | return 0; |
| - | break; |
| - | } |
| - | } |
| - | if (checked_type == 0) |
| - | return 1; |
| - | return (cmp->negate ? !ret : ret); |
| - | } |
| - | |
| - | /* Check if we should ignore this filesystem. */ |
| - | static int ignore(struct fs_info *fs) |
| - | { |
| - | int wanted; |
| - | char *s; |
| - | |
| - | /* |
| - | * If the pass number is 0, ignore it. |
| - | */ |
| - | if (fs->passno == 0) |
| - | return 1; |
| - | |
| - | interpret_type(fs); |
| - | |
| - | /* |
| - | * If a specific fstype is specified, and it doesn't match, |
| - | * ignore it. |
| - | */ |
| - | if (!fs_match(fs, &fs_type_compiled)) return 1; |
| - | |
| - | /* Are we ignoring this type? */ |
| - | if (index_in_str_array(ignored_types, fs->type) >= 0) |
| - | return 1; |
| - | |
| - | /* Do we really really want to check this fs? */ |
| - | wanted = index_in_str_array(really_wanted, fs->type) >= 0; |
| - | |
| - | /* See if the <fsck.fs> program is available. */ |
| - | s = find_fsck(fs->type); |
| - | if (s == NULL) { |
| - | if (wanted) |
| - | bb_error_msg("can't check %s: fsck.%s not found", |
| - | fs->device, fs->type); |
| - | return 1; |
| - | } |
| - | free(s); |
| - | |
| - | /* We can and want to check this file system type. */ |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Returns TRUE if a partition on the same disk is already being |
| - | * checked. |
| - | */ |
| - | static int device_already_active(char *device) |
| - | { |
| - | struct fsck_instance *inst; |
| - | char *base; |
| - | |
| - | if (force_all_parallel) |
| - | return 0; |
| - | |
| - | #ifdef BASE_MD |
| - | /* Don't check a soft raid disk with any other disk */ |
| - | if (instance_list && |
| - | (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) || |
| - | !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))) |
| - | return 1; |
| - | #endif |
| - | |
| - | base = base_device(device); |
| - | /* |
| - | * If we don't know the base device, assume that the device is |
| - | * already active if there are any fsck instances running. |
| - | */ |
| - | if (!base) |
| - | return (instance_list != 0); |
| - | for (inst = instance_list; inst; inst = inst->next) { |
| - | if (!inst->base_device || !strcmp(base, inst->base_device)) { |
| - | free(base); |
| - | return 1; |
| - | } |
| - | } |
| - | free(base); |
| - | return 0; |
| - | } |
| - | |
| - | /* Check all file systems, using the /etc/fstab table. */ |
| - | static int check_all(void) |
| - | { |
| - | struct fs_info *fs = NULL; |
| - | int status = EXIT_OK; |
| - | int not_done_yet = 1; |
| - | int passno = 1; |
| - | int pass_done; |
| - | |
| - | if (verbose) |
| - | fputs("Checking all file systems.\n", stdout); |
| - | |
| - | /* |
| - | * Do an initial scan over the filesystem; mark filesystems |
| - | * which should be ignored as done, and resolve any "auto" |
| - | * filesystem types (done as a side-effect of calling ignore()). |
| - | */ |
| - | for (fs = filesys_info; fs; fs = fs->next) { |
| - | if (ignore(fs)) |
| - | fs->flags |= FLAG_DONE; |
| - | } |
| - | |
| - | /* |
| - | * Find and check the root filesystem. |
| - | */ |
| - | if (!parallel_root) { |
| - | for (fs = filesys_info; fs; fs = fs->next) { |
| - | if (LONE_CHAR(fs->mountpt, '/')) |
| - | break; |
| - | } |
| - | if (fs) { |
| - | if (!skip_root && !ignore(fs)) { |
| - | fsck_device(fs, 1); |
| - | status |= wait_many(FLAG_WAIT_ALL); |
| - | if (status > EXIT_NONDESTRUCT) |
| - | return status; |
| - | } |
| - | fs->flags |= FLAG_DONE; |
| - | } |
| - | } |
| - | /* |
| - | * This is for the bone-headed user who enters the root |
| - | * filesystem twice. Skip root will skep all root entries. |
| - | */ |
| - | if (skip_root) |
| - | for (fs = filesys_info; fs; fs = fs->next) |
| - | if (LONE_CHAR(fs->mountpt, '/')) |
| - | fs->flags |= FLAG_DONE; |
| - | |
| - | while (not_done_yet) { |
| - | not_done_yet = 0; |
| - | pass_done = 1; |
| - | |
| - | for (fs = filesys_info; fs; fs = fs->next) { |
| - | if (cancel_requested) |
| - | break; |
| - | if (fs->flags & FLAG_DONE) |
| - | continue; |
| - | /* |
| - | * If the filesystem's pass number is higher |
| - | * than the current pass number, then we don't |
| - | * do it yet. |
| - | */ |
| - | if (fs->passno > passno) { |
| - | not_done_yet++; |
| - | continue; |
| - | } |
| - | /* |
| - | * If a filesystem on a particular device has |
| - | * already been spawned, then we need to defer |
| - | * this to another pass. |
| - | */ |
| - | if (device_already_active(fs->device)) { |
| - | pass_done = 0; |
| - | continue; |
| - | } |
| - | /* |
| - | * Spawn off the fsck process |
| - | */ |
| - | fsck_device(fs, serialize); |
| - | fs->flags |= FLAG_DONE; |
| - | |
| - | /* |
| - | * Only do one filesystem at a time, or if we |
| - | * have a limit on the number of fsck's extant |
| - | * at one time, apply that limit. |
| - | */ |
| - | if (serialize || |
| - | (max_running && (num_running >= max_running))) { |
| - | pass_done = 0; |
| - | break; |
| - | } |
| - | } |
| - | if (cancel_requested) |
| - | break; |
| - | if (verbose > 1) |
| - | printf("--waiting-- (pass %d)\n", passno); |
| - | status |= wait_many(pass_done ? FLAG_WAIT_ALL : |
| - | FLAG_WAIT_ATLEAST_ONE); |
| - | if (pass_done) { |
| - | if (verbose > 1) |
| - | printf("----------------------------------\n"); |
| - | passno++; |
| - | } else |
| - | not_done_yet++; |
| - | } |
| - | if (cancel_requested && !kill_sent) { |
| - | kill_all(SIGTERM); |
| - | kill_sent++; |
| - | } |
| - | status |= wait_many(FLAG_WAIT_ATLEAST_ONE); |
| - | return status; |
| - | } |
| - | |
| - | static void signal_cancel(int sig FSCK_ATTR((unused))) |
| - | { |
| - | cancel_requested++; |
| - | } |
| - | |
| - | static void PRS(int argc, char **argv) |
| - | { |
| - | int i, j; |
| - | char *arg, *dev, *tmp = NULL; |
| - | char options[128]; |
| - | int opt = 0; |
| - | int opts_for_fsck = 0; |
| - | struct sigaction sa; |
| - | |
| - | /* |
| - | * Set up signal action |
| - | */ |
| - | memset(&sa, 0, sizeof(struct sigaction)); |
| - | sa.sa_handler = signal_cancel; |
| - | sigaction(SIGINT, &sa, 0); |
| - | sigaction(SIGTERM, &sa, 0); |
| - | |
| - | num_devices = 0; |
| - | num_args = 0; |
| - | instance_list = 0; |
| - | |
| - | for (i=1; i < argc; i++) { |
| - | arg = argv[i]; |
| - | if (!arg) |
| - | continue; |
| - | if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { |
| - | if (num_devices >= MAX_DEVICES) { |
| - | bb_error_msg_and_die("too many devices"); |
| - | } |
| - | dev = blkid_get_devname(cache, arg, NULL); |
| - | if (!dev && strchr(arg, '=')) { |
| - | /* |
| - | * Check to see if we failed because |
| - | * /proc/partitions isn't found. |
| - | */ |
| - | if (access("/proc/partitions", R_OK) < 0) { |
| - | bb_perror_msg_and_die("can't open /proc/partitions " |
| - | "(is /proc mounted?)"); |
| - | } |
| - | /* |
| - | * Check to see if this is because |
| - | * we're not running as root |
| - | */ |
| - | if (geteuid()) |
| - | bb_error_msg_and_die( |
| - | "must be root to scan for matching filesystems: %s\n", arg); |
| - | else |
| - | bb_error_msg_and_die( |
| - | "can't find matching filesystem: %s", arg); |
| - | } |
| - | devices[num_devices++] = dev ? dev : string_copy(arg); |
| - | continue; |
| - | } |
| - | if (arg[0] != '-' || opts_for_fsck) { |
| - | if (num_args >= MAX_ARGS) { |
| - | bb_error_msg_and_die("too many arguments"); |
| - | } |
| - | args[num_args++] = string_copy(arg); |
| - | continue; |
| - | } |
| - | for (j=1; arg[j]; j++) { |
| - | if (opts_for_fsck) { |
| - | options[++opt] = arg[j]; |
| - | continue; |
| - | } |
| - | switch (arg[j]) { |
| - | case 'A': |
| - | doall++; |
| - | break; |
| - | case 'C': |
| - | progress++; |
| - | if (arg[j+1]) { |
| - | progress_fd = string_to_int(arg+j+1); |
| - | if (progress_fd < 0) |
| - | progress_fd = 0; |
| - | else |
| - | goto next_arg; |
| - | } else if ((i+1) < argc |
| - | && argv[i+1][0] != '-') { |
| - | progress_fd = string_to_int(argv[i]); |
| - | if (progress_fd < 0) |
| - | progress_fd = 0; |
| - | else { |
| - | goto next_arg; |
| - | } |
| - | } |
| - | break; |
| - | case 'V': |
| - | verbose++; |
| - | break; |
| - | case 'N': |
| - | noexecute++; |
| - | break; |
| - | case 'R': |
| - | skip_root++; |
| - | break; |
| - | case 'T': |
| - | notitle++; |
| - | break; |
| - | case 'M': |
| - | like_mount++; |
| - | break; |
| - | case 'P': |
| - | parallel_root++; |
| - | break; |
| - | case 's': |
| - | serialize++; |
| - | break; |
| - | case 't': |
| - | tmp = 0; |
| - | if (fstype) |
| - | bb_show_usage(); |
| - | if (arg[j+1]) |
| - | tmp = arg+j+1; |
| - | else if ((i+1) < argc) |
| - | tmp = argv[++i]; |
| - | else |
| - | bb_show_usage(); |
| - | fstype = string_copy(tmp); |
| - | compile_fs_type(fstype, &fs_type_compiled); |
| - | goto next_arg; |
| - | case '-': |
| - | opts_for_fsck++; |
| - | break; |
| - | case '?': |
| - | bb_show_usage(); |
| - | break; |
| - | default: |
| - | options[++opt] = arg[j]; |
| - | break; |
| - | } |
| - | } |
| - | next_arg: |
| - | if (opt) { |
| - | options[0] = '-'; |
| - | options[++opt] = '\0'; |
| - | if (num_args >= MAX_ARGS) { |
| - | bb_error_msg("too many arguments"); |
| - | } |
| - | args[num_args++] = string_copy(options); |
| - | opt = 0; |
| - | } |
| - | } |
| - | if (getenv("FSCK_FORCE_ALL_PARALLEL")) |
| - | force_all_parallel++; |
| - | if ((tmp = getenv("FSCK_MAX_INST"))) |
| - | max_running = atoi(tmp); |
| - | } |
| - | |
| - | int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| - | int fsck_main(int argc, char **argv) |
| - | { |
| - | int i, status = 0; |
| - | int interactive = 0; |
| - | const char *fstab; |
| - | struct fs_info *fs; |
| - | |
| - | setvbuf(stdout, NULL, _IONBF, BUFSIZ); |
| - | setvbuf(stderr, NULL, _IONBF, BUFSIZ); |
| - | |
| - | blkid_get_cache(&cache, NULL); |
| - | PRS(argc, argv); |
| - | |
| - | if (!notitle) |
| - | printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); |
| - | |
| - | fstab = getenv("FSTAB_FILE"); |
| - | if (!fstab) |
| - | fstab = _PATH_MNTTAB; |
| - | load_fs_info(fstab); |
| - | |
| - | fsck_path = e2fs_set_sbin_path(); |
| - | |
| - | if ((num_devices == 1) || (serialize)) |
| - | interactive = 1; |
| - | |
| - | /* If -A was specified ("check all"), do that! */ |
| - | if (doall) |
| - | return check_all(); |
| - | |
| - | if (num_devices == 0) { |
| - | serialize++; |
| - | interactive++; |
| - | return check_all(); |
| - | } |
| - | for (i = 0; i < num_devices; i++) { |
| - | if (cancel_requested) { |
| - | if (!kill_sent) { |
| - | kill_all(SIGTERM); |
| - | kill_sent++; |
| - | } |
| - | break; |
| - | } |
| - | fs = lookup(devices[i]); |
| - | if (!fs) { |
| - | fs = create_fs_device(devices[i], 0, "auto", |
| - | 0, -1, -1); |
| - | if (!fs) |
| - | continue; |
| - | } |
| - | fsck_device(fs, interactive); |
| - | if (serialize || |
| - | (max_running && (num_running >= max_running))) { |
| - | struct fsck_instance *inst; |
| - | |
| - | inst = wait_one(0); |
| - | if (inst) { |
| - | status |= inst->exit_status; |
| - | free_instance(inst); |
| - | } |
| - | if (verbose > 1) |
| - | printf("----------------------------------\n"); |
| - | } |
| - | } |
| - | status |= wait_many(FLAG_WAIT_ALL); |
| - | blkid_put_cache(cache); |
| - | return status; |
| - | } |
| @@ -1,16 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * fsck.h |
| - | */ |
| - | |
| - | #define FSCK_ATTR(x) __attribute__(x) |
| - | |
| - | #define EXIT_OK 0 |
| - | #define EXIT_NONDESTRUCT 1 |
| - | #define EXIT_DESTRUCT 2 |
| - | #define EXIT_UNCORRECTED 4 |
| - | #define EXIT_ERROR 8 |
| - | #define EXIT_USAGE 16 |
| - | #define FSCK_CANCELED 32 /* Aborted with a signal or ^C */ |
| - | |
| - | extern char *e2fs_set_sbin_path(void); |
| @@ -1,129 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * lsattr.c - List file attributes on an ext2 file system |
| - | * |
| - | * Copyright (C) 1993, 1994 Remy Card <[email protected]> |
| - | * 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 - Display version info only when -V specified (G M Sipe) |
| - | */ |
| - | |
| - | #include <sys/types.h> |
| - | #include <dirent.h> |
| - | #include <errno.h> |
| - | #include <fcntl.h> |
| - | #include <getopt.h> |
| - | #include <stdio.h> |
| - | #include <unistd.h> |
| - | #include <stdlib.h> |
| - | #include <string.h> |
| - | #include <sys/param.h> |
| - | #include <sys/stat.h> |
| - | |
| - | #include "ext2fs/ext2_fs.h" |
| - | #include "e2fsbb.h" |
| - | #include "e2p/e2p.h" |
| - | |
| - | #define OPT_RECUR 1 |
| - | #define OPT_ALL 2 |
| - | #define OPT_DIRS_OPT 4 |
| - | #define OPT_PF_LONG 8 |
| - | #define OPT_GENERATION 16 |
| - | static int flags; |
| - | |
| - | static void list_attributes(const char *name) |
| - | { |
| - | unsigned long fsflags; |
| - | unsigned long generation; |
| - | |
| - | if (fgetflags(name, &fsflags) == -1) |
| - | goto read_err; |
| - | if (flags & OPT_GENERATION) { |
| - | if (fgetversion(name, &generation) == -1) |
| - | goto read_err; |
| - | printf("%5lu ", generation); |
| - | } |
| - | |
| - | if (flags & OPT_PF_LONG) { |
| - | printf("%-28s ", name); |
| - | print_e2flags(stdout, fsflags, PFOPT_LONG); |
| - | bb_putchar('\n'); |
| - | } else { |
| - | print_e2flags(stdout, fsflags, 0); |
| - | printf(" %s\n", name); |
| - | } |
| - | |
| - | return; |
| - | read_err: |
| - | bb_perror_msg("reading %s", name); |
| - | } |
| - | |
| - | static int lsattr_dir_proc(const char *, struct dirent *, void *); |
| - | |
| - | static void lsattr_args(const char *name) |
| - | { |
| - | struct stat st; |
| - | |
| - | if (lstat(name, &st) == -1) { |
| - | bb_perror_msg("stating %s", name); |
| - | } else { |
| - | if (S_ISDIR(st.st_mode) && !(flags & OPT_DIRS_OPT)) |
| - | iterate_on_dir(name, lsattr_dir_proc, NULL); |
| - | else |
| - | list_attributes(name); |
| - | } |
| - | } |
| - | |
| - | static int lsattr_dir_proc(const char *dir_name, struct dirent *de, |
| - | void *private) |
| - | { |
| - | struct stat st; |
| - | char *path; |
| - | |
| - | path = concat_path_file(dir_name, de->d_name); |
| - | |
| - | if (lstat(path, &st) == -1) |
| - | bb_simple_perror_msg(path); |
| - | else { |
| - | if (de->d_name[0] != '.' || (flags & OPT_ALL)) { |
| - | list_attributes(path); |
| - | if (S_ISDIR(st.st_mode) && (flags & OPT_RECUR) && |
| - | (de->d_name[0] != '.' && (de->d_name[1] != '\0' || |
| - | (de->d_name[1] != '.' && de->d_name[2] != '\0')))) { |
| - | printf("\n%s:\n", path); |
| - | iterate_on_dir(path, lsattr_dir_proc, NULL); |
| - | bb_putchar('\n'); |
| - | } |
| - | } |
| - | } |
| - | |
| - | free(path); |
| - | |
| - | return 0; |
| - | } |
| - | |
| - | int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| - | int lsattr_main(int argc, char **argv) |
| - | { |
| - | int i; |
| - | |
| - | flags = getopt32(argv, "Radlv"); |
| - | |
| - | if (optind > argc - 1) |
| - | lsattr_args("."); |
| - | else |
| - | for (i = optind; i < argc; i++) |
| - | lsattr_args(argv[i]); |
| - | |
| - | return EXIT_SUCCESS; |
| - | } |
| @@ -1,1333 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * mke2fs.c - Make a ext2fs filesystem. |
| - | * |
| - | * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
| - | * 2003, 2004, 2005 by Theodore Ts'o. |
| - | * |
| - | * Licensed under GPLv2, see file LICENSE in this source tree. |
| - | */ |
| - | |
| - | /* Usage: mke2fs [options] device |
| - | * |
| - | * The device may be a block device or a image of one, but this isn't |
| - | * enforced (but it's not much fun on a character device :-). |
| - | */ |
| - | |
| - | #include <stdio.h> |
| - | #include <string.h> |
| - | #include <fcntl.h> |
| - | #include <ctype.h> |
| - | #include <time.h> |
| - | #include <getopt.h> |
| - | #include <unistd.h> |
| - | #include <stdlib.h> |
| - | #include <errno.h> |
| - | #include <mntent.h> |
| - | #include <sys/ioctl.h> |
| - | #include <sys/types.h> |
| - | |
| - | #include "e2fsbb.h" |
| - | #include "ext2fs/ext2_fs.h" |
| - | #include "uuid/uuid.h" |
| - | #include "e2p/e2p.h" |
| - | #include "ext2fs/ext2fs.h" |
| - | #include "util.h" |
| - | |
| - | #define STRIDE_LENGTH 8 |
| - | |
| - | #ifndef __sparc__ |
| - | #define ZAP_BOOTBLOCK |
| - | #endif |
| - | |
| - | static const char * device_name; |
| - | |
| - | /* Command line options */ |
| - | static int cflag; |
| - | static int quiet; |
| - | static int super_only; |
| - | static int force; |
| - | static int noaction; |
| - | static int journal_size; |
| - | static int journal_flags; |
| - | static const char *bad_blocks_filename; |
| - | static __u32 fs_stride; |
| - | |
| - | static struct ext2_super_block param; |
| - | static char *creator_os; |
| - | static char *volume_label; |
| - | static char *mount_dir; |
| - | static char *journal_device = NULL; |
| - | static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */ |
| - | |
| - | static int sys_page_size = 4096; |
| - | static int linux_version_code = 0; |
| - | |
| - | static int int_log2(int arg) |
| - | { |
| - | int l = 0; |
| - | |
| - | arg >>= 1; |
| - | while (arg) { |
| - | l++; |
| - | arg >>= 1; |
| - | } |
| - | return l; |
| - | } |
| - | |
| - | static int int_log10(unsigned int arg) |
| - | { |
| - | int l; |
| - | |
| - | for (l = 0; arg; l++) |
| - | arg = arg / 10; |
| - | return l; |
| - | } |
| - | |
| - | /* |
| - | * This function sets the default parameters for a filesystem |
| - | * |
| - | * The type is specified by the user. The size is the maximum size |
| - | * (in megabytes) for which a set of parameters applies, with a size |
| - | * of zero meaning that it is the default parameter for the type. |
| - | * Note that order is important in the table below. |
| - | */ |
| - | #define DEF_MAX_BLOCKSIZE -1 |
| - | static const char default_str[] = "default"; |
| - | struct mke2fs_defaults { |
| - | const char *type; |
| - | int size; |
| - | int blocksize; |
| - | int inode_ratio; |
| - | }; |
| - | |
| - | static const struct mke2fs_defaults settings[] = { |
| - | { default_str, 0, 4096, 8192 }, |
| - | { default_str, 512, 1024, 4096 }, |
| - | { default_str, 3, 1024, 8192 }, |
| - | { "journal", 0, 4096, 8192 }, |
| - | { "news", 0, 4096, 4096 }, |
| - | { "largefile", 0, 4096, 1024 * 1024 }, |
| - | { "largefile4", 0, 4096, 4096 * 1024 }, |
| - | { 0, 0, 0, 0}, |
| - | }; |
| - | |
| - | static void set_fs_defaults(const char *fs_type, |
| - | struct ext2_super_block *super, |
| - | int blocksize, int sector_size, |
| - | int *inode_ratio) |
| - | { |
| - | int megs; |
| - | int ratio = 0; |
| - | const struct mke2fs_defaults *p; |
| - | int use_bsize = 1024; |
| - | |
| - | megs = super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024; |
| - | if (inode_ratio) |
| - | ratio = *inode_ratio; |
| - | if (!fs_type) |
| - | fs_type = default_str; |
| - | for (p = settings; p->type; p++) { |
| - | if ((strcmp(p->type, fs_type) != 0) && |
| - | (strcmp(p->type, default_str) != 0)) |
| - | continue; |
| - | if ((p->size != 0) && (megs > p->size)) |
| - | continue; |
| - | if (ratio == 0) |
| - | *inode_ratio = p->inode_ratio < blocksize ? |
| - | blocksize : p->inode_ratio; |
| - | use_bsize = p->blocksize; |
| - | } |
| - | if (blocksize <= 0) { |
| - | if (use_bsize == DEF_MAX_BLOCKSIZE) { |
| - | use_bsize = sys_page_size; |
| - | if ((linux_version_code < (2*65536 + 6*256)) && |
| - | (use_bsize > 4096)) |
| - | use_bsize = 4096; |
| - | } |
| - | if (sector_size && use_bsize < sector_size) |
| - | use_bsize = sector_size; |
| - | if ((blocksize < 0) && (use_bsize < (-blocksize))) |
| - | use_bsize = -blocksize; |
| - | blocksize = use_bsize; |
| - | super->s_blocks_count /= blocksize / 1024; |
| - | } |
| - | super->s_log_frag_size = super->s_log_block_size = |
| - | int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Helper function for read_bb_file and test_disk |
| - | */ |
| - | static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk) |
| - | { |
| - | bb_error_msg("Bad block %u out of range; ignored", blk); |
| - | } |
| - | |
| - | /* |
| - | * Busybox stuff |
| - | */ |
| - | static void mke2fs_error_msg_and_die(int retval, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); |
| - | static void mke2fs_error_msg_and_die(int retval, const char *fmt, ...) |
| - | { |
| - | va_list ap; |
| - | |
| - | if (retval) { |
| - | va_start(ap, fmt); |
| - | fprintf(stderr, "\nCould not "); |
| - | vfprintf(stderr, fmt, ap); |
| - | fprintf(stderr, "\n"); |
| - | va_end(ap); |
| - | exit(EXIT_FAILURE); |
| - | } |
| - | } |
| - | |
| - | static void mke2fs_verbose(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); |
| - | static void mke2fs_verbose(const char *fmt, ...) |
| - | { |
| - | va_list ap; |
| - | |
| - | if (!quiet) { |
| - | va_start(ap, fmt); |
| - | vfprintf(stdout, fmt, ap); |
| - | fflush(stdout); |
| - | va_end(ap); |
| - | } |
| - | } |
| - | |
| - | static void mke2fs_verbose_done(void) |
| - | { |
| - | mke2fs_verbose("done\n"); |
| - | } |
| - | |
| - | static void mke2fs_warning_msg(int retval, char *fmt, ... ) __attribute__ ((format (printf, 2, 3))); |
| - | static void mke2fs_warning_msg(int retval, char *fmt, ... ) |
| - | { |
| - | va_list ap; |
| - | |
| - | if (retval) { |
| - | va_start(ap, fmt); |
| - | fprintf(stderr, "\nWarning: "); |
| - | vfprintf(stderr, fmt, ap); |
| - | fprintf(stderr, "\n"); |
| - | va_end(ap); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Reads the bad blocks list from a file |
| - | */ |
| - | static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list, |
| - | const char *bad_blocks_file) |
| - | { |
| - | FILE *f; |
| - | errcode_t retval; |
| - | |
| - | f = xfopen_for_read(bad_blocks_file); |
| - | retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block); |
| - | fclose (f); |
| - | mke2fs_error_msg_and_die(retval, "read bad blocks from list"); |
| - | } |
| - | |
| - | /* |
| - | * Runs the badblocks program to test the disk |
| - | */ |
| - | static void test_disk(ext2_filsys fs, badblocks_list *bb_list) |
| - | { |
| - | FILE *f; |
| - | errcode_t retval; |
| - | char buf[1024]; |
| - | |
| - | sprintf(buf, "badblocks -b %u %s%s%s %d", fs->blocksize, |
| - | quiet ? "" : "-s ", (cflag > 1) ? "-w " : "", |
| - | fs->device_name, fs->super->s_blocks_count); |
| - | mke2fs_verbose("Running command: %s\n", buf); |
| - | f = popen(buf, "r"); |
| - | if (!f) { |
| - | bb_perror_msg_and_die("can't run '%s'", buf); |
| - | } |
| - | retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block); |
| - | pclose(f); |
| - | mke2fs_error_msg_and_die(retval, "read bad blocks from program"); |
| - | } |
| - | |
| - | static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list) |
| - | { |
| - | dgrp_t i; |
| - | blk_t j; |
| - | unsigned must_be_good; |
| - | blk_t blk; |
| - | badblocks_iterate bb_iter; |
| - | errcode_t retval; |
| - | blk_t group_block; |
| - | int group; |
| - | int group_bad; |
| - | |
| - | if (!bb_list) |
| - | return; |
| - | |
| - | /* |
| - | * The primary superblock and group descriptors *must* be |
| - | * good; if not, abort. |
| - | */ |
| - | must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks; |
| - | for (i = fs->super->s_first_data_block; i <= must_be_good; i++) { |
| - | if (ext2fs_badblocks_list_test(bb_list, i)) { |
| - | bb_error_msg_and_die( |
| - | "Block %d in primary superblock/group descriptor area bad\n" |
| - | "Blocks %d through %d must be good in order to build a filesystem\n" |
| - | "Aborting ...", i, fs->super->s_first_data_block, must_be_good); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * See if any of the bad blocks are showing up in the backup |
| - | * superblocks and/or group descriptors. If so, issue a |
| - | * warning and adjust the block counts appropriately. |
| - | */ |
| - | group_block = fs->super->s_first_data_block + |
| - | fs->super->s_blocks_per_group; |
| - | |
| - | for (i = 1; i < fs->group_desc_count; i++) { |
| - | group_bad = 0; |
| - | for (j=0; j < fs->desc_blocks+1; j++) { |
| - | if (ext2fs_badblocks_list_test(bb_list, |
| - | group_block + j)) { |
| - | mke2fs_warning_msg(!group_bad, |
| - | "the backup superblock/group descriptors at block %d contain\n" |
| - | "bad blocks\n", group_block); |
| - | group_bad++; |
| - | group = ext2fs_group_of_blk(fs, group_block+j); |
| - | fs->group_desc[group].bg_free_blocks_count++; |
| - | fs->super->s_free_blocks_count++; |
| - | } |
| - | } |
| - | group_block += fs->super->s_blocks_per_group; |
| - | } |
| - | |
| - | /* |
| - | * Mark all the bad blocks as used... |
| - | */ |
| - | retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter); |
| - | mke2fs_error_msg_and_die(retval, "mark bad blocks as used"); |
| - | |
| - | while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) |
| - | ext2fs_mark_block_bitmap(fs->block_map, blk); |
| - | ext2fs_badblocks_list_iterate_end(bb_iter); |
| - | } |
| - | |
| - | /* |
| - | * These functions implement a generalized progress meter. |
| - | */ |
| - | struct progress_struct { |
| - | char format[20]; |
| - | char backup[80]; |
| - | __u32 max; |
| - | int skip_progress; |
| - | }; |
| - | |
| - | static void progress_init(struct progress_struct *progress, |
| - | const char *label,__u32 max) |
| - | { |
| - | int i; |
| - | |
| - | memset(progress, 0, sizeof(struct progress_struct)); |
| - | if (quiet) |
| - | return; |
| - | |
| - | /* |
| - | * Figure out how many digits we need |
| - | */ |
| - | i = int_log10(max); |
| - | sprintf(progress->format, "%%%dd/%%%dld", i, i); |
| - | memset(progress->backup, '\b', sizeof(progress->backup)-1); |
| - | progress->backup[sizeof(progress->backup)-1] = 0; |
| - | if ((2*i)+1 < (int) sizeof(progress->backup)) |
| - | progress->backup[(2*i)+1] = 0; |
| - | progress->max = max; |
| - | |
| - | progress->skip_progress = 0; |
| - | if (getenv("MKE2FS_SKIP_PROGRESS")) |
| - | progress->skip_progress++; |
| - | |
| - | fputs(label, stdout); |
| - | fflush(stdout); |
| - | } |
| - | |
| - | static void progress_update(struct progress_struct *progress, __u32 val) |
| - | { |
| - | if ((progress->format[0] == 0) || progress->skip_progress) |
| - | return; |
| - | printf(progress->format, val, progress->max); |
| - | fputs(progress->backup, stdout); |
| - | } |
| - | |
| - | static void progress_close(struct progress_struct *progress) |
| - | { |
| - | if (progress->format[0] == 0) |
| - | return; |
| - | printf("%-28s\n", "done"); |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Helper function which zeros out _num_ blocks starting at _blk_. In |
| - | * case of an error, the details of the error is returned via _ret_blk_ |
| - | * and _ret_count_ if they are non-NULL pointers. Returns 0 on |
| - | * success, and an error code on an error. |
| - | * |
| - | * As a special case, if the first argument is NULL, then it will |
| - | * attempt to free the static zeroizing buffer. (This is to keep |
| - | * programs that check for memory leaks happy.) |
| - | */ |
| - | static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num, |
| - | struct progress_struct *progress, |
| - | blk_t *ret_blk, int *ret_count) |
| - | { |
| - | int j, count, next_update; |
| - | static char *buf; |
| - | errcode_t retval; |
| - | |
| - | /* If fs is null, clean up the static buffer and return */ |
| - | if (!fs) { |
| - | if (buf) { |
| - | free(buf); |
| - | buf = 0; |
| - | } |
| - | return 0; |
| - | } |
| - | /* Allocate the zeroizing buffer if necessary */ |
| - | if (!buf) { |
| - | buf = xzalloc(fs->blocksize * STRIDE_LENGTH); |
| - | } |
| - | /* OK, do the write loop */ |
| - | next_update = 0; |
| - | |
| - | for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { |
| - | count = num - j; |
| - | if (count > STRIDE_LENGTH) |
| - | count = STRIDE_LENGTH; |
| - | retval = io_channel_write_blk(fs->io, blk, count, buf); |
| - | if (retval) { |
| - | if (ret_count) |
| - | *ret_count = count; |
| - | if (ret_blk) |
| - | *ret_blk = blk; |
| - | return retval; |
| - | } |
| - | if (progress && j > next_update) { |
| - | next_update += num / 100; |
| - | progress_update(progress, blk); |
| - | } |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static void write_inode_tables(ext2_filsys fs) |
| - | { |
| - | errcode_t retval; |
| - | blk_t blk; |
| - | dgrp_t i; |
| - | int num; |
| - | struct progress_struct progress; |
| - | |
| - | if (quiet) |
| - | memset(&progress, 0, sizeof(progress)); |
| - | else |
| - | progress_init(&progress, "Writing inode tables: ", |
| - | fs->group_desc_count); |
| - | |
| - | for (i = 0; i < fs->group_desc_count; i++) { |
| - | progress_update(&progress, i); |
| - | |
| - | blk = fs->group_desc[i].bg_inode_table; |
| - | num = fs->inode_blocks_per_group; |
| - | |
| - | retval = zero_blocks(fs, blk, num, 0, &blk, &num); |
| - | mke2fs_error_msg_and_die(retval, |
| - | "write %d blocks in inode table starting at %d.", |
| - | num, blk); |
| - | if (sync_kludge) { |
| - | if (sync_kludge == 1) |
| - | sync(); |
| - | else if ((i % sync_kludge) == 0) |
| - | sync(); |
| - | } |
| - | } |
| - | zero_blocks(0, 0, 0, 0, 0, 0); |
| - | progress_close(&progress); |
| - | } |
| - | |
| - | static void create_root_dir(ext2_filsys fs) |
| - | { |
| - | errcode_t retval; |
| - | struct ext2_inode inode; |
| - | |
| - | retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); |
| - | mke2fs_error_msg_and_die(retval, "create root dir"); |
| - | if (geteuid()) { |
| - | retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode); |
| - | mke2fs_error_msg_and_die(retval, "read root inode"); |
| - | inode.i_uid = getuid(); |
| - | if (inode.i_uid) |
| - | inode.i_gid = getgid(); |
| - | retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); |
| - | mke2fs_error_msg_and_die(retval, "set root inode ownership"); |
| - | } |
| - | } |
| - | |
| - | static void create_lost_and_found(ext2_filsys fs) |
| - | { |
| - | errcode_t retval; |
| - | ext2_ino_t ino; |
| - | const char *name = "lost+found"; |
| - | int i = 1; |
| - | char *msg = "create"; |
| - | int lpf_size = 0; |
| - | |
| - | fs->umask = 077; |
| - | retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name); |
| - | if (retval) { |
| - | goto CREATE_LOST_AND_FOUND_ERROR; |
| - | } |
| - | |
| - | retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino); |
| - | if (retval) { |
| - | msg = "lookup"; |
| - | goto CREATE_LOST_AND_FOUND_ERROR; |
| - | } |
| - | |
| - | for (; i < EXT2_NDIR_BLOCKS; i++) { |
| - | if ((lpf_size += fs->blocksize) >= 16*1024) |
| - | break; |
| - | retval = ext2fs_expand_dir(fs, ino); |
| - | msg = "expand"; |
| - | CREATE_LOST_AND_FOUND_ERROR: |
| - | mke2fs_error_msg_and_die(retval, "%s %s", msg, name); |
| - | } |
| - | } |
| - | |
| - | static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list) |
| - | { |
| - | errcode_t retval; |
| - | |
| - | ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO); |
| - | fs->group_desc[0].bg_free_inodes_count--; |
| - | fs->super->s_free_inodes_count--; |
| - | retval = ext2fs_update_bb_inode(fs, bb_list); |
| - | mke2fs_error_msg_and_die(retval, "set bad block inode"); |
| - | } |
| - | |
| - | static void reserve_inodes(ext2_filsys fs) |
| - | { |
| - | ext2_ino_t i; |
| - | int group; |
| - | |
| - | for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) { |
| - | ext2fs_mark_inode_bitmap(fs->inode_map, i); |
| - | group = ext2fs_group_of_ino(fs, i); |
| - | fs->group_desc[group].bg_free_inodes_count--; |
| - | fs->super->s_free_inodes_count--; |
| - | } |
| - | ext2fs_mark_ib_dirty(fs); |
| - | } |
| - | |
| - | #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ |
| - | #define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */ |
| - | #define BSD_LABEL_OFFSET 64 |
| - | |
| - | static void zap_sector(ext2_filsys fs, int sect, int nsect) |
| - | { |
| - | char *buf; |
| - | char *fmt = "could not %s %d"; |
| - | int retval; |
| - | unsigned int *magic; |
| - | |
| - | buf = xmalloc(512*nsect); |
| - | |
| - | if (sect == 0) { |
| - | /* Check for a BSD disklabel, and don't erase it if so */ |
| - | retval = io_channel_read_blk(fs->io, 0, -512, buf); |
| - | if (retval) |
| - | mke2fs_warning_msg(retval, fmt, "read block", 0); |
| - | else { |
| - | magic = (unsigned int *) (buf + BSD_LABEL_OFFSET); |
| - | if ((*magic == BSD_DISKMAGIC) || |
| - | (*magic == BSD_MAGICDISK)) |
| - | return; |
| - | } |
| - | } |
| - | |
| - | memset(buf, 0, 512*nsect); |
| - | io_channel_set_blksize(fs->io, 512); |
| - | retval = io_channel_write_blk(fs->io, sect, -512*nsect, buf); |
| - | io_channel_set_blksize(fs->io, fs->blocksize); |
| - | free(buf); |
| - | mke2fs_warning_msg(retval, fmt, "erase sector", sect); |
| - | } |
| - | |
| - | static void create_journal_dev(ext2_filsys fs) |
| - | { |
| - | struct progress_struct progress; |
| - | errcode_t retval; |
| - | char *buf; |
| - | char *fmt = "%s journal superblock"; |
| - | blk_t blk; |
| - | int count; |
| - | |
| - | retval = ext2fs_create_journal_superblock(fs, |
| - | fs->super->s_blocks_count, 0, &buf); |
| - | mke2fs_error_msg_and_die(retval, fmt, "init"); |
| - | if (quiet) |
| - | memset(&progress, 0, sizeof(progress)); |
| - | else |
| - | progress_init(&progress, "Zeroing journal device: ", |
| - | fs->super->s_blocks_count); |
| - | |
| - | retval = zero_blocks(fs, 0, fs->super->s_blocks_count, |
| - | &progress, &blk, &count); |
| - | mke2fs_error_msg_and_die(retval, "zero journal device (block %u, count %d)", |
| - | blk, count); |
| - | zero_blocks(0, 0, 0, 0, 0, 0); |
| - | |
| - | retval = io_channel_write_blk(fs->io, |
| - | fs->super->s_first_data_block+1, |
| - | 1, buf); |
| - | mke2fs_error_msg_and_die(retval, fmt, "write"); |
| - | progress_close(&progress); |
| - | } |
| - | |
| - | static void show_stats(ext2_filsys fs) |
| - | { |
| - | struct ext2_super_block *s = fs->super; |
| - | char *os; |
| - | blk_t group_block; |
| - | dgrp_t i; |
| - | int need, col_left; |
| - | |
| - | mke2fs_warning_msg((param.s_blocks_count != s->s_blocks_count), |
| - | "%d blocks unused\n", param.s_blocks_count - s->s_blocks_count); |
| - | os = e2p_os2string(fs->super->s_creator_os); |
| - | printf( "Filesystem label=%.*s\n" |
| - | "OS type: %s\n" |
| - | "Block size=%u (log=%u)\n" |
| - | "Fragment size=%u (log=%u)\n" |
| - | "%u inodes, %u blocks\n" |
| - | "%u blocks (%2.2f%%) reserved for the super user\n" |
| - | "First data block=%u\n", |
| - | (int) sizeof(s->s_volume_name), |
| - | s->s_volume_name, |
| - | os, |
| - | fs->blocksize, s->s_log_block_size, |
| - | fs->fragsize, s->s_log_frag_size, |
| - | s->s_inodes_count, s->s_blocks_count, |
| - | s->s_r_blocks_count, 100.0 * s->s_r_blocks_count / s->s_blocks_count, |
| - | s->s_first_data_block); |
| - | free(os); |
| - | if (s->s_reserved_gdt_blocks) { |
| - | printf("Maximum filesystem blocks=%lu\n", |
| - | (s->s_reserved_gdt_blocks + fs->desc_blocks) * |
| - | (fs->blocksize / sizeof(struct ext2_group_desc)) * |
| - | s->s_blocks_per_group); |
| - | } |
| - | printf( "%u block group%s\n" |
| - | "%u blocks per group, %u fragments per group\n" |
| - | "%u inodes per group\n", |
| - | fs->group_desc_count, (fs->group_desc_count > 1) ? "s" : "", |
| - | s->s_blocks_per_group, s->s_frags_per_group, |
| - | s->s_inodes_per_group); |
| - | if (fs->group_desc_count == 1) { |
| - | bb_putchar('\n'); |
| - | return; |
| - | } |
| - | |
| - | printf("Superblock backups stored on blocks: "); |
| - | group_block = s->s_first_data_block; |
| - | col_left = 0; |
| - | for (i = 1; i < fs->group_desc_count; i++) { |
| - | group_block += s->s_blocks_per_group; |
| - | if (!ext2fs_bg_has_super(fs, i)) |
| - | continue; |
| - | if (i != 1) |
| - | printf(", "); |
| - | need = int_log10(group_block) + 2; |
| - | if (need > col_left) { |
| - | printf("\n\t"); |
| - | col_left = 72; |
| - | } |
| - | col_left -= need; |
| - | printf("%u", group_block); |
| - | } |
| - | puts("\n"); |
| - | } |
| - | |
| - | /* |
| - | * Set the S_CREATOR_OS field. Return true if OS is known, |
| - | * otherwise, 0. |
| - | */ |
| - | static int set_os(struct ext2_super_block *sb, char *os) |
| - | { |
| - | if (isdigit (*os)) { |
| - | sb->s_creator_os = atoi(os); |
| - | return 1; |
| - | } |
| - | |
| - | if ((sb->s_creator_os = e2p_string2os(os)) >= 0) { |
| - | return 1; |
| - | } else if (!strcasecmp("GNU", os)) { |
| - | sb->s_creator_os = EXT2_OS_HURD; |
| - | return 1; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | static void parse_extended_opts(struct ext2_super_block *sb_param, |
| - | const char *opts) |
| - | { |
| - | char *buf, *token, *next, *p, *arg; |
| - | int r_usage = 0; |
| - | |
| - | buf = xstrdup(opts); |
| - | for (token = buf; token && *token; token = next) { |
| - | p = strchr(token, ','); |
| - | next = 0; |
| - | if (p) { |
| - | *p = 0; |
| - | next = p+1; |
| - | } |
| - | arg = strchr(token, '='); |
| - | if (arg) { |
| - | *arg = 0; |
| - | arg++; |
| - | } |
| - | if (strcmp(token, "stride") == 0) { |
| - | if (!arg) { |
| - | r_usage++; |
| - | continue; |
| - | } |
| - | fs_stride = strtoul(arg, &p, 0); |
| - | if (*p || (fs_stride == 0)) { |
| - | bb_error_msg("Invalid stride parameter: %s", arg); |
| - | r_usage++; |
| - | continue; |
| - | } |
| - | } else if (!strcmp(token, "resize")) { |
| - | unsigned long resize, bpg, rsv_groups; |
| - | unsigned long group_desc_count, desc_blocks; |
| - | unsigned int gdpb, blocksize; |
| - | int rsv_gdb; |
| - | |
| - | if (!arg) { |
| - | r_usage++; |
| - | continue; |
| - | } |
| - | |
| - | resize = parse_num_blocks(arg, |
| - | sb_param->s_log_block_size); |
| - | |
| - | if (resize == 0) { |
| - | bb_error_msg("Invalid resize parameter: %s", arg); |
| - | r_usage++; |
| - | continue; |
| - | } |
| - | if (resize <= sb_param->s_blocks_count) { |
| - | bb_error_msg("The resize maximum must be greater " |
| - | "than the filesystem size"); |
| - | r_usage++; |
| - | continue; |
| - | } |
| - | |
| - | blocksize = EXT2_BLOCK_SIZE(sb_param); |
| - | bpg = sb_param->s_blocks_per_group; |
| - | if (!bpg) |
| - | bpg = blocksize * 8; |
| - | gdpb = blocksize / sizeof(struct ext2_group_desc); |
| - | group_desc_count = (sb_param->s_blocks_count + |
| - | bpg - 1) / bpg; |
| - | desc_blocks = (group_desc_count + |
| - | gdpb - 1) / gdpb; |
| - | rsv_groups = (resize + bpg - 1) / bpg; |
| - | rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - |
| - | desc_blocks; |
| - | if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb_param)) |
| - | rsv_gdb = EXT2_ADDR_PER_BLOCK(sb_param); |
| - | |
| - | if (rsv_gdb > 0) { |
| - | sb_param->s_feature_compat |= |
| - | EXT2_FEATURE_COMPAT_RESIZE_INO; |
| - | |
| - | sb_param->s_reserved_gdt_blocks = rsv_gdb; |
| - | } |
| - | } else |
| - | r_usage++; |
| - | } |
| - | if (r_usage) { |
| - | bb_error_msg_and_die( |
| - | "\nBad options specified.\n\n" |
| - | "Extended options are separated by commas, " |
| - | "and may take an argument which\n" |
| - | "\tis set off by an equals ('=') sign.\n\n" |
| - | "Valid extended options are:\n" |
| - | "\tstride=<stride length in blocks>\n" |
| - | "\tresize=<resize maximum size in blocks>\n"); |
| - | } |
| - | } |
| - | |
| - | static __u32 ok_features[3] = { |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL | |
| - | EXT2_FEATURE_COMPAT_RESIZE_INO | |
| - | EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */ |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE| /* Incompat */ |
| - | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV| |
| - | EXT2_FEATURE_INCOMPAT_META_BG, |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */ |
| - | }; |
| - | |
| - | static int PRS(int argc, char **argv) |
| - | { |
| - | int c; |
| - | int size; |
| - | char * tmp; |
| - | int blocksize = 0; |
| - | int inode_ratio = 0; |
| - | int inode_size = 0; |
| - | int reserved_ratio = 5; |
| - | int sector_size = 0; |
| - | int show_version_only = 0; |
| - | ext2_ino_t num_inodes = 0; |
| - | errcode_t retval; |
| - | char * extended_opts = NULL; |
| - | const char * fs_type = NULL; |
| - | blk_t dev_size; |
| - | long sysval; |
| - | |
| - | /* Update our PATH to include /sbin */ |
| - | e2fs_set_sbin_path(); |
| - | |
| - | tmp = getenv("MKE2FS_SYNC"); |
| - | if (tmp) |
| - | sync_kludge = atoi(tmp); |
| - | |
| - | /* Determine the system page size if possible */ |
| - | #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)) |
| - | #define _SC_PAGESIZE _SC_PAGE_SIZE |
| - | #endif |
| - | #ifdef _SC_PAGESIZE |
| - | sysval = sysconf(_SC_PAGESIZE); |
| - | if (sysval > 0) |
| - | sys_page_size = sysval; |
| - | #endif /* _SC_PAGESIZE */ |
| - | |
| - | setbuf(stdout, NULL); |
| - | setbuf(stderr, NULL); |
| - | memset(¶m, 0, sizeof(struct ext2_super_block)); |
| - | param.s_rev_level = 1; /* Create revision 1 filesystems now */ |
| - | param.s_feature_incompat |= EXT2_FEATURE_INCOMPAT_FILETYPE; |
| - | param.s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | |
| - | #ifdef __linux__ |
| - | linux_version_code = get_linux_version_code(); |
| - | if (linux_version_code && linux_version_code < KERNEL_VERSION(2,2,0)) { |
| - | param.s_rev_level = 0; |
| - | param.s_feature_incompat = 0; |
| - | param.s_feature_compat = 0; |
| - | param.s_feature_ro_compat = 0; |
| - | } |
| - | #endif |
| - | |
| - | /* If called as mkfs.ext3, create a journal inode */ |
| - | if (last_char_is(applet_name, '3')) |
| - | journal_size = -1; |
| - | |
| - | while ((c = getopt (argc, argv, |
| - | "b:cE:f:g:i:jl:m:no:qr:R:s:tvI:J:ST:FL:M:N:O:V")) != EOF) { |
| - | switch (c) { |
| - | case 'b': |
| - | blocksize = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE); |
| - | mke2fs_warning_msg((blocksize > 4096), |
| - | "blocksize %d not usable on most systems", |
| - | blocksize); |
| - | param.s_log_block_size = |
| - | int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); |
| - | break; |
| - | case 'c': /* Check for bad blocks */ |
| - | case 't': /* deprecated */ |
| - | cflag++; |
| - | break; |
| - | case 'f': |
| - | size = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE); |
| - | param.s_log_frag_size = |
| - | int_log2(size >> EXT2_MIN_BLOCK_LOG_SIZE); |
| - | mke2fs_warning_msg(1, "fragments not supported. Ignoring -f option"); |
| - | break; |
| - | case 'g': |
| - | param.s_blocks_per_group = xatou32(optarg); |
| - | if ((param.s_blocks_per_group % 8) != 0) { |
| - | bb_error_msg_and_die("blocks per group must be multiple of 8"); |
| - | } |
| - | break; |
| - | case 'i': |
| - | /* Huh? is "* 1024" correct? */ |
| - | inode_ratio = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE * 1024); |
| - | break; |
| - | case 'J': |
| - | parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg); |
| - | break; |
| - | case 'j': |
| - | param.s_feature_compat |= |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | if (!journal_size) |
| - | journal_size = -1; |
| - | break; |
| - | case 'l': |
| - | bad_blocks_filename = optarg; |
| - | break; |
| - | case 'm': |
| - | reserved_ratio = xatou_range(optarg, 0, 50); |
| - | break; |
| - | case 'n': |
| - | noaction++; |
| - | break; |
| - | case 'o': |
| - | creator_os = optarg; |
| - | break; |
| - | case 'r': |
| - | param.s_rev_level = xatoi_positive(optarg); |
| - | if (param.s_rev_level == EXT2_GOOD_OLD_REV) { |
| - | param.s_feature_incompat = 0; |
| - | param.s_feature_compat = 0; |
| - | param.s_feature_ro_compat = 0; |
| - | } |
| - | break; |
| - | case 's': /* deprecated */ |
| - | if (xatou(optarg)) |
| - | param.s_feature_ro_compat |= |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | else |
| - | param.s_feature_ro_compat &= |
| - | ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | break; |
| - | #ifdef EXT2_DYNAMIC_REV |
| - | case 'I': |
| - | inode_size = xatoi_positive(optarg); |
| - | break; |
| - | #endif |
| - | case 'N': |
| - | num_inodes = xatoi_positive(optarg); |
| - | break; |
| - | case 'v': |
| - | quiet = 0; |
| - | break; |
| - | case 'q': |
| - | quiet = 1; |
| - | break; |
| - | case 'F': |
| - | force = 1; |
| - | break; |
| - | case 'L': |
| - | volume_label = optarg; |
| - | break; |
| - | case 'M': |
| - | mount_dir = optarg; |
| - | break; |
| - | case 'O': |
| - | if (!strcmp(optarg, "none")) { |
| - | param.s_feature_compat = 0; |
| - | param.s_feature_incompat = 0; |
| - | param.s_feature_ro_compat = 0; |
| - | break; |
| - | } |
| - | if (e2p_edit_feature(optarg, |
| - | ¶m.s_feature_compat, |
| - | ok_features)) { |
| - | bb_error_msg_and_die("Invalid filesystem option set: %s", optarg); |
| - | } |
| - | break; |
| - | case 'E': |
| - | case 'R': |
| - | extended_opts = optarg; |
| - | break; |
| - | case 'S': |
| - | super_only = 1; |
| - | break; |
| - | case 'T': |
| - | fs_type = optarg; |
| - | break; |
| - | case 'V': |
| - | /* Print version number and exit */ |
| - | show_version_only = 1; |
| - | quiet = 0; |
| - | break; |
| - | default: |
| - | bb_show_usage(); |
| - | } |
| - | } |
| - | if ((optind == argc) /*&& !show_version_only*/) |
| - | bb_show_usage(); |
| - | device_name = argv[optind++]; |
| - | |
| - | mke2fs_verbose("mke2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); |
| - | |
| - | if (show_version_only) { |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * If there's no blocksize specified and there is a journal |
| - | * device, use it to figure out the blocksize |
| - | */ |
| - | if (blocksize <= 0 && journal_device) { |
| - | ext2_filsys jfs; |
| - | io_manager io_ptr; |
| - | |
| - | #ifdef CONFIG_TESTIO_DEBUG |
| - | io_ptr = test_io_manager; |
| - | test_io_backing_manager = unix_io_manager; |
| - | #else |
| - | io_ptr = unix_io_manager; |
| - | #endif |
| - | retval = ext2fs_open(journal_device, |
| - | EXT2_FLAG_JOURNAL_DEV_OK, 0, |
| - | 0, io_ptr, &jfs); |
| - | mke2fs_error_msg_and_die(retval, "open journal device %s", journal_device); |
| - | if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) { |
| - | bb_error_msg_and_die( |
| - | "Journal dev blocksize (%d) smaller than " |
| - | "minimum blocksize %d\n", jfs->blocksize, |
| - | -blocksize); |
| - | } |
| - | blocksize = jfs->blocksize; |
| - | param.s_log_block_size = |
| - | int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); |
| - | ext2fs_close(jfs); |
| - | } |
| - | |
| - | if (blocksize > sys_page_size) { |
| - | mke2fs_warning_msg(1, "%d-byte blocks too big for system (max %d)", |
| - | blocksize, sys_page_size); |
| - | if (!force) { |
| - | proceed_question(); |
| - | } |
| - | bb_error_msg("Forced to continue"); |
| - | } |
| - | mke2fs_warning_msg(((blocksize > 4096) && |
| - | (param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)), |
| - | "some 2.4 kernels do not support " |
| - | "blocksizes greater than 4096 using ext3.\n" |
| - | "Use -b 4096 if this is an issue for you\n"); |
| - | |
| - | if (optind < argc) { |
| - | param.s_blocks_count = parse_num_blocks(argv[optind++], |
| - | param.s_log_block_size); |
| - | mke2fs_error_msg_and_die(!param.s_blocks_count, "invalid blocks count - %s", argv[optind - 1]); |
| - | } |
| - | if (optind < argc) |
| - | bb_show_usage(); |
| - | |
| - | if (param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { |
| - | if (!fs_type) |
| - | fs_type = "journal"; |
| - | reserved_ratio = 0; |
| - | param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; |
| - | param.s_feature_compat = 0; |
| - | param.s_feature_ro_compat = 0; |
| - | } |
| - | if (param.s_rev_level == EXT2_GOOD_OLD_REV && |
| - | (param.s_feature_compat || param.s_feature_ro_compat || |
| - | param.s_feature_incompat)) |
| - | param.s_rev_level = 1; /* Create a revision 1 filesystem */ |
| - | |
| - | check_plausibility(device_name , force); |
| - | check_mount(device_name, force, "filesystem"); |
| - | |
| - | param.s_log_frag_size = param.s_log_block_size; |
| - | |
| - | if (noaction && param.s_blocks_count) { |
| - | dev_size = param.s_blocks_count; |
| - | retval = 0; |
| - | } else { |
| - | retry: |
| - | retval = ext2fs_get_device_size(device_name, |
| - | EXT2_BLOCK_SIZE(¶m), |
| - | &dev_size); |
| - | if ((retval == EFBIG) && |
| - | (blocksize == 0) && |
| - | (param.s_log_block_size == 0)) { |
| - | param.s_log_block_size = 2; |
| - | blocksize = 4096; |
| - | goto retry; |
| - | } |
| - | } |
| - | |
| - | mke2fs_error_msg_and_die((retval && (retval != EXT2_ET_UNIMPLEMENTED)),"determine filesystem size"); |
| - | |
| - | if (!param.s_blocks_count) { |
| - | if (retval == EXT2_ET_UNIMPLEMENTED) { |
| - | mke2fs_error_msg_and_die(1, |
| - | "determine device size; you " |
| - | "must specify\nthe size of the " |
| - | "filesystem"); |
| - | } else { |
| - | if (dev_size == 0) { |
| - | bb_error_msg_and_die( |
| - | "Device size reported to be zero. " |
| - | "Invalid partition specified, or\n\t" |
| - | "partition table wasn't reread " |
| - | "after running fdisk, due to\n\t" |
| - | "a modified partition being busy " |
| - | "and in use. You may need to reboot\n\t" |
| - | "to re-read your partition table.\n" |
| - | ); |
| - | } |
| - | param.s_blocks_count = dev_size; |
| - | if (sys_page_size > EXT2_BLOCK_SIZE(¶m)) |
| - | param.s_blocks_count &= ~((sys_page_size / |
| - | EXT2_BLOCK_SIZE(¶m))-1); |
| - | } |
| - | |
| - | } else if (!force && (param.s_blocks_count > dev_size)) { |
| - | bb_error_msg("Filesystem larger than apparent device size"); |
| - | proceed_question(); |
| - | } |
| - | |
| - | /* |
| - | * If the user asked for HAS_JOURNAL, then make sure a journal |
| - | * gets created. |
| - | */ |
| - | if ((param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
| - | !journal_size) |
| - | journal_size = -1; |
| - | |
| - | /* Set first meta blockgroup via an environment variable */ |
| - | /* (this is mostly for debugging purposes) */ |
| - | if ((param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) && |
| - | ((tmp = getenv("MKE2FS_FIRST_META_BG")))) |
| - | param.s_first_meta_bg = atoi(tmp); |
| - | |
| - | /* Get the hardware sector size, if available */ |
| - | retval = ext2fs_get_device_sectsize(device_name, §or_size); |
| - | mke2fs_error_msg_and_die(retval, "determine hardware sector size"); |
| - | |
| - | if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL) |
| - | sector_size = atoi(tmp); |
| - | |
| - | set_fs_defaults(fs_type, ¶m, blocksize, sector_size, &inode_ratio); |
| - | blocksize = EXT2_BLOCK_SIZE(¶m); |
| - | |
| - | if (extended_opts) |
| - | parse_extended_opts(¶m, extended_opts); |
| - | |
| - | /* Since sparse_super is the default, we would only have a problem |
| - | * here if it was explicitly disabled. |
| - | */ |
| - | if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) && |
| - | !(param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) { |
| - | bb_error_msg_and_die("reserved online resize blocks not supported " |
| - | "on non-sparse filesystem"); |
| - | } |
| - | |
| - | if (param.s_blocks_per_group) { |
| - | if (param.s_blocks_per_group < 256 || |
| - | param.s_blocks_per_group > 8 * (unsigned) blocksize) { |
| - | bb_error_msg_and_die("blocks per group count out of range"); |
| - | } |
| - | } |
| - | |
| - | if (!force && param.s_blocks_count >= (1 << 31)) { |
| - | bb_error_msg_and_die("Filesystem too large. No more than 2**31-1 blocks\n" |
| - | "\t (8TB using a blocksize of 4k) are currently supported."); |
| - | } |
| - | |
| - | if (inode_size) { |
| - | if (inode_size < EXT2_GOOD_OLD_INODE_SIZE || |
| - | inode_size > EXT2_BLOCK_SIZE(¶m) || |
| - | inode_size & (inode_size - 1)) { |
| - | bb_error_msg_and_die("invalid inode size %d (min %d/max %d)", |
| - | inode_size, EXT2_GOOD_OLD_INODE_SIZE, |
| - | blocksize); |
| - | } |
| - | mke2fs_warning_msg((inode_size != EXT2_GOOD_OLD_INODE_SIZE), |
| - | "%d-byte inodes not usable on most systems", |
| - | inode_size); |
| - | param.s_inode_size = inode_size; |
| - | } |
| - | |
| - | /* |
| - | * Calculate number of inodes based on the inode ratio |
| - | */ |
| - | param.s_inodes_count = num_inodes ? num_inodes : |
| - | ((__u64) param.s_blocks_count * blocksize) |
| - | / inode_ratio; |
| - | |
| - | /* |
| - | * Calculate number of blocks to reserve |
| - | */ |
| - | param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100; |
| - | return 1; |
| - | } |
| - | |
| - | static void mke2fs_clean_up(void) |
| - | { |
| - | if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device); |
| - | } |
| - | |
| - | int mke2fs_main (int argc, char **argv); |
| - | int mke2fs_main (int argc, char **argv) |
| - | { |
| - | errcode_t retval; |
| - | ext2_filsys fs; |
| - | badblocks_list bb_list = 0; |
| - | unsigned int i; |
| - | int val; |
| - | io_manager io_ptr; |
| - | |
| - | if (ENABLE_FEATURE_CLEAN_UP) |
| - | atexit(mke2fs_clean_up); |
| - | if (!PRS(argc, argv)) |
| - | return 0; |
| - | |
| - | #ifdef CONFIG_TESTIO_DEBUG |
| - | io_ptr = test_io_manager; |
| - | test_io_backing_manager = unix_io_manager; |
| - | #else |
| - | io_ptr = unix_io_manager; |
| - | #endif |
| - | |
| - | /* |
| - | * Initialize the superblock.... |
| - | */ |
| - | retval = ext2fs_initialize(device_name, 0, ¶m, |
| - | io_ptr, &fs); |
| - | mke2fs_error_msg_and_die(retval, "set up superblock"); |
| - | |
| - | /* |
| - | * Wipe out the old on-disk superblock |
| - | */ |
| - | if (!noaction) |
| - | zap_sector(fs, 2, 6); |
| - | |
| - | /* |
| - | * Generate a UUID for it... |
| - | */ |
| - | uuid_generate(fs->super->s_uuid); |
| - | |
| - | /* |
| - | * Initialize the directory index variables |
| - | */ |
| - | fs->super->s_def_hash_version = EXT2_HASH_TEA; |
| - | uuid_generate((unsigned char *) fs->super->s_hash_seed); |
| - | |
| - | /* |
| - | * Add "jitter" to the superblock's check interval so that we |
| - | * don't check all the filesystems at the same time. We use a |
| - | * kludgy hack of using the UUID to derive a random jitter value. |
| - | */ |
| - | for (i = 0, val = 0; i < sizeof(fs->super->s_uuid); i++) |
| - | val += fs->super->s_uuid[i]; |
| - | fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT; |
| - | |
| - | /* |
| - | * Override the creator OS, if applicable |
| - | */ |
| - | if (creator_os && !set_os(fs->super, creator_os)) { |
| - | bb_error_msg_and_die("unknown os - %s", creator_os); |
| - | } |
| - | |
| - | /* |
| - | * For the Hurd, we will turn off filetype since it doesn't |
| - | * support it. |
| - | */ |
| - | if (fs->super->s_creator_os == EXT2_OS_HURD) |
| - | fs->super->s_feature_incompat &= |
| - | ~EXT2_FEATURE_INCOMPAT_FILETYPE; |
| - | |
| - | /* |
| - | * Set the volume label... |
| - | */ |
| - | if (volume_label) { |
| - | snprintf(fs->super->s_volume_name, sizeof(fs->super->s_volume_name), "%s", volume_label); |
| - | } |
| - | |
| - | /* |
| - | * Set the last mount directory |
| - | */ |
| - | if (mount_dir) { |
| - | snprintf(fs->super->s_last_mounted, sizeof(fs->super->s_last_mounted), "%s", mount_dir); |
| - | } |
| - | |
| - | if (!quiet || noaction) |
| - | show_stats(fs); |
| - | |
| - | if (noaction) |
| - | return 0; |
| - | |
| - | if (fs->super->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { |
| - | create_journal_dev(fs); |
| - | return (ext2fs_close(fs) ? 1 : 0); |
| - | } |
| - | |
| - | if (bad_blocks_filename) |
| - | read_bb_file(fs, &bb_list, bad_blocks_filename); |
| - | if (cflag) |
| - | test_disk(fs, &bb_list); |
| - | |
| - | handle_bad_blocks(fs, bb_list); |
| - | fs->stride = fs_stride; |
| - | retval = ext2fs_allocate_tables(fs); |
| - | mke2fs_error_msg_and_die(retval, "allocate filesystem tables"); |
| - | if (super_only) { |
| - | fs->super->s_state |= EXT2_ERROR_FS; |
| - | fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY); |
| - | } else { |
| - | /* rsv must be a power of two (64kB is MD RAID sb alignment) */ |
| - | unsigned int rsv = 65536 / fs->blocksize; |
| - | unsigned long blocks = fs->super->s_blocks_count; |
| - | unsigned long start; |
| - | blk_t ret_blk; |
| - | |
| - | #ifdef ZAP_BOOTBLOCK |
| - | zap_sector(fs, 0, 2); |
| - | #endif |
| - | |
| - | /* |
| - | * Wipe out any old MD RAID (or other) metadata at the end |
| - | * of the device. This will also verify that the device is |
| - | * as large as we think. Be careful with very small devices. |
| - | */ |
| - | start = (blocks & ~(rsv - 1)); |
| - | if (start > rsv) |
| - | start -= rsv; |
| - | if (start > 0) |
| - | retval = zero_blocks(fs, start, blocks - start, |
| - | NULL, &ret_blk, NULL); |
| - | |
| - | mke2fs_warning_msg(retval, "can't zero block %u at end of filesystem", ret_blk); |
| - | write_inode_tables(fs); |
| - | create_root_dir(fs); |
| - | create_lost_and_found(fs); |
| - | reserve_inodes(fs); |
| - | create_bad_block_inode(fs, bb_list); |
| - | if (fs->super->s_feature_compat & |
| - | EXT2_FEATURE_COMPAT_RESIZE_INO) { |
| - | retval = ext2fs_create_resize_inode(fs); |
| - | mke2fs_error_msg_and_die(retval, "reserve blocks for online resize"); |
| - | } |
| - | } |
| - | |
| - | if (journal_device) { |
| - | make_journal_device(journal_device, fs, quiet, force); |
| - | } else if (journal_size) { |
| - | make_journal_blocks(fs, journal_size, journal_flags, quiet); |
| - | } |
| - | |
| - | mke2fs_verbose("Writing superblocks and filesystem accounting information: "); |
| - | retval = ext2fs_flush(fs); |
| - | mke2fs_warning_msg(retval, "had trouble writing out superblocks"); |
| - | mke2fs_verbose_done(); |
| - | if (!quiet && !getenv("MKE2FS_SKIP_CHECK_MSG")) |
| - | print_check_message(fs); |
| - | val = ext2fs_close(fs); |
| - | return (retval || val) ? 1 : 0; |
| - | } |
| @@ -1,710 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * tune2fs.c - Change the file system parameters on an ext2 file system |
| - | * |
| - | * Copyright (C) 1992, 1993, 1994 Remy Card <[email protected]> |
| - | * Laboratoire MASI, Institut Blaise Pascal |
| - | * Universite Pierre et Marie Curie (Paris VI) |
| - | * |
| - | * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. |
| - | * |
| - | * Licensed under GPLv2, see file LICENSE in this source tree. |
| - | */ |
| - | |
| - | /* |
| - | * History: |
| - | * 93/06/01 - Creation |
| - | * 93/10/31 - Added the -c option to change the maximal mount counts |
| - | * 93/12/14 - Added -l flag to list contents of superblock |
| - | * M.J.E. Mol ([email protected]) |
| - | * F.W. ten Wolde ([email protected]) |
| - | * 93/12/29 - Added the -e option to change errors behavior |
| - | * 94/02/27 - Ported to use the ext2fs library |
| - | * 94/03/06 - Added the checks interval from Uwe Ohse ([email protected]) |
| - | */ |
| - | |
| - | #include <sys/types.h> |
| - | #include <fcntl.h> |
| - | #include <stdio.h> |
| - | #include <stdlib.h> |
| - | #include <string.h> |
| - | #include <time.h> |
| - | #include <unistd.h> |
| - | #include <getopt.h> |
| - | |
| - | #include "e2fsbb.h" |
| - | #include "ext2fs/ext2_fs.h" |
| - | #include "ext2fs/ext2fs.h" |
| - | #include "uuid/uuid.h" |
| - | #include "e2p/e2p.h" |
| - | #include "ext2fs/kernel-jbd.h" |
| - | #include "util.h" |
| - | #include "blkid/blkid.h" |
| - | |
| - | #include "libbb.h" |
| - | |
| - | static char * device_name = NULL; |
| - | static char * new_label, *new_last_mounted, *new_UUID; |
| - | static char * io_options; |
| - | static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; |
| - | static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; |
| - | static time_t last_check_time; |
| - | static int print_label; |
| - | static int max_mount_count, mount_count, mount_flags; |
| - | static unsigned long interval, reserved_blocks; |
| - | static unsigned reserved_ratio; |
| - | static unsigned long resgid, resuid; |
| - | static unsigned short errors; |
| - | static int open_flag; |
| - | static char *features_cmd; |
| - | static char *mntopts_cmd; |
| - | |
| - | static int journal_size, journal_flags; |
| - | static char *journal_device = NULL; |
| - | |
| - | static const char *please_fsck = "Please run e2fsck on the filesystem\n"; |
| - | |
| - | static __u32 ok_features[3] = { |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL | EXT2_FEATURE_COMPAT_DIR_INDEX, |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE, |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
| - | }; |
| - | |
| - | /* |
| - | * Remove an external journal from the filesystem |
| - | */ |
| - | static void remove_journal_device(ext2_filsys fs) |
| - | { |
| - | char *journal_path; |
| - | ext2_filsys jfs; |
| - | char buf[1024]; |
| - | journal_superblock_t *jsb; |
| - | int i, nr_users; |
| - | errcode_t retval; |
| - | int commit_remove_journal = 0; |
| - | io_manager io_ptr; |
| - | |
| - | if (f_flag) |
| - | commit_remove_journal = 1; /* force removal even if error */ |
| - | |
| - | uuid_unparse(fs->super->s_journal_uuid, buf); |
| - | journal_path = blkid_get_devname(NULL, "UUID", buf); |
| - | |
| - | if (!journal_path) { |
| - | journal_path = |
| - | ext2fs_find_block_device(fs->super->s_journal_dev); |
| - | if (!journal_path) |
| - | return; |
| - | } |
| - | |
| - | io_ptr = unix_io_manager; |
| - | retval = ext2fs_open(journal_path, EXT2_FLAG_RW| |
| - | EXT2_FLAG_JOURNAL_DEV_OK, 0, |
| - | fs->blocksize, io_ptr, &jfs); |
| - | if (retval) { |
| - | bb_error_msg("Failed to open external journal"); |
| - | goto no_valid_journal; |
| - | } |
| - | if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { |
| - | bb_error_msg("%s is not a journal device", journal_path); |
| - | goto no_valid_journal; |
| - | } |
| - | |
| - | /* Get the journal superblock */ |
| - | if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { |
| - | bb_error_msg("Failed to read journal superblock"); |
| - | goto no_valid_journal; |
| - | } |
| - | |
| - | 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))) { |
| - | bb_error_msg("Journal superblock not found!"); |
| - | goto no_valid_journal; |
| - | } |
| - | |
| - | /* Find the filesystem UUID */ |
| - | 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) { |
| - | bb_error_msg("Filesystem's UUID not found on journal device"); |
| - | commit_remove_journal = 1; |
| - | goto no_valid_journal; |
| - | } |
| - | nr_users--; |
| - | for (i=0; i < nr_users; i++) |
| - | memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); |
| - | jsb->s_nr_users = htonl(nr_users); |
| - | |
| - | /* Write back the journal superblock */ |
| - | if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { |
| - | bb_error_msg("Failed to write journal superblock"); |
| - | goto no_valid_journal; |
| - | } |
| - | |
| - | commit_remove_journal = 1; |
| - | |
| - | no_valid_journal: |
| - | if (commit_remove_journal == 0) |
| - | bb_error_msg_and_die("Journal NOT removed"); |
| - | fs->super->s_journal_dev = 0; |
| - | uuid_clear(fs->super->s_journal_uuid); |
| - | ext2fs_mark_super_dirty(fs); |
| - | puts("Journal removed"); |
| - | free(journal_path); |
| - | } |
| - | |
| - | /* Helper function for remove_journal_inode */ |
| - | static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, |
| - | int blockcnt EXT2FS_ATTR((unused)), |
| - | void *private EXT2FS_ATTR((unused))) |
| - | { |
| - | blk_t block; |
| - | int group; |
| - | |
| - | block = *blocknr; |
| - | ext2fs_unmark_block_bitmap(fs->block_map,block); |
| - | group = ext2fs_group_of_blk(fs, block); |
| - | fs->group_desc[group].bg_free_blocks_count++; |
| - | fs->super->s_free_blocks_count++; |
| - | return 0; |
| - | } |
| - | |
| - | /* |
| - | * Remove the journal inode from the filesystem |
| - | */ |
| - | static void remove_journal_inode(ext2_filsys fs) |
| - | { |
| - | struct ext2_inode inode; |
| - | errcode_t retval; |
| - | ino_t ino = fs->super->s_journal_inum; |
| - | char *msg = "to read"; |
| - | char *s = "journal inode"; |
| - | |
| - | retval = ext2fs_read_inode(fs, ino, &inode); |
| - | if (retval) |
| - | goto REMOVE_JOURNAL_INODE_ERROR; |
| - | if (ino == EXT2_JOURNAL_INO) { |
| - | retval = ext2fs_read_bitmaps(fs); |
| - | if (retval) { |
| - | msg = "to read bitmaps"; |
| - | s = ""; |
| - | goto REMOVE_JOURNAL_INODE_ERROR; |
| - | } |
| - | retval = ext2fs_block_iterate(fs, ino, 0, NULL, |
| - | release_blocks_proc, NULL); |
| - | if (retval) { |
| - | msg = "clearing"; |
| - | goto REMOVE_JOURNAL_INODE_ERROR; |
| - | } |
| - | memset(&inode, 0, sizeof(inode)); |
| - | ext2fs_mark_bb_dirty(fs); |
| - | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; |
| - | } else |
| - | inode.i_flags &= ~EXT2_IMMUTABLE_FL; |
| - | retval = ext2fs_write_inode(fs, ino, &inode); |
| - | if (retval) { |
| - | msg = "writing"; |
| - | REMOVE_JOURNAL_INODE_ERROR: |
| - | bb_error_msg_and_die("Failed %s %s", msg, s); |
| - | } |
| - | fs->super->s_journal_inum = 0; |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | /* |
| - | * Update the default mount options |
| - | */ |
| - | static void update_mntopts(ext2_filsys fs, char *mntopts) |
| - | { |
| - | struct ext2_super_block *sb= fs->super; |
| - | |
| - | if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) |
| - | bb_error_msg_and_die("Invalid mount option set: %s", mntopts); |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | /* |
| - | * Update the feature set as provided by the user. |
| - | */ |
| - | static void update_feature_set(ext2_filsys fs, char *features) |
| - | { |
| - | int sparse, old_sparse, filetype, old_filetype; |
| - | int journal, old_journal, dxdir, old_dxdir; |
| - | struct ext2_super_block *sb= fs->super; |
| - | __u32 old_compat, old_incompat, old_ro_compat; |
| - | |
| - | old_compat = sb->s_feature_compat; |
| - | old_ro_compat = sb->s_feature_ro_compat; |
| - | old_incompat = sb->s_feature_incompat; |
| - | |
| - | old_sparse = sb->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | old_filetype = sb->s_feature_incompat & |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE; |
| - | old_journal = sb->s_feature_compat & |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | old_dxdir = sb->s_feature_compat & |
| - | EXT2_FEATURE_COMPAT_DIR_INDEX; |
| - | if (e2p_edit_feature(features, &sb->s_feature_compat, ok_features)) |
| - | bb_error_msg_and_die("Invalid filesystem option set: %s", features); |
| - | sparse = sb->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | filetype = sb->s_feature_incompat & |
| - | EXT2_FEATURE_INCOMPAT_FILETYPE; |
| - | journal = sb->s_feature_compat & |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | dxdir = sb->s_feature_compat & |
| - | EXT2_FEATURE_COMPAT_DIR_INDEX; |
| - | if (old_journal && !journal) { |
| - | if ((mount_flags & EXT2_MF_MOUNTED) && |
| - | !(mount_flags & EXT2_MF_READONLY)) { |
| - | bb_error_msg_and_die( |
| - | "The has_journal flag may only be " |
| - | "cleared when the filesystem is\n" |
| - | "unmounted or mounted " |
| - | "read-only"); |
| - | } |
| - | if (sb->s_feature_incompat & |
| - | EXT3_FEATURE_INCOMPAT_RECOVER) { |
| - | bb_error_msg_and_die( |
| - | "The needs_recovery flag is set. " |
| - | "%s before clearing the has_journal flag.", |
| - | please_fsck); |
| - | } |
| - | if (sb->s_journal_inum) { |
| - | remove_journal_inode(fs); |
| - | } |
| - | if (sb->s_journal_dev) { |
| - | remove_journal_device(fs); |
| - | } |
| - | } |
| - | if (journal && !old_journal) { |
| - | /* |
| - | * If adding a journal flag, let the create journal |
| - | * code below handle creating setting the flag and |
| - | * creating the journal. We supply a default size if |
| - | * necessary. |
| - | */ |
| - | if (!journal_size) |
| - | journal_size = -1; |
| - | sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | } |
| - | if (dxdir && !old_dxdir) { |
| - | if (!sb->s_def_hash_version) |
| - | sb->s_def_hash_version = EXT2_HASH_TEA; |
| - | if (uuid_is_null((unsigned char *) sb->s_hash_seed)) |
| - | uuid_generate((unsigned char *) sb->s_hash_seed); |
| - | } |
| - | |
| - | if (sb->s_rev_level == EXT2_GOOD_OLD_REV && |
| - | (sb->s_feature_compat || sb->s_feature_ro_compat || |
| - | sb->s_feature_incompat)) |
| - | ext2fs_update_dynamic_rev(fs); |
| - | if ((sparse != old_sparse) || |
| - | (filetype != old_filetype)) { |
| - | sb->s_state &= ~EXT2_VALID_FS; |
| - | printf("\n%s\n", please_fsck); |
| - | } |
| - | if ((old_compat != sb->s_feature_compat) || |
| - | (old_ro_compat != sb->s_feature_ro_compat) || |
| - | (old_incompat != sb->s_feature_incompat)) |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | /* |
| - | * Add a journal to the filesystem. |
| - | */ |
| - | static void add_journal(ext2_filsys fs) |
| - | { |
| - | if (fs->super->s_feature_compat & |
| - | EXT3_FEATURE_COMPAT_HAS_JOURNAL) { |
| - | bb_error_msg_and_die("The filesystem already has a journal"); |
| - | } |
| - | if (journal_device) { |
| - | make_journal_device(journal_device, fs, 0, 0); |
| - | } else if (journal_size) { |
| - | make_journal_blocks(fs, journal_size, journal_flags, 0); |
| - | /* |
| - | * If the filesystem wasn't mounted, we need to force |
| - | * the block group descriptors out. |
| - | */ |
| - | if ((mount_flags & EXT2_MF_MOUNTED) == 0) |
| - | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; |
| - | } |
| - | print_check_message(fs); |
| - | } |
| - | |
| - | /* |
| - | * Busybox stuff |
| - | */ |
| - | static char * x_blkid_get_devname(const char *token) |
| - | { |
| - | char * dev_name; |
| - | |
| - | if (!(dev_name = blkid_get_devname(NULL, token, NULL))) |
| - | bb_error_msg_and_die("Unable to resolve '%s'", token); |
| - | return dev_name; |
| - | } |
| - | |
| - | #ifdef CONFIG_E2LABEL |
| - | static void parse_e2label_options(int argc, char ** argv) |
| - | { |
| - | if ((argc < 2) || (argc > 3)) |
| - | bb_show_usage(); |
| - | io_options = strchr(argv[1], '?'); |
| - | if (io_options) |
| - | *io_options++ = 0; |
| - | device_name = x_blkid_get_devname(argv[1]); |
| - | if (argc == 3) { |
| - | open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK; |
| - | L_flag = 1; |
| - | new_label = argv[2]; |
| - | } else |
| - | print_label++; |
| - | } |
| - | #else |
| - | #define parse_e2label_options(x,y) |
| - | #endif |
| - | |
| - | static time_t parse_time(char *str) |
| - | { |
| - | struct tm ts; |
| - | |
| - | if (strcmp(str, "now") == 0) { |
| - | return time(0); |
| - | } |
| - | memset(&ts, 0, sizeof(ts)); |
| - | #ifdef HAVE_STRPTIME |
| - | strptime(str, "%Y%m%d%H%M%S", &ts); |
| - | #else |
| - | sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, |
| - | &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); |
| - | ts.tm_year -= 1900; |
| - | ts.tm_mon -= 1; |
| - | if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || |
| - | ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || |
| - | ts.tm_min > 59 || ts.tm_sec > 61) |
| - | ts.tm_mday = 0; |
| - | #endif |
| - | if (ts.tm_mday == 0) { |
| - | bb_error_msg_and_die("can't parse date/time specifier: %s", str); |
| - | } |
| - | return mktime(&ts); |
| - | } |
| - | |
| - | static void parse_tune2fs_options(int argc, char **argv) |
| - | { |
| - | int c; |
| - | char * tmp; |
| - | |
| - | printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); |
| - | while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF) |
| - | switch (c) |
| - | { |
| - | case 'c': |
| - | max_mount_count = xatou_range(optarg, 0, 16000); |
| - | if (max_mount_count == 0) |
| - | max_mount_count = -1; |
| - | c_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'C': |
| - | mount_count = xatou_range(optarg, 0, 16000); |
| - | C_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'e': |
| - | if (strcmp (optarg, "continue") == 0) |
| - | errors = EXT2_ERRORS_CONTINUE; |
| - | else if (strcmp (optarg, "remount-ro") == 0) |
| - | errors = EXT2_ERRORS_RO; |
| - | else if (strcmp (optarg, "panic") == 0) |
| - | errors = EXT2_ERRORS_PANIC; |
| - | else { |
| - | bb_error_msg_and_die("bad error behavior - %s", optarg); |
| - | } |
| - | e_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'f': /* Force */ |
| - | f_flag = 1; |
| - | break; |
| - | case 'g': |
| - | resgid = bb_strtoul(optarg, NULL, 10); |
| - | if (errno) |
| - | resgid = xgroup2gid(optarg); |
| - | g_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'i': |
| - | interval = strtoul(optarg, &tmp, 0); |
| - | switch (*tmp) { |
| - | case 's': |
| - | tmp++; |
| - | break; |
| - | case '\0': |
| - | case 'd': |
| - | case 'D': /* days */ |
| - | interval *= 86400; |
| - | if (*tmp != '\0') |
| - | tmp++; |
| - | break; |
| - | case 'm': |
| - | case 'M': /* months! */ |
| - | interval *= 86400 * 30; |
| - | tmp++; |
| - | break; |
| - | case 'w': |
| - | case 'W': /* weeks */ |
| - | interval *= 86400 * 7; |
| - | tmp++; |
| - | break; |
| - | } |
| - | if (*tmp || interval > (365 * 86400)) { |
| - | bb_error_msg_and_die("bad interval - %s", optarg); |
| - | } |
| - | i_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'j': |
| - | if (!journal_size) |
| - | journal_size = -1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'J': |
| - | parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg); |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'l': |
| - | l_flag = 1; |
| - | break; |
| - | case 'L': |
| - | new_label = optarg; |
| - | L_flag = 1; |
| - | open_flag = EXT2_FLAG_RW | |
| - | EXT2_FLAG_JOURNAL_DEV_OK; |
| - | break; |
| - | case 'm': |
| - | reserved_ratio = xatou_range(optarg, 0, 50); |
| - | m_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'M': |
| - | new_last_mounted = optarg; |
| - | M_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'o': |
| - | if (mntopts_cmd) { |
| - | bb_error_msg_and_die("-o may only be specified once"); |
| - | } |
| - | mntopts_cmd = optarg; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | |
| - | case 'O': |
| - | if (features_cmd) { |
| - | bb_error_msg_and_die("-O may only be specified once"); |
| - | } |
| - | features_cmd = optarg; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'r': |
| - | reserved_blocks = xatoul(optarg); |
| - | r_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 's': |
| - | s_flag = atoi(optarg); |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'T': |
| - | T_flag = 1; |
| - | last_check_time = parse_time(optarg); |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'u': |
| - | resuid = bb_strtoul(optarg, NULL, 10); |
| - | if (errno) |
| - | resuid = xuname2uid(optarg); |
| - | u_flag = 1; |
| - | open_flag = EXT2_FLAG_RW; |
| - | break; |
| - | case 'U': |
| - | new_UUID = optarg; |
| - | U_flag = 1; |
| - | open_flag = EXT2_FLAG_RW | |
| - | EXT2_FLAG_JOURNAL_DEV_OK; |
| - | break; |
| - | default: |
| - | bb_show_usage(); |
| - | } |
| - | if (optind < argc - 1 || optind == argc) |
| - | bb_show_usage(); |
| - | if (!open_flag && !l_flag) |
| - | bb_show_usage(); |
| - | io_options = strchr(argv[optind], '?'); |
| - | if (io_options) |
| - | *io_options++ = 0; |
| - | device_name = x_blkid_get_devname(argv[optind]); |
| - | } |
| - | |
| - | static void tune2fs_clean_up(void) |
| - | { |
| - | if (ENABLE_FEATURE_CLEAN_UP && device_name) free(device_name); |
| - | if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device); |
| - | } |
| - | |
| - | int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| - | int tune2fs_main(int argc, char **argv) |
| - | { |
| - | errcode_t retval; |
| - | ext2_filsys fs; |
| - | struct ext2_super_block *sb; |
| - | io_manager io_ptr; |
| - | |
| - | if (ENABLE_FEATURE_CLEAN_UP) |
| - | atexit(tune2fs_clean_up); |
| - | |
| - | if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */ |
| - | parse_e2label_options(argc, argv); |
| - | else |
| - | parse_tune2fs_options(argc, argv); /* tune2fs */ |
| - | |
| - | io_ptr = unix_io_manager; |
| - | retval = ext2fs_open2(device_name, io_options, open_flag, |
| - | 0, 0, io_ptr, &fs); |
| - | if (retval) |
| - | bb_error_msg_and_die("No valid superblock on %s", device_name); |
| - | sb = fs->super; |
| - | if (print_label) { |
| - | /* For e2label emulation */ |
| - | printf("%.*s\n", (int) sizeof(sb->s_volume_name), |
| - | sb->s_volume_name); |
| - | return 0; |
| - | } |
| - | retval = ext2fs_check_if_mounted(device_name, &mount_flags); |
| - | if (retval) |
| - | bb_error_msg_and_die("can't determine if %s is mounted", device_name); |
| - | /* Normally we only need to write out the superblock */ |
| - | fs->flags |= EXT2_FLAG_SUPER_ONLY; |
| - | |
| - | if (c_flag) { |
| - | sb->s_max_mnt_count = max_mount_count; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting maximal mount count to %d\n", max_mount_count); |
| - | } |
| - | if (C_flag) { |
| - | sb->s_mnt_count = mount_count; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting current mount count to %d\n", mount_count); |
| - | } |
| - | if (e_flag) { |
| - | sb->s_errors = errors; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting error behavior to %u\n", errors); |
| - | } |
| - | if (g_flag) { |
| - | sb->s_def_resgid = resgid; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting reserved blocks gid to %lu\n", resgid); |
| - | } |
| - | if (i_flag) { |
| - | sb->s_checkinterval = interval; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting interval between check %lu seconds\n", interval); |
| - | } |
| - | if (m_flag) { |
| - | sb->s_r_blocks_count = (sb->s_blocks_count / 100) |
| - | * reserved_ratio; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting reserved blocks percentage to %u (%u blocks)\n", |
| - | reserved_ratio, sb->s_r_blocks_count); |
| - | } |
| - | if (r_flag) { |
| - | if (reserved_blocks >= sb->s_blocks_count/2) |
| - | bb_error_msg_and_die("reserved blocks count is too big (%lu)", reserved_blocks); |
| - | sb->s_r_blocks_count = reserved_blocks; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting reserved blocks count to %lu\n", reserved_blocks); |
| - | } |
| - | if (s_flag == 1) { |
| - | if (sb->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) |
| - | bb_error_msg("\nThe filesystem already has sparse superblocks"); |
| - | else { |
| - | sb->s_feature_ro_compat |= |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | sb->s_state &= ~EXT2_VALID_FS; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("\nSparse superblock flag set. %s", please_fsck); |
| - | } |
| - | } |
| - | if (s_flag == 0) { |
| - | if (!(sb->s_feature_ro_compat & |
| - | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) |
| - | bb_error_msg("\nThe filesystem already has sparse superblocks disabled"); |
| - | else { |
| - | sb->s_feature_ro_compat &= |
| - | ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; |
| - | sb->s_state &= ~EXT2_VALID_FS; |
| - | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("\nSparse superblock flag cleared. %s", please_fsck); |
| - | } |
| - | } |
| - | if (T_flag) { |
| - | sb->s_lastcheck = last_check_time; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting time filesystem last checked to %s\n", |
| - | ctime(&last_check_time)); |
| - | } |
| - | if (u_flag) { |
| - | sb->s_def_resuid = resuid; |
| - | ext2fs_mark_super_dirty(fs); |
| - | printf("Setting reserved blocks uid to %lu\n", resuid); |
| - | } |
| - | if (L_flag) { |
| - | if (strlen(new_label) > sizeof(sb->s_volume_name)) |
| - | bb_error_msg("Warning: label too long, truncating"); |
| - | memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); |
| - | safe_strncpy(sb->s_volume_name, new_label, |
| - | sizeof(sb->s_volume_name)); |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | if (M_flag) { |
| - | memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); |
| - | safe_strncpy(sb->s_last_mounted, new_last_mounted, |
| - | sizeof(sb->s_last_mounted)); |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | if (mntopts_cmd) |
| - | update_mntopts(fs, mntopts_cmd); |
| - | if (features_cmd) |
| - | update_feature_set(fs, features_cmd); |
| - | if (journal_size || journal_device) |
| - | add_journal(fs); |
| - | |
| - | if (U_flag) { |
| - | if ((strcasecmp(new_UUID, "null") == 0) || |
| - | (strcasecmp(new_UUID, "clear") == 0)) { |
| - | uuid_clear(sb->s_uuid); |
| - | } else if (strcasecmp(new_UUID, "time") == 0) { |
| - | uuid_generate_time(sb->s_uuid); |
| - | } else if (strcasecmp(new_UUID, "random") == 0) { |
| - | uuid_generate(sb->s_uuid); |
| - | } else if (uuid_parse(new_UUID, sb->s_uuid)) { |
| - | bb_error_msg_and_die("Invalid UUID format"); |
| - | } |
| - | ext2fs_mark_super_dirty(fs); |
| - | } |
| - | |
| - | if (l_flag) |
| - | list_super (sb); |
| - | return (ext2fs_close (fs) ? 1 : 0); |
| - | } |
| @@ -1,263 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * util.c --- helper functions used by tune2fs and mke2fs |
| - | * |
| - | * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. |
| - | * |
| - | * Licensed under GPLv2, see file LICENSE in this source tree. |
| - | */ |
| - | |
| - | #include <stdio.h> |
| - | #include <string.h> |
| - | #include <errno.h> |
| - | #include <linux/major.h> |
| - | #include <sys/stat.h> |
| - | |
| - | #include "e2fsbb.h" |
| - | #include "e2p/e2p.h" |
| - | #include "ext2fs/ext2_fs.h" |
| - | #include "ext2fs/ext2fs.h" |
| - | #include "blkid/blkid.h" |
| - | #include "util.h" |
| - | |
| - | void proceed_question(void) |
| - | { |
| - | fputs("Proceed anyway? (y,n) ", stdout); |
| - | if (bb_ask_confirmation() == 0) |
| - | exit(1); |
| - | } |
| - | |
| - | void check_plausibility(const char *device, int force) |
| - | { |
| - | int val; |
| - | struct stat s; |
| - | val = stat(device, &s); |
| - | if (force) |
| - | return; |
| - | if (val == -1) |
| - | bb_perror_msg_and_die("can't stat '%s'", device); |
| - | if (!S_ISBLK(s.st_mode)) { |
| - | printf("%s is not a block special device.\n", device); |
| - | proceed_question(); |
| - | return; |
| - | } |
| - | |
| - | #ifdef HAVE_LINUX_MAJOR_H |
| - | #ifndef MAJOR |
| - | #define MAJOR(dev) ((dev)>>8) |
| - | #define MINOR(dev) ((dev) & 0xff) |
| - | #endif |
| - | #ifndef SCSI_BLK_MAJOR |
| - | #ifdef SCSI_DISK0_MAJOR |
| - | #ifdef SCSI_DISK8_MAJOR |
| - | #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ |
| - | ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ |
| - | ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) |
| - | #else |
| - | #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ |
| - | ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) |
| - | #endif /* defined(SCSI_DISK8_MAJOR) */ |
| - | #define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR) |
| - | #else |
| - | #define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR) |
| - | #endif /* defined(SCSI_DISK0_MAJOR) */ |
| - | #endif /* defined(SCSI_BLK_MAJOR) */ |
| - | if (((MAJOR(s.st_rdev) == HD_MAJOR && |
| - | MINOR(s.st_rdev)%64 == 0) || |
| - | (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) && |
| - | MINOR(s.st_rdev)%16 == 0))) { |
| - | printf("%s is entire device, not just one partition!\n", device); |
| - | proceed_question(); |
| - | } |
| - | #endif |
| - | } |
| - | |
| - | void check_mount(const char *device, int force, const char *type) |
| - | { |
| - | errcode_t retval; |
| - | int mount_flags; |
| - | |
| - | retval = ext2fs_check_if_mounted(device, &mount_flags); |
| - | if (retval) { |
| - | bb_error_msg("can't determine if %s is mounted", device); |
| - | return; |
| - | } |
| - | if (mount_flags & EXT2_MF_MOUNTED) { |
| - | bb_error_msg("%s is mounted !", device); |
| - | force_check: |
| - | if (force) |
| - | bb_error_msg("badblocks forced anyways"); |
| - | else |
| - | bb_error_msg_and_die("it's not safe to run badblocks!"); |
| - | } |
| - | |
| - | if (mount_flags & EXT2_MF_BUSY) { |
| - | bb_error_msg("%s is apparently in use by the system", device); |
| - | goto force_check; |
| - | } |
| - | } |
| - | |
| - | void parse_journal_opts(char **journal_device, int *journal_flags, |
| - | int *journal_size, const char *opts) |
| - | { |
| - | char *buf, *token, *next, *p, *arg; |
| - | int journal_usage = 0; |
| - | buf = xstrdup(opts); |
| - | for (token = buf; token && *token; token = next) { |
| - | p = strchr(token, ','); |
| - | next = 0; |
| - | if (p) { |
| - | *p = 0; |
| - | next = p+1; |
| - | } |
| - | arg = strchr(token, '='); |
| - | if (arg) { |
| - | *arg = 0; |
| - | arg++; |
| - | } |
| - | if (strcmp(token, "device") == 0) { |
| - | *journal_device = blkid_get_devname(NULL, arg, NULL); |
| - | if (!*journal_device) { |
| - | journal_usage++; |
| - | continue; |
| - | } |
| - | } else if (strcmp(token, "size") == 0) { |
| - | if (!arg) { |
| - | journal_usage++; |
| - | continue; |
| - | } |
| - | (*journal_size) = strtoul(arg, &p, 0); |
| - | if (*p) |
| - | journal_usage++; |
| - | } else if (strcmp(token, "v1_superblock") == 0) { |
| - | (*journal_flags) |= EXT2_MKJOURNAL_V1_SUPER; |
| - | continue; |
| - | } else |
| - | journal_usage++; |
| - | } |
| - | if (journal_usage) |
| - | bb_error_msg_and_die( |
| - | "\nBad journal options specified.\n\n" |
| - | "Journal options are separated by commas, " |
| - | "and may take an argument which\n" |
| - | "\tis set off by an equals ('=') sign.\n\n" |
| - | "Valid journal options are:\n" |
| - | "\tsize=<journal size in megabytes>\n" |
| - | "\tdevice=<journal device>\n\n" |
| - | "The journal size must be between " |
| - | "1024 and 102400 filesystem blocks.\n\n"); |
| - | } |
| - | |
| - | /* |
| - | * Determine the number of journal blocks to use, either via |
| - | * user-specified # of megabytes, or via some intelligently selected |
| - | * defaults. |
| - | * |
| - | * Find a reasonable journal file size (in blocks) given the number of blocks |
| - | * in the filesystem. For very small filesystems, it is not reasonable to |
| - | * have a journal that fills more than half of the filesystem. |
| - | */ |
| - | int figure_journal_size(int size, ext2_filsys fs) |
| - | { |
| - | blk_t j_blocks; |
| - | |
| - | if (fs->super->s_blocks_count < 2048) { |
| - | bb_error_msg("Filesystem too small for a journal"); |
| - | return 0; |
| - | } |
| - | |
| - | if (size >= 0) { |
| - | j_blocks = size * 1024 / (fs->blocksize / 1024); |
| - | if (j_blocks < 1024 || j_blocks > 102400) |
| - | bb_error_msg_and_die("\nThe requested journal " |
| - | "size is %d blocks;\n it must be " |
| - | "between 1024 and 102400 blocks; Aborting", |
| - | j_blocks); |
| - | if (j_blocks > fs->super->s_free_blocks_count) |
| - | bb_error_msg_and_die("Journal size too big for filesystem"); |
| - | return j_blocks; |
| - | } |
| - | |
| - | if (fs->super->s_blocks_count < 32768) |
| - | j_blocks = 1024; |
| - | else if (fs->super->s_blocks_count < 256*1024) |
| - | j_blocks = 4096; |
| - | else if (fs->super->s_blocks_count < 512*1024) |
| - | j_blocks = 8192; |
| - | else if (fs->super->s_blocks_count < 1024*1024) |
| - | j_blocks = 16384; |
| - | else |
| - | j_blocks = 32768; |
| - | |
| - | return j_blocks; |
| - | } |
| - | |
| - | void print_check_message(ext2_filsys fs) |
| - | { |
| - | printf("This filesystem will be automatically " |
| - | "checked every %d mounts or\n" |
| - | "%g days, whichever comes first. " |
| - | "Use tune2fs -c or -i to override.\n", |
| - | fs->super->s_max_mnt_count, |
| - | (double)fs->super->s_checkinterval / (3600 * 24)); |
| - | } |
| - | |
| - | void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int force) |
| - | { |
| - | errcode_t retval; |
| - | ext2_filsys jfs; |
| - | io_manager io_ptr; |
| - | |
| - | check_plausibility(journal_device, force); |
| - | check_mount(journal_device, force, "journal"); |
| - | io_ptr = unix_io_manager; |
| - | retval = ext2fs_open(journal_device, EXT2_FLAG_RW| |
| - | EXT2_FLAG_JOURNAL_DEV_OK, 0, |
| - | fs->blocksize, io_ptr, &jfs); |
| - | if (retval) |
| - | bb_error_msg_and_die("can't journal device %s", journal_device); |
| - | if (!quiet) |
| - | printf("Adding journal to device %s: ", journal_device); |
| - | fflush(stdout); |
| - | retval = ext2fs_add_journal_device(fs, jfs); |
| - | if (retval) |
| - | bb_error_msg_and_die("\nFailed to add journal to device %s", journal_device); |
| - | if (!quiet) |
| - | puts("done"); |
| - | ext2fs_close(jfs); |
| - | } |
| - | |
| - | void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, int quiet) |
| - | { |
| - | unsigned long journal_blocks; |
| - | errcode_t retval; |
| - | |
| - | journal_blocks = figure_journal_size(journal_size, fs); |
| - | if (!journal_blocks) { |
| - | fs->super->s_feature_compat &= |
| - | ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| - | return; |
| - | } |
| - | if (!quiet) |
| - | printf("Creating journal (%lu blocks): ", journal_blocks); |
| - | fflush(stdout); |
| - | retval = ext2fs_add_journal_inode(fs, journal_blocks, |
| - | journal_flags); |
| - | if (retval) |
| - | bb_error_msg_and_die("can't create journal"); |
| - | if (!quiet) |
| - | puts("done"); |
| - | } |
| - | |
| - | char *e2fs_set_sbin_path(void) |
| - | { |
| - | char *oldpath = getenv("PATH"); |
| - | /* Update our PATH to include /sbin */ |
| - | #define PATH_SET "/sbin" |
| - | if (oldpath) |
| - | oldpath = xasprintf("%s:%s", PATH_SET, oldpath); |
| - | else |
| - | oldpath = PATH_SET; |
| - | putenv(oldpath); |
| - | return oldpath; |
| - | } |
| @@ -1,22 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * util.h --- header file defining prototypes for helper functions |
| - | * used by tune2fs and mke2fs |
| - | * |
| - | * Copyright 2000 by Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * This file may be redistributed under the terms of the GNU Public |
| - | * License. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | extern void proceed_question(void); |
| - | extern void check_plausibility(const char *device, int force); |
| - | extern void parse_journal_opts(char **, int *, int *, const char *opts); |
| - | extern void check_mount(const char *device, int force, const char *type); |
| - | extern int figure_journal_size(int size, ext2_filsys fs); |
| - | extern void print_check_message(ext2_filsys fs); |
| - | extern void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int force); |
| - | extern void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, int quiet); |
| - | extern char *e2fs_set_sbin_path(void); |
| @@ -1,16 +0,0 @@ | |
| - | # Makefile for busybox |
| - | # |
| - | # Copyright (C) 1999-2005 by Erik Andersen <[email protected]> |
| - | # |
| - | # 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) += compare.o gen_uuid.o pack.o parse.o unpack.o unparse.o \ |
| - | uuid_time.o |
| @@ -1,55 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * compare.c --- compare whether or not two UUID's are the same |
| - | * |
| - | * Returns 0 if the two UUID's are different, and 1 if they are the same. |
| - | * |
| - | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include "uuidP.h" |
| - | #include <string.h> |
| - | |
| - | #define UUCMP(u1,u2) if (u1 != u2) return (u1 < u2) ? -1 : 1; |
| - | |
| - | int uuid_compare(const uuid_t uu1, const uuid_t uu2) |
| - | { |
| - | struct uuid uuid1, uuid2; |
| - | |
| - | uuid_unpack(uu1, &uuid1); |
| - | uuid_unpack(uu2, &uuid2); |
| - | |
| - | UUCMP(uuid1.time_low, uuid2.time_low); |
| - | UUCMP(uuid1.time_mid, uuid2.time_mid); |
| - | UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); |
| - | UUCMP(uuid1.clock_seq, uuid2.clock_seq); |
| - | return memcmp(uuid1.node, uuid2.node, 6); |
| - | } |
| @@ -1,304 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * gen_uuid.c --- generate a DCE-compatible uuid |
| - | * |
| - | * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <unistd.h> |
| - | #include <stdlib.h> |
| - | #include <string.h> |
| - | #include <fcntl.h> |
| - | #include <errno.h> |
| - | #include <sys/types.h> |
| - | #include <sys/stat.h> |
| - | #include <sys/file.h> |
| - | #include <sys/time.h> |
| - | #ifdef HAVE_SYS_IOCTL_H |
| - | #include <sys/ioctl.h> |
| - | #endif |
| - | #include <sys/socket.h> |
| - | #ifdef HAVE_SYS_SOCKIO_H |
| - | #include <sys/sockio.h> |
| - | #endif |
| - | #ifdef HAVE_NET_IF_H |
| - | #include <net/if.h> |
| - | #endif |
| - | #ifdef HAVE_NETINET_IN_H |
| - | #include <netinet/in.h> |
| - | #endif |
| - | #ifdef HAVE_NET_IF_DL_H |
| - | #include <net/if_dl.h> |
| - | #endif |
| - | |
| - | #include "uuidP.h" |
| - | |
| - | #ifdef HAVE_SRANDOM |
| - | #define srand(x) srandom(x) |
| - | #define rand() random() |
| - | #endif |
| - | |
| - | static int get_random_fd(void) |
| - | { |
| - | struct timeval tv; |
| - | static int fd = -2; |
| - | int i; |
| - | |
| - | if (fd == -2) { |
| - | gettimeofday(&tv, 0); |
| - | fd = open("/dev/urandom", O_RDONLY); |
| - | if (fd == -1) |
| - | fd = open("/dev/random", O_RDONLY | O_NONBLOCK); |
| - | srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); |
| - | } |
| - | /* Crank the random number generator a few times */ |
| - | gettimeofday(&tv, 0); |
| - | for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) |
| - | rand(); |
| - | return fd; |
| - | } |
| - | |
| - | |
| - | /* |
| - | * Generate a series of random bytes. Use /dev/urandom if possible, |
| - | * and if not, use srandom/random. |
| - | */ |
| - | static void get_random_bytes(void *buf, int nbytes) |
| - | { |
| - | int i, n = nbytes, fd = get_random_fd(); |
| - | int lose_counter = 0; |
| - | unsigned char *cp = (unsigned char *) buf; |
| - | |
| - | if (fd >= 0) { |
| - | while (n > 0) { |
| - | i = read(fd, cp, n); |
| - | if (i <= 0) { |
| - | if (lose_counter++ > 16) |
| - | break; |
| - | continue; |
| - | } |
| - | n -= i; |
| - | cp += i; |
| - | lose_counter = 0; |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * We do this all the time, but this is the only source of |
| - | * randomness if /dev/random/urandom is out to lunch. |
| - | */ |
| - | for (cp = buf, i = 0; i < nbytes; i++) |
| - | *cp++ ^= (rand() >> 7) & 0xFF; |
| - | } |
| - | |
| - | /* |
| - | * Get the ethernet hardware address, if we can find it... |
| - | */ |
| - | static int get_node_id(unsigned char *node_id) |
| - | { |
| - | #ifdef HAVE_NET_IF_H |
| - | int sd; |
| - | struct ifreq ifr, *ifrp; |
| - | struct ifconf ifc; |
| - | char buf[1024]; |
| - | int n, i; |
| - | unsigned char *a; |
| - | #ifdef HAVE_NET_IF_DL_H |
| - | struct sockaddr_dl *sdlp; |
| - | #endif |
| - | |
| - | /* |
| - | * BSD 4.4 defines the size of an ifreq to be |
| - | * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len |
| - | * However, under earlier systems, sa_len isn't present, so the size is |
| - | * just sizeof(struct ifreq) |
| - | */ |
| - | #ifdef HAVE_SA_LEN |
| - | #ifndef max |
| - | #define max(a,b) ((a) > (b) ? (a) : (b)) |
| - | #endif |
| - | #define ifreq_size(i) max(sizeof(struct ifreq),\ |
| - | sizeof((i).ifr_name)+(i).ifr_addr.sa_len) |
| - | #else |
| - | #define ifreq_size(i) sizeof(struct ifreq) |
| - | #endif /* HAVE_SA_LEN*/ |
| - | |
| - | sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
| - | if (sd < 0) { |
| - | return -1; |
| - | } |
| - | memset(buf, 0, sizeof(buf)); |
| - | ifc.ifc_len = sizeof(buf); |
| - | ifc.ifc_buf = buf; |
| - | if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { |
| - | close(sd); |
| - | return -1; |
| - | } |
| - | n = ifc.ifc_len; |
| - | for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { |
| - | ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); |
| - | strncpy_IFNAMSIZ(ifr.ifr_name, ifrp->ifr_name); |
| - | #ifdef SIOCGIFHWADDR |
| - | if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) |
| - | continue; |
| - | a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; |
| - | #else |
| - | #ifdef SIOCGENADDR |
| - | if (ioctl(sd, SIOCGENADDR, &ifr) < 0) |
| - | continue; |
| - | a = (unsigned char *) ifr.ifr_enaddr; |
| - | #else |
| - | #ifdef HAVE_NET_IF_DL_H |
| - | sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; |
| - | if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) |
| - | continue; |
| - | a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; |
| - | #else |
| - | /* |
| - | * XXX we don't have a way of getting the hardware |
| - | * address |
| - | */ |
| - | close(sd); |
| - | return 0; |
| - | #endif /* HAVE_NET_IF_DL_H */ |
| - | #endif /* SIOCGENADDR */ |
| - | #endif /* SIOCGIFHWADDR */ |
| - | if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) |
| - | continue; |
| - | if (node_id) { |
| - | memcpy(node_id, a, 6); |
| - | close(sd); |
| - | return 1; |
| - | } |
| - | } |
| - | close(sd); |
| - | #endif |
| - | return 0; |
| - | } |
| - | |
| - | /* Assume that the gettimeofday() has microsecond granularity */ |
| - | #define MAX_ADJUSTMENT 10 |
| - | |
| - | static int get_clock(uint32_t *clock_high, uint32_t *clock_low, uint16_t *ret_clock_seq) |
| - | { |
| - | static int adjustment = 0; |
| - | static struct timeval last = {0, 0}; |
| - | static uint16_t clock_seq; |
| - | struct timeval tv; |
| - | unsigned long long clock_reg; |
| - | |
| - | try_again: |
| - | gettimeofday(&tv, 0); |
| - | if ((last.tv_sec == 0) && (last.tv_usec == 0)) { |
| - | get_random_bytes(&clock_seq, sizeof(clock_seq)); |
| - | clock_seq &= 0x3FFF; |
| - | last = tv; |
| - | last.tv_sec--; |
| - | } |
| - | if ((tv.tv_sec < last.tv_sec) || |
| - | ((tv.tv_sec == last.tv_sec) && |
| - | (tv.tv_usec < last.tv_usec))) { |
| - | clock_seq = (clock_seq+1) & 0x3FFF; |
| - | adjustment = 0; |
| - | last = tv; |
| - | } else if ((tv.tv_sec == last.tv_sec) && |
| - | (tv.tv_usec == last.tv_usec)) { |
| - | if (adjustment >= MAX_ADJUSTMENT) |
| - | goto try_again; |
| - | adjustment++; |
| - | } else { |
| - | adjustment = 0; |
| - | last = tv; |
| - | } |
| - | |
| - | clock_reg = tv.tv_usec*10 + adjustment; |
| - | clock_reg += ((unsigned long long) tv.tv_sec)*10000000; |
| - | clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; |
| - | |
| - | *clock_high = clock_reg >> 32; |
| - | *clock_low = clock_reg; |
| - | *ret_clock_seq = clock_seq; |
| - | return 0; |
| - | } |
| - | |
| - | void uuid_generate_time(uuid_t out) |
| - | { |
| - | static unsigned char node_id[6]; |
| - | static int has_init = 0; |
| - | struct uuid uu; |
| - | uint32_t clock_mid; |
| - | |
| - | if (!has_init) { |
| - | if (get_node_id(node_id) <= 0) { |
| - | get_random_bytes(node_id, 6); |
| - | /* |
| - | * Set multicast bit, to prevent conflicts |
| - | * with IEEE 802 addresses obtained from |
| - | * network cards |
| - | */ |
| - | node_id[0] |= 0x01; |
| - | } |
| - | has_init = 1; |
| - | } |
| - | get_clock(&clock_mid, &uu.time_low, &uu.clock_seq); |
| - | uu.clock_seq |= 0x8000; |
| - | uu.time_mid = (uint16_t) clock_mid; |
| - | uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; |
| - | memcpy(uu.node, node_id, 6); |
| - | uuid_pack(&uu, out); |
| - | } |
| - | |
| - | void uuid_generate_random(uuid_t out) |
| - | { |
| - | uuid_t buf; |
| - | struct uuid uu; |
| - | |
| - | get_random_bytes(buf, sizeof(buf)); |
| - | uuid_unpack(buf, &uu); |
| - | |
| - | uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; |
| - | uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000; |
| - | uuid_pack(&uu, out); |
| - | } |
| - | |
| - | /* |
| - | * This is the generic front-end to uuid_generate_random and |
| - | * uuid_generate_time. It uses uuid_generate_random only if |
| - | * /dev/urandom is available, since otherwise we won't have |
| - | * high-quality randomness. |
| - | */ |
| - | void uuid_generate(uuid_t out) |
| - | { |
| - | if (get_random_fd() >= 0) |
| - | uuid_generate_random(out); |
| - | else |
| - | uuid_generate_time(out); |
| - | } |
| @@ -1,69 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * Internal routine for packing UUID's |
| - | * |
| - | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <string.h> |
| - | #include "uuidP.h" |
| - | |
| - | void uuid_pack(const struct uuid *uu, uuid_t ptr) |
| - | { |
| - | uint32_t tmp; |
| - | unsigned char *out = ptr; |
| - | |
| - | tmp = uu->time_low; |
| - | out[3] = (unsigned char) tmp; |
| - | tmp >>= 8; |
| - | out[2] = (unsigned char) tmp; |
| - | tmp >>= 8; |
| - | out[1] = (unsigned char) tmp; |
| - | tmp >>= 8; |
| - | out[0] = (unsigned char) tmp; |
| - | |
| - | tmp = uu->time_mid; |
| - | out[5] = (unsigned char) tmp; |
| - | tmp >>= 8; |
| - | out[4] = (unsigned char) tmp; |
| - | |
| - | tmp = uu->time_hi_and_version; |
| - | out[7] = (unsigned char) tmp; |
| - | tmp >>= 8; |
| - | out[6] = (unsigned char) tmp; |
| - | |
| - | tmp = uu->clock_seq; |
| - | out[9] = (unsigned char) tmp; |
| - | tmp >>= 8; |
| - | out[8] = (unsigned char) tmp; |
| - | |
| - | memcpy(out+10, uu->node, 6); |
| - | } |
| @@ -1,80 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * parse.c --- UUID parsing |
| - | * |
| - | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <stdlib.h> |
| - | #include <stdio.h> |
| - | #include <ctype.h> |
| - | #include <string.h> |
| - | |
| - | #include "uuidP.h" |
| - | |
| - | int uuid_parse(const char *in, uuid_t uu) |
| - | { |
| - | struct uuid uuid; |
| - | int i; |
| - | const char *cp; |
| - | char buf[3]; |
| - | |
| - | if (strlen(in) != 36) |
| - | return -1; |
| - | for (i=0, cp = in; i <= 36; i++,cp++) { |
| - | if ((i == 8) || (i == 13) || (i == 18) || |
| - | (i == 23)) { |
| - | if (*cp == '-') |
| - | continue; |
| - | else |
| - | return -1; |
| - | } |
| - | if (i== 36) |
| - | if (*cp == 0) |
| - | continue; |
| - | if (!isxdigit(*cp)) |
| - | return -1; |
| - | } |
| - | uuid.time_low = strtoul(in, NULL, 16); |
| - | uuid.time_mid = strtoul(in+9, NULL, 16); |
| - | uuid.time_hi_and_version = strtoul(in+14, NULL, 16); |
| - | uuid.clock_seq = strtoul(in+19, NULL, 16); |
| - | cp = in+24; |
| - | buf[2] = 0; |
| - | for (i=0; i < 6; i++) { |
| - | buf[0] = *cp++; |
| - | buf[1] = *cp++; |
| - | uuid.node[i] = strtoul(buf, NULL, 16); |
| - | } |
| - | |
| - | uuid_pack(&uuid, uu); |
| - | return 0; |
| - | } |
| @@ -1,63 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * Internal routine for unpacking UUID |
| - | * |
| - | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <string.h> |
| - | #include "uuidP.h" |
| - | |
| - | void uuid_unpack(const uuid_t in, struct uuid *uu) |
| - | { |
| - | const uint8_t *ptr = in; |
| - | uint32_t 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); |
| - | } |
| @@ -1,77 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * unparse.c -- convert a UUID to string |
| - | * |
| - | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <stdio.h> |
| - | |
| - | #include "uuidP.h" |
| - | |
| - | static const char *fmt_lower = |
| - | "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; |
| - | |
| - | static const char *fmt_upper = |
| - | "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; |
| - | |
| - | #ifdef UUID_UNPARSE_DEFAULT_UPPER |
| - | #define FMT_DEFAULT fmt_upper |
| - | #else |
| - | #define FMT_DEFAULT fmt_lower |
| - | #endif |
| - | |
| - | static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt) |
| - | { |
| - | struct uuid uuid; |
| - | |
| - | uuid_unpack(uu, &uuid); |
| - | sprintf(out, fmt, |
| - | 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]); |
| - | } |
| - | |
| - | void uuid_unparse_lower(const uuid_t uu, char *out) |
| - | { |
| - | uuid_unparse_x(uu, out, fmt_lower); |
| - | } |
| - | |
| - | void uuid_unparse_upper(const uuid_t uu, char *out) |
| - | { |
| - | uuid_unparse_x(uu, out, fmt_upper); |
| - | } |
| - | |
| - | void uuid_unparse(const uuid_t uu, char *out) |
| - | { |
| - | uuid_unparse_x(uu, out, FMT_DEFAULT); |
| - | } |
| @@ -1,103 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * Public include file for the UUID library |
| - | * |
| - | * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | #ifndef UUID_UUID_H |
| - | #define UUID_UUID_H 1 |
| - | |
| - | #include <sys/types.h> |
| - | #include <time.h> |
| - | |
| - | typedef unsigned char uuid_t[16]; |
| - | |
| - | /* UUID Variant definitions */ |
| - | #define UUID_VARIANT_NCS 0 |
| - | #define UUID_VARIANT_DCE 1 |
| - | #define UUID_VARIANT_MICROSOFT 2 |
| - | #define UUID_VARIANT_OTHER 3 |
| - | |
| - | /* UUID Type definitions */ |
| - | #define UUID_TYPE_DCE_TIME 1 |
| - | #define UUID_TYPE_DCE_RANDOM 4 |
| - | |
| - | /* Allow UUID constants to be defined */ |
| - | #ifdef __GNUC__ |
| - | #define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ |
| - | static const uuid_t name UNUSED_PARAM = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} |
| - | #else |
| - | #define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ |
| - | static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} |
| - | #endif |
| - | |
| - | #ifdef __cplusplus |
| - | extern "C" { |
| - | #endif |
| - | |
| - | /* clear.c */ |
| - | /*void uuid_clear(uuid_t uu);*/ |
| - | #define uuid_clear(uu) memset(uu, 0, sizeof(uu)) |
| - | |
| - | /* compare.c */ |
| - | int uuid_compare(const uuid_t uu1, const uuid_t uu2); |
| - | |
| - | /* copy.c */ |
| - | /*void uuid_copy(uuid_t dst, const uuid_t src);*/ |
| - | #define uuid_copy(dst,src) memcpy(dst, src, sizeof(dst)) |
| - | |
| - | /* gen_uuid.c */ |
| - | void uuid_generate(uuid_t out); |
| - | void uuid_generate_random(uuid_t out); |
| - | void uuid_generate_time(uuid_t out); |
| - | |
| - | /* isnull.c */ |
| - | /*int uuid_is_null(const uuid_t uu);*/ |
| - | #define uuid_is_null(uu) (!memcmp(uu, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(uu))) |
| - | |
| - | /* parse.c */ |
| - | int uuid_parse(const char *in, uuid_t uu); |
| - | |
| - | /* unparse.c */ |
| - | void uuid_unparse(const uuid_t uu, char *out); |
| - | void uuid_unparse_lower(const uuid_t uu, char *out); |
| - | void uuid_unparse_upper(const uuid_t uu, char *out); |
| - | |
| - | /* uuid_time.c */ |
| - | time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); |
| - | int uuid_type(const uuid_t uu); |
| - | int uuid_variant(const uuid_t uu); |
| - | |
| - | #ifdef __cplusplus |
| - | } |
| - | #endif |
| - | |
| - | #endif /* _UUID_UUID_H */ |
| @@ -1,60 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * uuid.h -- private header file for uuids |
| - | * |
| - | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <inttypes.h> |
| - | #include <sys/types.h> |
| - | |
| - | #include "uuid.h" |
| - | |
| - | /* |
| - | * Offset between 15-Oct-1582 and 1-Jan-70 |
| - | */ |
| - | #define TIME_OFFSET_HIGH 0x01B21DD2 |
| - | #define TIME_OFFSET_LOW 0x13814000 |
| - | |
| - | struct uuid { |
| - | uint32_t time_low; |
| - | uint16_t time_mid; |
| - | uint16_t time_hi_and_version; |
| - | uint16_t clock_seq; |
| - | uint8_t node[6]; |
| - | }; |
| - | |
| - | |
| - | /* |
| - | * prototypes |
| - | */ |
| - | void uuid_pack(const struct uuid *uu, uuid_t ptr); |
| - | void uuid_unpack(const uuid_t in, struct uuid *uu); |
| @@ -1,161 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * uuid_time.c --- Interpret the time field from a uuid. This program |
| - | * violates the UUID abstraction barrier by reaching into the guts |
| - | * of a UUID and interpreting it. |
| - | * |
| - | * Copyright (C) 1998, 1999 Theodore Ts'o. |
| - | * |
| - | * %Begin-Header% |
| - | * Redistribution and use in source and binary forms, with or without |
| - | * modification, are permitted provided that the following conditions |
| - | * are met: |
| - | * 1. Redistributions of source code must retain the above copyright |
| - | * notice, and the entire permission notice in its entirety, |
| - | * including the disclaimer of warranties. |
| - | * 2. Redistributions in binary form must reproduce the above copyright |
| - | * notice, this list of conditions and the following disclaimer in the |
| - | * documentation and/or other materials provided with the distribution. |
| - | * 3. The name of the author may not be used to endorse or promote |
| - | * products derived from this software without specific prior |
| - | * written permission. |
| - | * |
| - | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| - | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| - | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| - | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| - | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| - | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| - | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| - | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| - | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| - | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| - | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| - | * DAMAGE. |
| - | * %End-Header% |
| - | */ |
| - | |
| - | #include <stdio.h> |
| - | #include <unistd.h> |
| - | #include <stdlib.h> |
| - | #include <sys/types.h> |
| - | #include <time.h> |
| - | |
| - | #include "uuidP.h" |
| - | |
| - | time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) |
| - | { |
| - | struct uuid uuid; |
| - | uint32_t high; |
| - | struct timeval tv; |
| - | unsigned long long clock_reg; |
| - | |
| - | uuid_unpack(uu, &uuid); |
| - | |
| - | high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); |
| - | clock_reg = uuid.time_low | ((unsigned long long) high << 32); |
| - | |
| - | clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; |
| - | tv.tv_sec = clock_reg / 10000000; |
| - | tv.tv_usec = (clock_reg % 10000000) / 10; |
| - | |
| - | if (ret_tv) |
| - | *ret_tv = tv; |
| - | |
| - | return tv.tv_sec; |
| - | } |
| - | |
| - | int uuid_type(const uuid_t uu) |
| - | { |
| - | struct uuid uuid; |
| - | |
| - | uuid_unpack(uu, &uuid); |
| - | return ((uuid.time_hi_and_version >> 12) & 0xF); |
| - | } |
| - | |
| - | int uuid_variant(const uuid_t uu) |
| - | { |
| - | struct uuid uuid; |
| - | int var; |
| - | |
| - | uuid_unpack(uu, &uuid); |
| - | var = uuid.clock_seq; |
| - | |
| - | if ((var & 0x8000) == 0) |
| - | return UUID_VARIANT_NCS; |
| - | if ((var & 0x4000) == 0) |
| - | return UUID_VARIANT_DCE; |
| - | if ((var & 0x2000) == 0) |
| - | return UUID_VARIANT_MICROSOFT; |
| - | return UUID_VARIANT_OTHER; |
| - | } |
| - | |
| - | #ifdef DEBUG |
| - | static const char *variant_string(int variant) |
| - | { |
| - | switch (variant) { |
| - | case UUID_VARIANT_NCS: |
| - | return "NCS"; |
| - | case UUID_VARIANT_DCE: |
| - | return "DCE"; |
| - | case UUID_VARIANT_MICROSOFT: |
| - | return "Microsoft"; |
| - | default: |
| - | return "Other"; |
| - | } |
| - | } |
| - | |
| - | |
| - | int |
| - | main(int argc, char **argv) |
| - | { |
| - | uuid_t buf; |
| - | time_t time_reg; |
| - | struct timeval tv; |
| - | int type, variant; |
| - | |
| - | if (argc != 2) { |
| - | fprintf(stderr, "Usage: %s uuid\n", argv[0]); |
| - | exit(1); |
| - | } |
| - | if (uuid_parse(argv[1], buf)) { |
| - | fprintf(stderr, "Invalid UUID: %s\n", argv[1]); |
| - | exit(1); |
| - | } |
| - | variant = uuid_variant(buf); |
| - | type = uuid_type(buf); |
| - | time_reg = uuid_time(buf, &tv); |
| - | |
| - | printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); |
| - | if (variant != UUID_VARIANT_DCE) { |
| - | printf("Warning: This program only knows how to interpret " |
| - | "DCE UUIDs.\n\tThe rest of the output is likely " |
| - | "to be incorrect!!\n"); |
| - | } |
| - | printf("UUID type is %d", type); |
| - | switch (type) { |
| - | case 1: |
| - | printf(" (time based)\n"); |
| - | break; |
| - | case 2: |
| - | printf(" (DCE)\n"); |
| - | break; |
| - | case 3: |
| - | printf(" (name-based)\n"); |
| - | break; |
| - | case 4: |
| - | printf(" (random)\n"); |
| - | break; |
| - | default: |
| - | bb_putchar('\n'); |
| - | } |
| - | if (type != 1) { |
| - | printf("Warning: not a time-based UUID, so UUID time " |
| - | "decoding will likely not work!\n"); |
| - | } |
| - | printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec, |
| - | ctime(&time_reg)); |
| - | |
| - | return 0; |
| - | } |
| - | #endif |