pmt: e2fsprogs: cleanup
This commit is contained in:
379
jni/e2fsprogs/Makefile
Executable file
379
jni/e2fsprogs/Makefile
Executable file
@@ -0,0 +1,379 @@
|
||||
# By YZBruh
|
||||
|
||||
# Copyright 2024 Partition Manager
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#####
|
||||
# sub-make for building e2fsprogs (built-in mke2fs)
|
||||
#####
|
||||
|
||||
# Include required files
|
||||
include ../../build/config/env.mk
|
||||
ifeq ($(INC_OLDENV),true)
|
||||
include ../../build/config/oldenv.mk
|
||||
endif
|
||||
|
||||
# Some variables, flags etc.
|
||||
E := @ echo
|
||||
INCLUDE := $(realpath ../../include/e2fsprogs)
|
||||
E2FSPROGS_DEFAULT_CFLAGS = \
|
||||
-std=c17 \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Wno-pointer-arith \
|
||||
-Wno-sign-compare \
|
||||
-Wno-type-limits \
|
||||
-Wno-typedef-redefinition \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-unused-command-line-argument \
|
||||
-fPIC \
|
||||
-pthread
|
||||
INCLUDE_DIRS := \
|
||||
$(INCLUDE)/misc \
|
||||
$(INCLUDE)/blkid \
|
||||
$(INCLUDE)/e2p \
|
||||
$(INCLUDE)/et \
|
||||
$(INCLUDE)/ext2fs \
|
||||
$(INCLUDE)/ss \
|
||||
$(INCLUDE)/support \
|
||||
$(INCLUDE)/uuid \
|
||||
$(INCLUDE)/e2fsck \
|
||||
$(INCLUDE)
|
||||
INC_DIRS := $(foreach dir,$(INCLUDE_DIRS),$(shell echo -I$(dir)))
|
||||
CFLAGS := $(E2FSPROGS_DEFAULT_CFLAGS) $(INC_DIRS)
|
||||
ARFLAGS := rcs
|
||||
OUT := $(realpath ../../out/e2fsprogs)
|
||||
MKE2FS := $(CURDIR)/mke2fs
|
||||
LIB := $(CURDIR)/lib
|
||||
LIBEXT2FS := $(LIB)/ext2fs
|
||||
LIBEXT2_UUID := $(LIB)/uuid
|
||||
LIBEXT2_E2P := $(LIB)/e2p
|
||||
LIBEXT2_QUOTA := $(LIB)/support
|
||||
LIBEXT2_MISC := $(LIB)/misc
|
||||
LIBEXT2_COM_ERR := $(LIB)/et
|
||||
LIBEXT2_BLKID := $(LIB)/blkid
|
||||
|
||||
# Source list of mke2fs
|
||||
MKE2FS_SRCS := \
|
||||
$(MKE2FS)/default_profile.c \
|
||||
$(MKE2FS)/mk_hugefiles.c \
|
||||
$(MKE2FS)/mke2fs.c \
|
||||
$(MKE2FS)/util.c
|
||||
|
||||
# Source list of libext2fs
|
||||
LIBEXT2FS_SRCS := \
|
||||
$(LIBEXT2FS)/alloc.c \
|
||||
$(LIBEXT2FS)/alloc_sb.c \
|
||||
$(LIBEXT2FS)/alloc_stats.c \
|
||||
$(LIBEXT2FS)/alloc_tables.c \
|
||||
$(LIBEXT2FS)/atexit.c \
|
||||
$(LIBEXT2FS)/badblocks.c \
|
||||
$(LIBEXT2FS)/bb_inode.c \
|
||||
$(LIBEXT2FS)/bitmaps.c \
|
||||
$(LIBEXT2FS)/bitops.c \
|
||||
$(LIBEXT2FS)/blkmap64_ba.c \
|
||||
$(LIBEXT2FS)/blkmap64_rb.c \
|
||||
$(LIBEXT2FS)/blknum.c \
|
||||
$(LIBEXT2FS)/block.c \
|
||||
$(LIBEXT2FS)/bmap.c \
|
||||
$(LIBEXT2FS)/check_desc.c \
|
||||
$(LIBEXT2FS)/crc16.c \
|
||||
$(LIBEXT2FS)/crc32c.c \
|
||||
$(LIBEXT2FS)/csum.c \
|
||||
$(LIBEXT2FS)/closefs.c \
|
||||
$(LIBEXT2FS)/dblist.c \
|
||||
$(LIBEXT2FS)/dblist_dir.c \
|
||||
$(LIBEXT2FS)/digest_encode.c \
|
||||
$(LIBEXT2FS)/dirblock.c \
|
||||
$(LIBEXT2FS)/dirhash.c \
|
||||
$(LIBEXT2FS)/dir_iterate.c \
|
||||
$(LIBEXT2FS)/dupfs.c \
|
||||
$(LIBEXT2FS)/expanddir.c \
|
||||
$(LIBEXT2FS)/ext2_err.c \
|
||||
$(LIBEXT2FS)/ext_attr.c \
|
||||
$(LIBEXT2FS)/extent.c \
|
||||
$(LIBEXT2FS)/fallocate.c \
|
||||
$(LIBEXT2FS)/fileio.c \
|
||||
$(LIBEXT2FS)/finddev.c \
|
||||
$(LIBEXT2FS)/flushb.c \
|
||||
$(LIBEXT2FS)/freefs.c \
|
||||
$(LIBEXT2FS)/gen_bitmap.c \
|
||||
$(LIBEXT2FS)/gen_bitmap64.c \
|
||||
$(LIBEXT2FS)/get_num_dirs.c \
|
||||
$(LIBEXT2FS)/get_pathname.c \
|
||||
$(LIBEXT2FS)/getsize.c \
|
||||
$(LIBEXT2FS)/getsectsize.c \
|
||||
$(LIBEXT2FS)/hashmap.c \
|
||||
$(LIBEXT2FS)/i_block.c \
|
||||
$(LIBEXT2FS)/icount.c \
|
||||
$(LIBEXT2FS)/imager.c \
|
||||
$(LIBEXT2FS)/ind_block.c \
|
||||
$(LIBEXT2FS)/initialize.c \
|
||||
$(LIBEXT2FS)/inline.c \
|
||||
$(LIBEXT2FS)/inline_data.c \
|
||||
$(LIBEXT2FS)/inode.c \
|
||||
$(LIBEXT2FS)/io_manager.c \
|
||||
$(LIBEXT2FS)/ismounted.c \
|
||||
$(LIBEXT2FS)/link.c \
|
||||
$(LIBEXT2FS)/llseek.c \
|
||||
$(LIBEXT2FS)/lookup.c \
|
||||
$(LIBEXT2FS)/mmp.c \
|
||||
$(LIBEXT2FS)/mkdir.c \
|
||||
$(LIBEXT2FS)/mkjournal.c \
|
||||
$(LIBEXT2FS)/namei.c \
|
||||
$(LIBEXT2FS)/native.c \
|
||||
$(LIBEXT2FS)/newdir.c \
|
||||
$(LIBEXT2FS)/nls_utf8.c \
|
||||
$(LIBEXT2FS)/openfs.c \
|
||||
$(LIBEXT2FS)/progress.c \
|
||||
$(LIBEXT2FS)/punch.c \
|
||||
$(LIBEXT2FS)/qcow2.c \
|
||||
$(LIBEXT2FS)/rbtree.c \
|
||||
$(LIBEXT2FS)/read_bb.c \
|
||||
$(LIBEXT2FS)/read_bb_file.c \
|
||||
$(LIBEXT2FS)/res_gdt.c \
|
||||
$(LIBEXT2FS)/rw_bitmaps.c \
|
||||
$(LIBEXT2FS)/sha256.c \
|
||||
$(LIBEXT2FS)/sha512.c \
|
||||
$(LIBEXT2FS)/swapfs.c \
|
||||
$(LIBEXT2FS)/symlink.c \
|
||||
$(LIBEXT2FS)/undo_io.c \
|
||||
$(LIBEXT2FS)/unix_io.c \
|
||||
$(LIBEXT2FS)/sparse_io.c \
|
||||
$(LIBEXT2FS)/unlink.c \
|
||||
$(LIBEXT2FS)/valid_blk.c \
|
||||
$(LIBEXT2FS)/version.c \
|
||||
$(LIBEXT2FS)/test_io.c
|
||||
|
||||
# Source list of libext2_uuid
|
||||
LIBEXT2_UUID_SRCS := \
|
||||
$(LIBEXT2_UUID)/clear.c \
|
||||
$(LIBEXT2_UUID)/compare.c \
|
||||
$(LIBEXT2_UUID)/copy.c \
|
||||
$(LIBEXT2_UUID)/gen_uuid.c \
|
||||
$(LIBEXT2_UUID)/isnull.c \
|
||||
$(LIBEXT2_UUID)/pack.c \
|
||||
$(LIBEXT2_UUID)/parse.c \
|
||||
$(LIBEXT2_UUID)/unpack.c \
|
||||
$(LIBEXT2_UUID)/unparse.c \
|
||||
$(LIBEXT2_UUID)/uuid_time.c
|
||||
|
||||
# Source list of libext2_blkid
|
||||
LIBEXT2_BLKID_SRCS := \
|
||||
$(LIBEXT2_BLKID)/cache.c \
|
||||
$(LIBEXT2_BLKID)/dev.c \
|
||||
$(LIBEXT2_BLKID)/devname.c \
|
||||
$(LIBEXT2_BLKID)/devno.c \
|
||||
$(LIBEXT2_BLKID)/getsize.c \
|
||||
$(LIBEXT2_BLKID)/llseek.c \
|
||||
$(LIBEXT2_BLKID)/probe.c \
|
||||
$(LIBEXT2_BLKID)/read.c \
|
||||
$(LIBEXT2_BLKID)/resolve.c \
|
||||
$(LIBEXT2_BLKID)/save.c \
|
||||
$(LIBEXT2_BLKID)/tag.c \
|
||||
$(LIBEXT2_BLKID)/version.c
|
||||
|
||||
# Source list of libext2_e2p
|
||||
LIBEXT2_E2P_SRCS := \
|
||||
$(LIBEXT2_E2P)/crypto_mode.c \
|
||||
$(LIBEXT2_E2P)/encoding.c \
|
||||
$(LIBEXT2_E2P)/errcode.c \
|
||||
$(LIBEXT2_E2P)/feature.c \
|
||||
$(LIBEXT2_E2P)/fgetflags.c \
|
||||
$(LIBEXT2_E2P)/fgetproject.c \
|
||||
$(LIBEXT2_E2P)/fgetversion.c \
|
||||
$(LIBEXT2_E2P)/fsetflags.c \
|
||||
$(LIBEXT2_E2P)/fsetproject.c \
|
||||
$(LIBEXT2_E2P)/fsetversion.c \
|
||||
$(LIBEXT2_E2P)/getflags.c \
|
||||
$(LIBEXT2_E2P)/getversion.c \
|
||||
$(LIBEXT2_E2P)/hashstr.c \
|
||||
$(LIBEXT2_E2P)/iod.c \
|
||||
$(LIBEXT2_E2P)/ljs.c \
|
||||
$(LIBEXT2_E2P)/ls.c \
|
||||
$(LIBEXT2_E2P)/mntopts.c \
|
||||
$(LIBEXT2_E2P)/ostype.c \
|
||||
$(LIBEXT2_E2P)/parse_num.c \
|
||||
$(LIBEXT2_E2P)/pe.c \
|
||||
$(LIBEXT2_E2P)/percent.c \
|
||||
$(LIBEXT2_E2P)/pf.c \
|
||||
$(LIBEXT2_E2P)/ps.c \
|
||||
$(LIBEXT2_E2P)/setflags.c \
|
||||
$(LIBEXT2_E2P)/setversion.c \
|
||||
$(LIBEXT2_E2P)/uuid.c
|
||||
|
||||
# Source list of libext2_quota
|
||||
LIBEXT2_QUOTA_SRCS := \
|
||||
$(LIBEXT2_QUOTA)/devname.c \
|
||||
$(LIBEXT2_QUOTA)/dict.c \
|
||||
$(LIBEXT2_QUOTA)/mkquota.c \
|
||||
$(LIBEXT2_QUOTA)/parse_qtype.c \
|
||||
$(LIBEXT2_QUOTA)/plausible.c \
|
||||
$(LIBEXT2_QUOTA)/prof_err.c \
|
||||
$(LIBEXT2_QUOTA)/profile.c \
|
||||
$(LIBEXT2_QUOTA)/profile_helpers.c \
|
||||
$(LIBEXT2_QUOTA)/quotaio.c \
|
||||
$(LIBEXT2_QUOTA)/quotaio_tree.c \
|
||||
$(LIBEXT2_QUOTA)/quotaio_v2.c
|
||||
|
||||
# Source od libext2_misc
|
||||
LIBEXT2_MISC_SRCS := $(LIBEXT2_MISC)/create_inode.c
|
||||
|
||||
# Source list of libext2_com_err
|
||||
LIBEXT2_COM_ERR_SRCS := \
|
||||
$(LIBEXT2_COM_ERR)/com_err.c \
|
||||
$(LIBEXT2_COM_ERR)/com_right.c \
|
||||
$(LIBEXT2_COM_ERR)/error_message.c \
|
||||
$(LIBEXT2_COM_ERR)/et_name.c \
|
||||
$(LIBEXT2_COM_ERR)/init_et.c
|
||||
|
||||
# Object lists
|
||||
MKE2FS_OBJS := $(MKE2FS_SRCS:.c=.o)
|
||||
LIBEXT2FS_OBJS := $(LIBEXT2FS_SRCS:.c=.o)
|
||||
LIBEXT2_UUID_OBJS := $(LIBEXT2_UUID_SRCS:.c=.o)
|
||||
LIBEXT2_BLKID_OBJS := $(LIBEXT2_BLKID_SRCS:.c=.o)
|
||||
LIBEXT2_E2P_OBJS := $(LIBEXT2_E2P_SRCS:.c=.o)
|
||||
LIBEXT2_QUOTA_OBJS := $(LIBEXT2_QUOTA_SRCS:.c=.o)
|
||||
LIBEXT2_MISC_OBJS := $(LIBEXT2_MISC_SRCS:.c=.o)
|
||||
LIBEXT2_COM_ERR_OBJS := $(LIBEXT2_COM_ERR_SRCS:.c=.o)
|
||||
|
||||
# Compiler flags (CFLAGS)
|
||||
LIBEXT2FS_CFLAGS := -Wno-unused-but-set-variable
|
||||
LIBEXT2_E2P_CFLAGS := -Wno-error=attributes
|
||||
LIBEXT2_MISC_CFLAGS := -Wno-error=format-extra-args
|
||||
LIBEXT2_BLKID_CFLAGS := \
|
||||
-Wno-error=attributes \
|
||||
-Wno-error=pointer-sign \
|
||||
-Wno-unused-but-set-variable \
|
||||
-fno-strict-aliasing
|
||||
|
||||
# Full object list
|
||||
OBJS_ALL := \
|
||||
$(MKE2FS_OBJS) \
|
||||
$(LIBEXT2FS_OBJS) \
|
||||
$(LIBEXT2_BLKID_OBJS) \
|
||||
$(LIBEXT2_UUID_OBJS) \
|
||||
$(LIBEXT2_E2P_OBJS) \
|
||||
$(LIBEXT2_QUOTA_OBJS) \
|
||||
$(LIBEXT2_MISC_OBJS) \
|
||||
$(LIBEXT2_COM_ERR_OBJS)
|
||||
|
||||
# Progress list
|
||||
PROGRESS_LIST := \
|
||||
$(LIBEXT2_BLKID_OBJS) \
|
||||
libext2_blkid_ar \
|
||||
$(LIBEXT2_UUID_OBJS) \
|
||||
libext2_uuid_ar \
|
||||
$(LIBEXT2_E2P_OBJS) \
|
||||
libext2_e2p_ar \
|
||||
$(LIBEXT2FS_OBJS) \
|
||||
libext2fs_ar \
|
||||
$(LIBEXT2_QUOTA_OBJS) \
|
||||
libext2_quota_ar \
|
||||
$(LIBEXT2_MISC_OBJS) \
|
||||
libext2_misc_ar \
|
||||
$(LIBEXT2_COM_ERR_OBJS) \
|
||||
libext2_com_err_ar \
|
||||
$(MKE2FS_OBJS) \
|
||||
mke2fs_dummy_ld
|
||||
|
||||
.PHONY: all
|
||||
all: $(PROGRESS_LIST)
|
||||
|
||||
# Cleaner
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ rm -rf $(OBJS_ALL)
|
||||
|
||||
#######################################
|
||||
# 'MAKE' TARGETS FOR BUILDING OBJECTS #
|
||||
#######################################
|
||||
|
||||
$(MKE2FS)/%.o: $(MKE2FS)/%.c
|
||||
$(E) " CC e2fsprogs/`basename $(MKE2FS)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) $(MKE2FS_CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2FS)/%.o: $(LIBEXT2FS)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2FS)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) $(LIBEXT2FS_CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2_BLKID)/%.o: $(LIBEXT2_BLKID)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2_BLKID)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) $(LIBEXT2_BLKID_CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2_E2P)/%.o: $(LIBEXT2_E2P)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2_E2P)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2_UUID)/%.o: $(LIBEXT2_UUID)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2_UUID)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2_QUOTA)/%.o: $(LIBEXT2_QUOTA)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2_QUOTA)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2_MISC)/%.o: $(LIBEXT2_MISC)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2_MISC)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) $(LIBEXT2_MISC_CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
$(LIBEXT2_COM_ERR)/%.o: $(LIBEXT2_COM_ERR)/%.c
|
||||
$(E) " CC e2fsprogs/lib/`basename $(LIBEXT2_COM_ERR)`/`basename $@`"
|
||||
@ $(CC) -c $(CFLAGS) "$<" -o "$@" || exit 1
|
||||
|
||||
#############################################
|
||||
# 'MAKE' TARGETS FOR GENERATING STATIC LIBS #
|
||||
#############################################
|
||||
|
||||
libext2fs_ar: $(LIBEXT2FS_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2fs.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2fs.a $^ || exit 1
|
||||
$(E) " ----------- libext2_quota -----------"
|
||||
|
||||
libext2_blkid_ar: $(LIBEXT2_BLKID_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2_blkid.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2_blkid.a $^ || exit 1
|
||||
$(E) " ----------- libext2_uuid ---------"
|
||||
|
||||
libext2_e2p_ar: $(LIBEXT2_E2P_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2_e2p.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2_e2p.a $^ || exit 1
|
||||
$(E) " ----------- libext2fs -----------"
|
||||
|
||||
libext2_uuid_ar: $(LIBEXT2_UUID_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2_uuid.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2_uuid.a $^ || exit 1
|
||||
$(E) " ----------- libext2_e2p -----------"
|
||||
|
||||
libext2_quota_ar: $(LIBEXT2_QUOTA_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2_quota.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2_quota.a $^ || exit 1
|
||||
$(E) " ----------- libext2_misc -----------"
|
||||
|
||||
libext2_misc_ar: $(LIBEXT2_MISC_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2_misc.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2_misc.a $^ || exit 1
|
||||
$(E) " ----------- libext2_com_err -----------"
|
||||
|
||||
libext2_com_err_ar: $(LIBEXT2_COM_ERR_OBJS)
|
||||
$(E) " AR out/e2fsprogs/libext2_com_err.a"
|
||||
@ $(AR) $(ARFLAGS) $(OUT)/libext2_com_err.a $^ || exit 1
|
||||
$(E) " ----------- mke2fs -----------"
|
||||
|
||||
#############################################
|
||||
# DUMMY 'MAKE' TARGET FOR DISPLAYING MKE2FS #
|
||||
#############################################
|
||||
|
||||
mke2fs_dummy_ld:
|
||||
$(E) " DMY mke2fs"
|
||||
849
jni/e2fsprogs/NOTICE
Executable file
849
jni/e2fsprogs/NOTICE
Executable file
@@ -0,0 +1,849 @@
|
||||
This package, the EXT2 filesystem utilities, are made available under
|
||||
the GNU Public License version 2, with the exception of the lib/ext2fs
|
||||
and lib/e2p libraries, which are made available under the GNU Library
|
||||
General Public License Version 2, the lib/uuid library which is made
|
||||
available under a BSD-style license and the lib/et and lib/ss
|
||||
libraries which are made available under an MIT-style license. Please
|
||||
see lib/uuid/COPYING for more details for the license for the files
|
||||
comprising the libuuid library, and the source file headers of the
|
||||
libet and libss libraries for more information.
|
||||
|
||||
The most recent officially distributed version can be found at
|
||||
http://e2fsprogs.sourceforge.net. If you need to make a distribution,
|
||||
that's the one you should use. If there is some reason why you'd like
|
||||
a more recent version that is still in ALPHA testing (i.e., either
|
||||
using the "WIP" test distributions or one from the hg or git
|
||||
repository from the development branch, please contact me
|
||||
(tytso@mit.edu) before you ship. The release schedules for this
|
||||
package are flexible, if you give me enough lead time.
|
||||
|
||||
|
||||
Theodore Ts'o
|
||||
23-June-2007
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
209
jni/e2fsprogs/lib/blkid/cache.c
Executable file
209
jni/e2fsprogs/lib/blkid/cache.c
Executable file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#else
|
||||
#define PR_GET_DUMPABLE 3
|
||||
#endif
|
||||
#if (!defined(HAVE_PRCTL) && defined(linux))
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include "blkidP.h"
|
||||
|
||||
int blkid_debug_mask = 0;
|
||||
|
||||
|
||||
static char *safe_getenv(const char *arg)
|
||||
{
|
||||
if ((getuid() != geteuid()) || (getgid() != getegid()))
|
||||
return NULL;
|
||||
#if HAVE_PRCTL
|
||||
if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
|
||||
return NULL;
|
||||
#else
|
||||
#if (defined(linux) && defined(SYS_prctl))
|
||||
if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
|
||||
return NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SECURE_GETENV)
|
||||
return secure_getenv(arg);
|
||||
#elif defined(HAVE___SECURE_GETENV)
|
||||
return __secure_getenv(arg);
|
||||
#else
|
||||
return getenv(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0 /* ifdef CONFIG_BLKID_DEBUG */
|
||||
static blkid_debug_dump_cache(int mask, blkid_cache cache)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
if (!cache) {
|
||||
printf("cache: NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("cache: time = %lu\n", cache->bic_time);
|
||||
printf("cache: flags = 0x%08X\n", cache->bic_flags);
|
||||
|
||||
list_for_each(p, &cache->bic_devs) {
|
||||
blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
|
||||
blkid_debug_dump_dev(dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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"));
|
||||
|
||||
if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
INIT_LIST_HEAD(&cache->bic_devs);
|
||||
INIT_LIST_HEAD(&cache->bic_tags);
|
||||
|
||||
if (filename && !strlen(filename))
|
||||
filename = 0;
|
||||
if (!filename)
|
||||
filename = safe_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);
|
||||
}
|
||||
|
||||
void blkid_gc_cache(blkid_cache cache)
|
||||
{
|
||||
struct list_head *p, *pnext;
|
||||
struct stat st;
|
||||
|
||||
if (!cache)
|
||||
return;
|
||||
|
||||
list_for_each_safe(p, pnext, &cache->bic_devs) {
|
||||
blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
|
||||
if (stat(dev->bid_name, &st) < 0) {
|
||||
DBG(DEBUG_CACHE,
|
||||
printf("freeing %s\n", dev->bid_name));
|
||||
blkid_free_dev(dev);
|
||||
cache->bic_flags |= BLKID_BIC_FL_CHANGED;
|
||||
} else {
|
||||
DBG(DEBUG_CACHE,
|
||||
printf("Device %s exists\n", dev->bid_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#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, "/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
|
||||
254
jni/e2fsprogs/lib/blkid/dev.c
Executable file
254
jni/e2fsprogs/lib/blkid/dev.c
Executable file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "blkidP.h"
|
||||
|
||||
blkid_dev blkid_new_dev(void)
|
||||
{
|
||||
blkid_dev dev;
|
||||
|
||||
if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev))))
|
||||
return NULL;
|
||||
|
||||
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 ?
|
||||
dev->bid_type : "(null)"));
|
||||
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
|
||||
*/
|
||||
extern 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", (long long)dev->bid_devno);
|
||||
printf(" dev: TIME=\"%ld\"\n", (long)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");
|
||||
}
|
||||
printf("\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;
|
||||
char *search_type;
|
||||
char *search_value;
|
||||
struct list_head *p;
|
||||
};
|
||||
|
||||
extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
|
||||
{
|
||||
blkid_dev_iterate iter;
|
||||
|
||||
iter = malloc(sizeof(struct blkid_struct_dev_iterate));
|
||||
if (iter) {
|
||||
iter->magic = DEV_ITERATE_MAGIC;
|
||||
iter->cache = cache;
|
||||
iter->p = cache->bic_devs.next;
|
||||
iter->search_type = 0;
|
||||
iter->search_value = 0;
|
||||
}
|
||||
return (iter);
|
||||
}
|
||||
|
||||
extern int blkid_dev_set_search(blkid_dev_iterate iter,
|
||||
char *search_type, char *search_value)
|
||||
{
|
||||
char *new_type, *new_value;
|
||||
|
||||
if (!iter || iter->magic != DEV_ITERATE_MAGIC || !search_type ||
|
||||
!search_value)
|
||||
return -1;
|
||||
new_type = malloc(strlen(search_type)+1);
|
||||
new_value = malloc(strlen(search_value)+1);
|
||||
if (!new_type || !new_value) {
|
||||
free(new_type);
|
||||
free(new_value);
|
||||
return -1;
|
||||
}
|
||||
strcpy(new_type, search_type);
|
||||
strcpy(new_value, search_value);
|
||||
free(iter->search_type);
|
||||
free(iter->search_value);
|
||||
iter->search_type = new_type;
|
||||
iter->search_value = new_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 on success, -1 on error
|
||||
*/
|
||||
extern int blkid_dev_next(blkid_dev_iterate iter,
|
||||
blkid_dev *ret_dev)
|
||||
{
|
||||
blkid_dev dev;
|
||||
|
||||
*ret_dev = 0;
|
||||
if (!iter || iter->magic != DEV_ITERATE_MAGIC)
|
||||
return -1;
|
||||
while (iter->p != &iter->cache->bic_devs) {
|
||||
dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs);
|
||||
iter->p = iter->p->next;
|
||||
if (iter->search_type &&
|
||||
!blkid_dev_has_tag(dev, iter->search_type,
|
||||
iter->search_value))
|
||||
continue;
|
||||
*ret_dev = dev;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern 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
|
||||
561
jni/e2fsprogs/lib/blkid/devname.c
Executable file
561
jni/e2fsprogs/lib/blkid/devname.c
Executable file
@@ -0,0 +1,561 @@
|
||||
/*
|
||||
* 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%
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.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, *pnext;
|
||||
|
||||
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)) {
|
||||
if (access(devname, F_OK) < 0)
|
||||
return NULL;
|
||||
dev = blkid_new_dev();
|
||||
if (!dev)
|
||||
return NULL;
|
||||
dev->bid_time = INT_MIN;
|
||||
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);
|
||||
if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED))
|
||||
return dev;
|
||||
/*
|
||||
* If the device is verified, then search the blkid
|
||||
* cache for any entries that match on the type, uuid,
|
||||
* and label, and verify them; if a cache entry can
|
||||
* not be verified, then it's stale and so we remove
|
||||
* it.
|
||||
*/
|
||||
list_for_each_safe(p, pnext, &cache->bic_devs) {
|
||||
blkid_dev dev2;
|
||||
dev2 = list_entry(p, struct blkid_struct_dev, bid_devs);
|
||||
if (dev2->bid_flags & BLKID_BID_FL_VERIFIED)
|
||||
continue;
|
||||
if (!dev->bid_type || !dev2->bid_type ||
|
||||
strcmp(dev->bid_type, dev2->bid_type))
|
||||
continue;
|
||||
if (dev->bid_label && dev2->bid_label &&
|
||||
strcmp(dev->bid_label, dev2->bid_label))
|
||||
continue;
|
||||
if (dev->bid_uuid && dev2->bid_uuid &&
|
||||
strcmp(dev->bid_uuid, dev2->bid_uuid))
|
||||
continue;
|
||||
if ((dev->bid_label && !dev2->bid_label) ||
|
||||
(!dev->bid_label && dev2->bid_label) ||
|
||||
(dev->bid_uuid && !dev2->bid_uuid) ||
|
||||
(!dev->bid_uuid && dev2->bid_uuid))
|
||||
continue;
|
||||
dev2 = blkid_verify(cache, dev2);
|
||||
if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED))
|
||||
blkid_free_dev(dev2);
|
||||
}
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* Directories where we will try to search for device names */
|
||||
static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL };
|
||||
|
||||
static int is_dm_leaf(const char *devname)
|
||||
{
|
||||
struct dirent *de, *d_de;
|
||||
DIR *dir, *d_dir;
|
||||
char path[300];
|
||||
int ret = 1;
|
||||
|
||||
if ((dir = opendir("/sys/block")) == NULL)
|
||||
return 0;
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
|
||||
!strcmp(de->d_name, devname) ||
|
||||
strncmp(de->d_name, "dm-", 3) ||
|
||||
strlen(de->d_name) > sizeof(path)-32)
|
||||
continue;
|
||||
sprintf(path, "/sys/block/%s/slaves", de->d_name);
|
||||
if ((d_dir = opendir(path)) == NULL)
|
||||
continue;
|
||||
while ((d_de = readdir(d_dir)) != NULL) {
|
||||
if (!strcmp(d_de->d_name, devname)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(d_dir);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
closedir(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
|
||||
* provides the real DM device names in /sys/block/<ptname>/dm/name
|
||||
*/
|
||||
static char *get_dm_name(const char *ptname)
|
||||
{
|
||||
FILE *f;
|
||||
size_t sz;
|
||||
char path[300], name[256], *res = NULL;
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
|
||||
if ((f = fopen(path, "r")) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* read "<name>\n" from sysfs */
|
||||
if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
|
||||
name[sz - 1] = '\0';
|
||||
snprintf(path, sizeof(path), "/dev/mapper/%s", name);
|
||||
res = blkid_strdup(path);
|
||||
}
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, int only_if_new)
|
||||
{
|
||||
blkid_dev dev = NULL;
|
||||
struct list_head *p, *pnext;
|
||||
const char **dir;
|
||||
char *devname = NULL;
|
||||
|
||||
/* See if we already have this device number in the cache. */
|
||||
list_for_each_safe(p, pnext, &cache->bic_devs) {
|
||||
blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
|
||||
bid_devs);
|
||||
if (tmp->bid_devno == devno) {
|
||||
if (only_if_new && !access(tmp->bid_name, F_OK))
|
||||
return;
|
||||
dev = blkid_verify(cache, tmp);
|
||||
if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
|
||||
break;
|
||||
dev = 0;
|
||||
}
|
||||
}
|
||||
if (dev && dev->bid_devno == devno)
|
||||
goto set_pri;
|
||||
|
||||
/* Try to translate private device-mapper dm-<N> names
|
||||
* to standard /dev/mapper/<name>.
|
||||
*/
|
||||
if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) {
|
||||
devname = get_dm_name(ptname);
|
||||
if (!devname)
|
||||
blkid__scan_dir("/dev/mapper", devno, 0, &devname);
|
||||
if (devname)
|
||||
goto get_dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = dirlist; *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 &&
|
||||
blkidP_is_disk_device(st.st_mode) &&
|
||||
st.st_rdev == devno) {
|
||||
devname = blkid_strdup(device);
|
||||
goto get_dev;
|
||||
}
|
||||
}
|
||||
/* Do a short-cut scan of /dev/mapper first */
|
||||
if (!devname)
|
||||
devname = get_dm_name(ptname);
|
||||
if (!devname)
|
||||
blkid__scan_dir("/dev/mapper", devno, 0, &devname);
|
||||
if (!devname) {
|
||||
devname = blkid_devno_to_devname(devno);
|
||||
if (!devname)
|
||||
return;
|
||||
}
|
||||
get_dev:
|
||||
dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
|
||||
free(devname);
|
||||
set_pri:
|
||||
if (dev) {
|
||||
if (pri)
|
||||
dev->bid_pri = pri;
|
||||
else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) {
|
||||
dev->bid_pri = BLKID_PRI_DM;
|
||||
if (is_dm_leaf(ptname))
|
||||
dev->bid_pri += 5;
|
||||
} else if (!strncmp(ptname, "md", 2))
|
||||
dev->bid_pri = BLKID_PRI_MD;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#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
|
||||
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(lvm_device, "r")) == 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, int only_if_new)
|
||||
{
|
||||
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 (!strcmp(vg_name, ".") || !strcmp(vg_name, ".."))
|
||||
continue;
|
||||
vdirname = malloc(vg_len + strlen(vg_name) + 8);
|
||||
if (!vdirname)
|
||||
goto exit;
|
||||
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 (!strcmp(lv_name, ".") || !strcmp(lv_name, ".."))
|
||||
continue;
|
||||
|
||||
lvm_device = malloc(vg_len + strlen(vg_name) +
|
||||
strlen(lv_name) + 8);
|
||||
if (!lvm_device) {
|
||||
closedir(lv_list);
|
||||
goto exit;
|
||||
}
|
||||
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,
|
||||
only_if_new);
|
||||
free(lvm_device);
|
||||
}
|
||||
closedir(lv_list);
|
||||
}
|
||||
exit:
|
||||
closedir(vg_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
|
||||
|
||||
static int
|
||||
evms_probe_all(blkid_cache cache, int only_if_new)
|
||||
{
|
||||
char line[100];
|
||||
int ma, mi, sz, num = 0;
|
||||
FILE *procpt;
|
||||
char device[110];
|
||||
|
||||
procpt = fopen(PROC_EVMS_VOLUMES, "r");
|
||||
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,
|
||||
only_if_new);
|
||||
num++;
|
||||
}
|
||||
fclose(procpt);
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the device data for all available block devices in the system.
|
||||
*/
|
||||
static int probe_all(blkid_cache cache, int only_if_new)
|
||||
{
|
||||
FILE *proc;
|
||||
char line[1024];
|
||||
char ptname0[129], ptname1[129], *ptname = 0;
|
||||
char *ptnames[2];
|
||||
dev_t devs[2];
|
||||
int ma, mi;
|
||||
unsigned long long sz;
|
||||
int lens[2] = { 0, 0 };
|
||||
int which = 0, last = 0;
|
||||
struct list_head *p, *pnext;
|
||||
|
||||
ptnames[0] = ptname0;
|
||||
ptnames[1] = ptname1;
|
||||
|
||||
if (!cache)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (cache->bic_flags & BLKID_BIC_FL_PROBED &&
|
||||
time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
|
||||
return 0;
|
||||
|
||||
blkid_read_cache(cache);
|
||||
evms_probe_all(cache, only_if_new);
|
||||
#ifdef VG_DIR
|
||||
lvm_probe_all(cache, only_if_new);
|
||||
#endif
|
||||
|
||||
proc = fopen(PROC_PARTITIONS, "r");
|
||||
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 base name of device has changed, also
|
||||
* check previous dev to see if it didn't have a partn.
|
||||
* heuristic: partition name ends in a digit, & partition
|
||||
* names contain whole device name as substring.
|
||||
*
|
||||
* Skip extended partitions.
|
||||
* heuristic: size is 1
|
||||
*
|
||||
* FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
|
||||
*/
|
||||
|
||||
lens[which] = strlen(ptname);
|
||||
|
||||
/* ends in a digit, clearly a partition, so check */
|
||||
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,
|
||||
only_if_new);
|
||||
lens[which] = 0; /* mark as checked */
|
||||
}
|
||||
|
||||
/*
|
||||
* If last was a whole disk and we just found a partition
|
||||
* on it, remove the whole-disk dev from the cache if
|
||||
* it exists.
|
||||
*/
|
||||
if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) {
|
||||
list_for_each_safe(p, pnext, &cache->bic_devs) {
|
||||
blkid_dev tmp;
|
||||
|
||||
/* find blkid dev for the whole-disk devno */
|
||||
tmp = list_entry(p, struct blkid_struct_dev,
|
||||
bid_devs);
|
||||
if (tmp->bid_devno == devs[last]) {
|
||||
DBG(DEBUG_DEVNAME,
|
||||
printf("freeing %s\n",
|
||||
tmp->bid_name));
|
||||
blkid_free_dev(tmp);
|
||||
cache->bic_flags |= BLKID_BIC_FL_CHANGED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lens[last] = 0;
|
||||
}
|
||||
/*
|
||||
* If last was not checked because it looked like a whole-disk
|
||||
* dev, and the device's base name has changed,
|
||||
* check last as well.
|
||||
*/
|
||||
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,
|
||||
only_if_new);
|
||||
lens[last] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the last device if it wasn't partitioned */
|
||||
if (lens[which])
|
||||
probe_one(cache, ptname, devs[which], 0, only_if_new);
|
||||
|
||||
fclose(proc);
|
||||
blkid_flush_cache(cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blkid_probe_all(blkid_cache cache)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n"));
|
||||
ret = probe_all(cache, 0);
|
||||
cache->bic_time = time(0);
|
||||
cache->bic_flags |= BLKID_BIC_FL_PROBED;
|
||||
DBG(DEBUG_PROBE, printf("End blkid_probe_all()\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blkid_probe_all_new(blkid_cache cache)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n"));
|
||||
ret = probe_all(cache, 1);
|
||||
DBG(DEBUG_PROBE, printf("End blkid_probe_all_new()\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#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, "/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
|
||||
242
jni/e2fsprogs/lib/blkid/devno.c
Executable file
242
jni/e2fsprogs/lib/blkid/devno.c
Executable file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "blkidP.h"
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 8
|
||||
/* gcc incorrectly thinks the destination string is not being null-terminated */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||
#endif
|
||||
|
||||
char *blkid_strndup(const char *s, int length)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (!length)
|
||||
length = strlen(s);
|
||||
|
||||
ret = malloc(length + 1);
|
||||
if (ret) {
|
||||
strncpy(ret, s, length);
|
||||
ret[length] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 8
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
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 = malloc(sizeof(struct dir_list));
|
||||
if (!dp)
|
||||
return;
|
||||
dp->name = blkid_strdup(name);
|
||||
if (!dp->name) {
|
||||
free(dp);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void blkid__scan_dir(const char *dirname, 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(dirname)) == NULL)
|
||||
return;
|
||||
dirlen = strlen(dirname) + 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", dirname, dp->d_name);
|
||||
if (stat(path, &st) < 0)
|
||||
continue;
|
||||
|
||||
if (blkidP_is_disk_device(st.st_mode) && st.st_rdev == devno) {
|
||||
*devname = blkid_strdup(path);
|
||||
DBG(DEBUG_DEVNO,
|
||||
printf("found 0x%llx at %s (%p)\n", (long long)devno,
|
||||
path, *devname));
|
||||
break;
|
||||
}
|
||||
if (list && S_ISDIR(st.st_mode) && !lstat(path, &st) &&
|
||||
S_ISDIR(st.st_mode))
|
||||
add_to_dirlist(path, list);
|
||||
}
|
||||
closedir(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Directories where we will try to search for device numbers */
|
||||
static const char *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 = 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));
|
||||
blkid__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: couldn't find devno 0x%04lx\n",
|
||||
(unsigned long) devno));
|
||||
} else {
|
||||
DBG(DEBUG_DEVNO,
|
||||
printf("found devno 0x%04llx as %s\n", (long long)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 = "Couldn't 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%04llx\n", (long long)devno);
|
||||
devname = blkid_devno_to_devname(devno);
|
||||
free(devname);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
217
jni/e2fsprogs/lib/blkid/getsize.c
Executable file
217
jni/e2fsprogs/lib/blkid/getsize.c
Executable file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "blkidP.h"
|
||||
|
||||
#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
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.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 bytes in a partition
|
||||
*/
|
||||
blkid_loff_t blkid_get_dev_size(int fd)
|
||||
{
|
||||
unsigned long long size64 __BLKID_ATTR((unused));
|
||||
blkid_loff_t high, low;
|
||||
|
||||
#if defined DKIOCGETBLOCKCOUNT && defined DKIOCGETBLOCKSIZE /* For Apple Darwin */
|
||||
unsigned int size;
|
||||
|
||||
if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0 &&
|
||||
ioctl(fd, DKIOCGETBLOCKSIZE, &size) >= 0) {
|
||||
if (sizeof(blkid_loff_t) < sizeof(unsigned long long) &&
|
||||
(size64 * size) > 0xFFFFFFFF)
|
||||
return 0; /* EFBIG */
|
||||
return (blkid_loff_t)size64 * size;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BLKGETSIZE64
|
||||
{
|
||||
int valid_blkgetsize64 = 1;
|
||||
#ifdef __linux__
|
||||
struct utsname ut;
|
||||
|
||||
if ((uname(&ut) == 0) &&
|
||||
((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 /* BLKGETSIZE64 */
|
||||
|
||||
#ifdef BLKGETSIZE
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE, &size) >= 0)
|
||||
return (blkid_loff_t)size << 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* tested on FreeBSD 6.1-RELEASE i386 */
|
||||
#ifdef DIOCGMEDIASIZE
|
||||
if (ioctl(fd, DIOCGMEDIASIZE, &size64) >= 0)
|
||||
return (off_t)size64;
|
||||
#endif /* DIOCGMEDIASIZE */
|
||||
|
||||
#ifdef FDGETPRM
|
||||
{
|
||||
struct floppy_struct this_floppy;
|
||||
|
||||
if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
|
||||
return (blkid_loff_t)this_floppy.size << 9;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO)
|
||||
{
|
||||
int part = -1;
|
||||
struct disklabel lab;
|
||||
struct partition *pp;
|
||||
char ch;
|
||||
struct stat st;
|
||||
|
||||
/*
|
||||
* This code works for FreeBSD 4.11 i386, except for the full
|
||||
* device (such as /dev/ad0). It doesn't work properly for
|
||||
* newer FreeBSD though. FreeBSD >= 5.0 should be covered by
|
||||
* the DIOCGMEDIASIZE above however.
|
||||
*
|
||||
* Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
|
||||
* character) devices, so we need to check for S_ISCHR, too.
|
||||
*/
|
||||
if (fstat(fd, &st) >= 0 &&
|
||||
blkidP_is_disk_device(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 /* defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) */
|
||||
{
|
||||
#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
|
||||
struct stat64 st;
|
||||
if (fstat64(fd, &st) == 0)
|
||||
#else
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == 0)
|
||||
#endif
|
||||
if (S_ISREG(st.st_mode))
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
long long 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],
|
||||
(unsigned long long)bytes >> 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
147
jni/e2fsprogs/lib/blkid/llseek.c
Executable file
147
jni/e2fsprogs/lib/blkid/llseek.c
Executable file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* llseek.c -- stub calling the llseek system call
|
||||
*
|
||||
* Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "blkidP.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
|
||||
|
||||
#define my_llseek lseek64
|
||||
|
||||
#elif defined(HAVE_LLSEEK)
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#ifndef HAVE_LLSEEK_PROTOTYPE
|
||||
extern long long llseek(int fd, long long offset, int origin);
|
||||
#endif
|
||||
|
||||
#define my_llseek llseek
|
||||
|
||||
#else /* ! HAVE_LLSEEK */
|
||||
|
||||
#if SIZEOF_LONG == SIZEOF_LONG_LONG
|
||||
|
||||
#define llseek lseek
|
||||
|
||||
#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */
|
||||
|
||||
#include <linux/unistd.h>
|
||||
|
||||
#ifndef __NR__llseek
|
||||
#define __NR__llseek 140
|
||||
#endif
|
||||
|
||||
#ifndef __i386__
|
||||
static int _llseek(unsigned int, unsigned long, unsigned long,
|
||||
blkid_loff_t *, unsigned int);
|
||||
|
||||
static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high,
|
||||
unsigned long, offset_low, blkid_loff_t *, result,
|
||||
unsigned int, origin)
|
||||
#endif
|
||||
|
||||
static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin)
|
||||
{
|
||||
blkid_loff_t result;
|
||||
int retval;
|
||||
|
||||
#ifndef __i386__
|
||||
retval = _llseek(fd, ((unsigned long long) offset) >> 32,
|
||||
((unsigned long long)offset) & 0xffffffff,
|
||||
&result, origin);
|
||||
#else
|
||||
retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32,
|
||||
((unsigned long long)offset) & 0xffffffff,
|
||||
&result, origin);
|
||||
#endif
|
||||
return (retval == -1 ? (blkid_loff_t) retval : result);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ || __ia64__ */
|
||||
|
||||
#endif /* HAVE_LLSEEK */
|
||||
|
||||
blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence)
|
||||
{
|
||||
blkid_loff_t result;
|
||||
static int do_compat = 0;
|
||||
|
||||
if ((sizeof(off_t) >= sizeof(blkid_loff_t)) ||
|
||||
(offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1))))
|
||||
return lseek(fd, (off_t) offset, whence);
|
||||
|
||||
if (do_compat) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = my_llseek(fd, offset, whence);
|
||||
if (result == -1 && errno == ENOSYS) {
|
||||
/*
|
||||
* Just in case this code runs on top of an old kernel
|
||||
* which does not support the llseek system call
|
||||
*/
|
||||
do_compat++;
|
||||
errno = EOVERFLOW;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else /* !linux */
|
||||
|
||||
#ifndef EOVERFLOW
|
||||
#ifdef EXT2_ET_INVALID_ARGUMENT
|
||||
#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT
|
||||
#else
|
||||
#define EOVERFLOW 112
|
||||
#endif
|
||||
#endif
|
||||
|
||||
blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin)
|
||||
{
|
||||
#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
|
||||
return lseek64 (fd, offset, origin);
|
||||
#else
|
||||
if ((sizeof(off_t) < sizeof(blkid_loff_t)) &&
|
||||
(offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
return lseek(fd, (off_t) offset, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* linux */
|
||||
|
||||
|
||||
1841
jni/e2fsprogs/lib/blkid/probe.c
Executable file
1841
jni/e2fsprogs/lib/blkid/probe.c
Executable file
File diff suppressed because it is too large
Load Diff
494
jni/e2fsprogs/lib/blkid/read.c
Executable file
494
jni/e2fsprogs/lib/blkid/read.c
Executable file
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* 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%
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 600 /* for inclusion of strtoull */
|
||||
|
||||
#include "config.h"
|
||||
#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>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "blkidP.h"
|
||||
#include "uuid/uuid.h"
|
||||
|
||||
#ifdef HAVE_STRTOULL
|
||||
#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
|
||||
#else
|
||||
/* FIXME: need to support real strtoull here */
|
||||
#define STRTOULL strtoul
|
||||
#endif
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static char *parse_word(char **buf)
|
||||
{
|
||||
char *word, *next;
|
||||
|
||||
word = *buf;
|
||||
if (*word == '\0')
|
||||
return NULL;
|
||||
|
||||
word = skip_over_blank(word);
|
||||
next = skip_over_word(word);
|
||||
if (*next) {
|
||||
char *end = next - 1;
|
||||
if (*end == '"' || *end == '\'')
|
||||
*end = '\0';
|
||||
*next++ = '\0';
|
||||
}
|
||||
*buf = next;
|
||||
|
||||
if (*word == '"' || *word == '\'')
|
||||
word++;
|
||||
return word;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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",
|
||||
(int)(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))) {
|
||||
free(name);
|
||||
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"))
|
||||
dev->bid_time = STRTOULL(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 = fdopen(fd, "r");
|
||||
if (!file)
|
||||
goto errout;
|
||||
|
||||
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 (buf[end] == '\\' && end < sizeof(buf) - 2 &&
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
#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", (long long)dev->bid_devno);
|
||||
printf(" dev: TIME=\"%lld\"\n", (long long)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");
|
||||
}
|
||||
printf("\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
|
||||
140
jni/e2fsprogs/lib/blkid/resolve.c
Executable file
140
jni/e2fsprogs/lib/blkid/resolve.c
Executable file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#include <stdio.h>
|
||||
#if 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"
|
||||
|
||||
/*
|
||||
* 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 = 0, *v = 0;
|
||||
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, '=')) {
|
||||
ret = blkid_strdup(token);
|
||||
goto out;
|
||||
}
|
||||
blkid_parse_tag_string(token, &t, &v);
|
||||
if (!t || !v)
|
||||
goto out;
|
||||
token = t;
|
||||
value = v;
|
||||
}
|
||||
|
||||
dev = blkid_find_dev_with_tag(c, token, value);
|
||||
if (!dev)
|
||||
goto out;
|
||||
|
||||
ret = blkid_strdup(blkid_dev_devname(dev));
|
||||
|
||||
out:
|
||||
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, "/dev/null") < 0) {
|
||||
fprintf(stderr, "Couldn'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
|
||||
213
jni/e2fsprogs/lib/blkid/save.c
Executable file
213
jni/e2fsprogs/lib/blkid/save.c
Executable file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#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"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
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 ?
|
||||
dev->bid_type : "(null)"));
|
||||
|
||||
fprintf(file,
|
||||
"<device DEVNO=\"0x%04lx\" TIME=\"%ld\"",
|
||||
(unsigned long) dev->bid_devno, (long) 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 = malloc(strlen(filename) + 8);
|
||||
if (tmp) {
|
||||
mode_t save_umask = umask(022);
|
||||
sprintf(tmp, "%s-XXXXXX", filename);
|
||||
fd = mkstemp(tmp);
|
||||
umask(save_umask);
|
||||
if (fd >= 0) {
|
||||
file = fdopen(fd, "w");
|
||||
opened = tmp;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
fchmod(fd, 0644);
|
||||
#else
|
||||
chmod(tmp, 0644);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
file = fopen(filename, "w");
|
||||
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) {
|
||||
(void) unlink(opened);
|
||||
DBG(DEBUG_SAVE,
|
||||
printf("unlinked temp cache %s\n", opened));
|
||||
} else {
|
||||
char *backup;
|
||||
|
||||
backup = malloc(strlen(filename) + 5);
|
||||
if (backup) {
|
||||
sprintf(backup, "%s.old", filename);
|
||||
unlink(backup);
|
||||
#if defined(__GNUC__) && __GNUC__ >= 5
|
||||
/* explicit (void) cast is not enough with glibc and _FORTIFY_SOURCE */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||
#endif
|
||||
(void) link(filename, backup);
|
||||
#if defined(__GNUC__) && __GNUC__ >= 5
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
free(backup);
|
||||
}
|
||||
if (rename(opened, filename) < 0)
|
||||
(void) unlink(opened);
|
||||
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, "/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
|
||||
471
jni/e2fsprogs/lib/blkid/tag.c
Executable file
471
jni/e2fsprogs/lib/blkid/tag.c
Executable file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blkidP.h"
|
||||
|
||||
static blkid_tag blkid_new_tag(void)
|
||||
{
|
||||
blkid_tag tag;
|
||||
|
||||
if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
|
||||
const char *value)
|
||||
{
|
||||
blkid_tag tag;
|
||||
|
||||
if (!dev || !type)
|
||||
return -1;
|
||||
|
||||
tag = blkid_find_tag_dev(dev, type);
|
||||
if (!value)
|
||||
return (tag != NULL);
|
||||
if (!tag || strcmp(tag->bit_val, value))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = 0;
|
||||
char **dev_var = 0;
|
||||
|
||||
if (!dev || !name)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (!(val = blkid_strndup(value, vlength)) && value)
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
/*
|
||||
* Certain common tags are linked directly to the device struct
|
||||
* We need to know what they are before we do anything else because
|
||||
* the function name parameter might get freed later on.
|
||||
*/
|
||||
if (!strcmp(name, "TYPE"))
|
||||
dev_var = &dev->bid_type;
|
||||
else if (!strcmp(name, "LABEL"))
|
||||
dev_var = &dev->bid_label;
|
||||
else if (!strcmp(name, "UUID"))
|
||||
dev_var = &dev->bid_uuid;
|
||||
|
||||
t = blkid_find_tag_dev(dev, name);
|
||||
if (!value) {
|
||||
if (t)
|
||||
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 (dev_var)
|
||||
*dev_var = val;
|
||||
|
||||
if (dev->bid_cache)
|
||||
dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (t)
|
||||
blkid_free_tag(t);
|
||||
else free(val);
|
||||
if (head)
|
||||
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;
|
||||
};
|
||||
|
||||
extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
|
||||
{
|
||||
blkid_tag_iterate iter;
|
||||
|
||||
iter = malloc(sizeof(struct blkid_struct_tag_iterate));
|
||||
if (iter) {
|
||||
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;
|
||||
}
|
||||
|
||||
extern 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.
|
||||
*/
|
||||
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;
|
||||
int probe_new = 0;
|
||||
|
||||
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) &&
|
||||
!access(tmp->bit_dev->bid_name, F_OK)) {
|
||||
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 && (dev->bid_flags & BLKID_BID_FL_VERIFIED)))
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (!dev && !probe_new) {
|
||||
if (blkid_probe_all_new(cache) < 0)
|
||||
return NULL;
|
||||
probe_new++;
|
||||
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: Can not 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
|
||||
50
jni/e2fsprogs/lib/blkid/version.c
Executable file
50
jni/e2fsprogs/lib/blkid/version.c
Executable file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* version.c --- Return the version of the blkid library
|
||||
*
|
||||
* Copyright (C) 2004 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <blkid/blkid_local.h>
|
||||
#include "version.h"
|
||||
|
||||
static const char *lib_version = E2FSPROGS_VERSION;
|
||||
static const char *lib_date = E2FSPROGS_DATE;
|
||||
|
||||
int blkid_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 blkid_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 blkid_parse_version_string(lib_version);
|
||||
}
|
||||
74
jni/e2fsprogs/lib/e2p/crypto_mode.c
Executable file
74
jni/e2fsprogs/lib/e2p/crypto_mode.c
Executable file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* crypto_mode.c --- convert between encryption modes and strings
|
||||
*
|
||||
* Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
struct mode {
|
||||
int num;
|
||||
const char *string;
|
||||
};
|
||||
|
||||
static struct mode mode_list[] = {
|
||||
{ EXT4_ENCRYPTION_MODE_INVALID, "Invalid"},
|
||||
{ EXT4_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"},
|
||||
{ EXT4_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"},
|
||||
{ EXT4_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"},
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const char *e2p_encmode2string(int num)
|
||||
{
|
||||
struct mode *p;
|
||||
static char buf[20];
|
||||
|
||||
for (p = mode_list; p->string; p++) {
|
||||
if (num == p->num)
|
||||
return p->string;
|
||||
}
|
||||
sprintf(buf, "ENC_MODE_%d", num);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the hash algorithm, or -1 on error
|
||||
*/
|
||||
int e2p_string2encmode(char *string)
|
||||
{
|
||||
struct mode *p;
|
||||
char *eptr;
|
||||
int num;
|
||||
|
||||
for (p = mode_list; p->string; p++) {
|
||||
if (!strcasecmp(string, p->string)) {
|
||||
return p->num;
|
||||
}
|
||||
}
|
||||
if (strncasecmp(string, "ENC_MODE_", 9))
|
||||
return -1;
|
||||
|
||||
if (string[9] == 0)
|
||||
return -1;
|
||||
num = strtol(string+9, &eptr, 10);
|
||||
if (num > 255 || num < 0)
|
||||
return -1;
|
||||
if (*eptr)
|
||||
return -1;
|
||||
return num;
|
||||
}
|
||||
|
||||
118
jni/e2fsprogs/lib/e2p/encoding.c
Executable file
118
jni/e2fsprogs/lib/e2p/encoding.c
Executable file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* encoding.c --- convert between encoding magic numbers and strings
|
||||
*
|
||||
* Copyright (C) 2018 Collabora Ltd.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
#define ARRAY_SIZE(array) \
|
||||
(sizeof(array) / sizeof(array[0]))
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
__u16 encoding_magic;
|
||||
__u16 default_flags;
|
||||
|
||||
} ext4_encoding_map[] = {
|
||||
{
|
||||
.encoding_magic = EXT4_ENC_UTF8_12_1,
|
||||
.name = "utf8-12.1",
|
||||
.default_flags = 0,
|
||||
},
|
||||
{
|
||||
.encoding_magic = EXT4_ENC_UTF8_12_1,
|
||||
.name = "utf8",
|
||||
.default_flags = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct enc_flags {
|
||||
__u16 flag;
|
||||
const char *param;
|
||||
} encoding_flags[] = {
|
||||
{ EXT4_ENC_STRICT_MODE_FL, "strict" },
|
||||
};
|
||||
|
||||
/* Return a positive number < 0xff indicating the encoding magic number
|
||||
* or a negative value indicating error. */
|
||||
int e2p_str2encoding(const char *string)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(ext4_encoding_map); i++)
|
||||
if (!strcmp(string, ext4_encoding_map[i].name))
|
||||
return ext4_encoding_map[i].encoding_magic;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Return the name of an encoding or NULL */
|
||||
const char *e2p_encoding2str(int encoding)
|
||||
{
|
||||
unsigned int i;
|
||||
static char buf[32];
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(ext4_encoding_map); i++)
|
||||
if (ext4_encoding_map[i].encoding_magic == encoding)
|
||||
return ext4_encoding_map[i].name;
|
||||
sprintf(buf, "UNKNOWN_ENCODING_%d", encoding);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int e2p_get_encoding_flags(int encoding)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(ext4_encoding_map); i++)
|
||||
if (ext4_encoding_map[i].encoding_magic == encoding)
|
||||
return ext4_encoding_map[i].default_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int e2p_str2encoding_flags(int encoding, char *param, __u16 *flags)
|
||||
{
|
||||
char *f = strtok(param, "-");
|
||||
const struct enc_flags *fl;
|
||||
unsigned int i, neg = 0;
|
||||
|
||||
if (encoding != EXT4_ENC_UTF8_12_1)
|
||||
return -EINVAL;
|
||||
while (f) {
|
||||
neg = 0;
|
||||
if (!strncmp("no", f, 2)) {
|
||||
neg = 1;
|
||||
f += 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(encoding_flags); i++) {
|
||||
fl = &encoding_flags[i];
|
||||
if (!strcmp(fl->param, f)) {
|
||||
if (neg)
|
||||
*flags &= ~fl->flag;
|
||||
else
|
||||
*flags |= fl->flag;
|
||||
|
||||
goto next_flag;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
next_flag:
|
||||
f = strtok(NULL, "-");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
48
jni/e2fsprogs/lib/e2p/errcode.c
Executable file
48
jni/e2fsprogs/lib/e2p/errcode.c
Executable file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* errcode.c - convert an error code to a string
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
static const char *err_string[] = {
|
||||
"",
|
||||
"UNKNOWN", /* 1 */
|
||||
"EIO", /* 2 */
|
||||
"ENOMEM", /* 3 */
|
||||
"EFSBADCRC", /* 4 */
|
||||
"EFSCORRUPTED", /* 5 */
|
||||
"ENOSPC", /* 6 */
|
||||
"ENOKEY", /* 7 */
|
||||
"EROFS", /* 8 */
|
||||
"EFBIG", /* 9 */
|
||||
"EEXIST", /* 10 */
|
||||
"ERANGE", /* 11 */
|
||||
"EOVERFLOW", /* 12 */
|
||||
"EBUSY", /* 13 */
|
||||
"ENOTDIR", /* 14 */
|
||||
"ENOTEMPTY", /* 15 */
|
||||
"ESHUTDOWN", /* 16 */
|
||||
"EFAULT", /* 17 */
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(array) \
|
||||
(sizeof(array) / sizeof(array[0]))
|
||||
|
||||
/* Return the name of an encoding or NULL */
|
||||
const char *e2p_errcode2str(unsigned int err)
|
||||
{
|
||||
static char buf[32];
|
||||
|
||||
if (err < ARRAY_SIZE(err_string))
|
||||
return err_string[err];
|
||||
|
||||
sprintf(buf, "UNKNOWN_ERRCODE_%u", err);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
445
jni/e2fsprogs/lib/e2p/feature.c
Executable file
445
jni/e2fsprogs/lib/e2p/feature.c
Executable file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* feature.c --- convert between features and strings
|
||||
*
|
||||
* Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "e2p.h"
|
||||
#include <ext2fs/ext2fs.h>
|
||||
#include <ext2fs/kernel-jbd.h>
|
||||
|
||||
struct feature {
|
||||
int compat;
|
||||
unsigned int mask;
|
||||
const char *string;
|
||||
};
|
||||
|
||||
static 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_INODE,
|
||||
"resize_inode" },
|
||||
{ E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,
|
||||
"lazy_bg" },
|
||||
{ E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP,
|
||||
"snapshot_bitmap" },
|
||||
{ E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_SPARSE_SUPER2,
|
||||
"sparse_super2" },
|
||||
{ E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_FAST_COMMIT,
|
||||
"fast_commit" },
|
||||
{ E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_STABLE_INODES,
|
||||
"stable_inodes" },
|
||||
|
||||
{ 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_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,
|
||||
"huge_file" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
|
||||
"uninit_bg" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
|
||||
"uninit_groups" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
|
||||
"dir_nlink" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
|
||||
"extra_isize" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA,
|
||||
"quota" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC,
|
||||
"bigalloc"},
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM,
|
||||
"metadata_csum"},
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA,
|
||||
"replica" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY,
|
||||
"read-only" },
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT,
|
||||
"project"},
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS,
|
||||
"shared_blocks"},
|
||||
{ E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_VERITY,
|
||||
"verity"},
|
||||
|
||||
{ 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,
|
||||
"extent" },
|
||||
{ E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
|
||||
"extents" },
|
||||
{ E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
|
||||
"meta_bg" },
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,
|
||||
"64bit" },
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP,
|
||||
"mmp" },
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,
|
||||
"flex_bg"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE,
|
||||
"ea_inode"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA,
|
||||
"dirdata"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CSUM_SEED,
|
||||
"metadata_csum_seed"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR,
|
||||
"large_dir"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA,
|
||||
"inline_data"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT,
|
||||
"encrypt"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD,
|
||||
"casefold"},
|
||||
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD,
|
||||
"fname_encoding"},
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct feature jrnl_feature_list[] = {
|
||||
{ E2P_FEATURE_COMPAT, JBD2_FEATURE_COMPAT_CHECKSUM,
|
||||
"journal_checksum" },
|
||||
|
||||
{ E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_REVOKE,
|
||||
"journal_incompat_revoke" },
|
||||
{ E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_64BIT,
|
||||
"journal_64bit" },
|
||||
{ E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT,
|
||||
"journal_async_commit" },
|
||||
{ E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V2,
|
||||
"journal_checksum_v2" },
|
||||
{ E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V3,
|
||||
"journal_checksum_v3" },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
void e2p_feature_to_string(int compat, unsigned int mask, char *buf,
|
||||
size_t buf_len)
|
||||
{
|
||||
struct feature *f;
|
||||
char fchar;
|
||||
int fnum;
|
||||
|
||||
for (f = feature_list; f->string; f++) {
|
||||
if ((compat == f->compat) &&
|
||||
(mask == f->mask)) {
|
||||
strncpy(buf, f->string, buf_len);
|
||||
buf[buf_len - 1] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
const char *e2p_feature2string(int compat, unsigned int mask)
|
||||
{
|
||||
static char buf[20];
|
||||
|
||||
e2p_feature_to_string(compat, mask, buf, sizeof(buf) / sizeof(buf[0]));
|
||||
return buf;
|
||||
}
|
||||
|
||||
int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
|
||||
{
|
||||
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 > 31 || num < 0)
|
||||
return 1;
|
||||
if (*eptr)
|
||||
return 1;
|
||||
*mask = 1 << num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *e2p_jrnl_feature2string(int compat, unsigned int mask)
|
||||
{
|
||||
struct feature *f;
|
||||
static char buf[20];
|
||||
char fchar;
|
||||
int fnum;
|
||||
|
||||
for (f = jrnl_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_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask)
|
||||
{
|
||||
struct feature *f;
|
||||
char *eptr;
|
||||
int num;
|
||||
|
||||
for (f = jrnl_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 > 31 || 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 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. If clear_ok_array is set,
|
||||
* then use it tell whether or not it is OK to clear a filesystem feature.
|
||||
*/
|
||||
int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,
|
||||
__u32 *clear_ok_array, int *type_err,
|
||||
unsigned int *mask_err)
|
||||
{
|
||||
char *cp, *buf, *next;
|
||||
int neg;
|
||||
unsigned int mask;
|
||||
int compat_type;
|
||||
int rc = 0;
|
||||
|
||||
if (!clear_ok_array)
|
||||
clear_ok_array = ok_array;
|
||||
|
||||
if (type_err)
|
||||
*type_err = 0;
|
||||
if (mask_err)
|
||||
*mask_err = 0;
|
||||
|
||||
buf = malloc(strlen(str)+1);
|
||||
if (!buf)
|
||||
return 1;
|
||||
strcpy(buf, str);
|
||||
for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {
|
||||
neg = 0;
|
||||
cp = skip_over_blanks(cp);
|
||||
next = skip_over_word(cp);
|
||||
|
||||
if (*next == 0)
|
||||
next = 0;
|
||||
else
|
||||
*next = 0;
|
||||
|
||||
if ((strcasecmp(cp, "none") == 0) ||
|
||||
(strcasecmp(cp, "clear") == 0)) {
|
||||
compat_array[0] = 0;
|
||||
compat_array[1] = 0;
|
||||
compat_array[2] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*cp) {
|
||||
case '-':
|
||||
case '^':
|
||||
neg++;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
cp++;
|
||||
break;
|
||||
}
|
||||
if (e2p_string2feature(cp, &compat_type, &mask)) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
if (neg) {
|
||||
if (clear_ok_array &&
|
||||
!(clear_ok_array[compat_type] & mask)) {
|
||||
rc = 1;
|
||||
if (type_err)
|
||||
*type_err = (compat_type |
|
||||
E2P_FEATURE_NEGATE_FLAG);
|
||||
if (mask_err)
|
||||
*mask_err = mask;
|
||||
break;
|
||||
}
|
||||
compat_array[compat_type] &= ~mask;
|
||||
} else {
|
||||
if (ok_array && !(ok_array[compat_type] & mask)) {
|
||||
rc = 1;
|
||||
if (type_err)
|
||||
*type_err = compat_type;
|
||||
if (mask_err)
|
||||
*mask_err = mask;
|
||||
break;
|
||||
}
|
||||
compat_array[compat_type] |= mask;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
|
||||
{
|
||||
return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int compat, compat2, i;
|
||||
unsigned int mask, mask2;
|
||||
const char *str;
|
||||
struct feature *f;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (i == 0) {
|
||||
f = feature_list;
|
||||
printf("Feature list:\n");
|
||||
} else {
|
||||
printf("\nJournal feature list:\n");
|
||||
f = jrnl_feature_list;
|
||||
}
|
||||
for (; f->string; f++) {
|
||||
if (i == 0) {
|
||||
e2p_string2feature((char *)f->string, &compat,
|
||||
&mask);
|
||||
str = e2p_feature2string(compat, mask);
|
||||
} else {
|
||||
e2p_jrnl_string2feature((char *)f->string,
|
||||
&compat, &mask);
|
||||
str = e2p_jrnl_feature2string(compat, mask);
|
||||
}
|
||||
|
||||
printf("\tCompat = %d, Mask = %u, %s\n",
|
||||
compat, mask, f->string);
|
||||
if (strcmp(f->string, str)) {
|
||||
if (e2p_string2feature((char *) str, &compat2,
|
||||
&mask2) ||
|
||||
(compat2 != compat) ||
|
||||
(mask2 != mask)) {
|
||||
fprintf(stderr, "Failure!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
117
jni/e2fsprogs/lib/e2p/fgetflags.c
Executable file
117
jni/e2fsprogs/lib/e2p/fgetflags.c
Executable file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* fgetflags.c - Get a file flags on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef O_NOFOLLOW
|
||||
#define O_NOFOLLOW 0
|
||||
#endif
|
||||
|
||||
#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_NOFOLLOW)
|
||||
|
||||
int fgetflags (const char * name, unsigned long * flags)
|
||||
{
|
||||
#if HAVE_STAT_FLAGS && !(APPLE_DARWIN && HAVE_EXT2_IOCTLS)
|
||||
struct stat buf;
|
||||
|
||||
if (stat (name, &buf) == -1)
|
||||
return -1;
|
||||
|
||||
*flags = 0;
|
||||
#ifdef UF_IMMUTABLE
|
||||
if (buf.st_flags & UF_IMMUTABLE)
|
||||
*flags |= EXT2_IMMUTABLE_FL;
|
||||
#endif
|
||||
#ifdef UF_APPEND
|
||||
if (buf.st_flags & UF_APPEND)
|
||||
*flags |= EXT2_APPEND_FL;
|
||||
#endif
|
||||
#ifdef UF_NODUMP
|
||||
if (buf.st_flags & UF_NODUMP)
|
||||
*flags |= EXT2_NODUMP_FL;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#elif APPLE_DARWIN && HAVE_EXT2_IOCTLS
|
||||
int f, save_errno = 0;
|
||||
|
||||
f = -1;
|
||||
save_errno = syscall(SYS_fsctl, name, EXT2_IOC_GETFLAGS, &f, 0);
|
||||
*flags = f;
|
||||
return (save_errno);
|
||||
#elif 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)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
fd = open(name, OPEN_FLAGS);
|
||||
if (fd == -1) {
|
||||
if (errno == ELOOP || errno == ENXIO)
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
if (!fstat(fd, &buf) &&
|
||||
!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
|
||||
close(fd);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
r = ioctl(fd, EXT2_IOC_GETFLAGS, &f);
|
||||
if (r == -1) {
|
||||
if (errno == ENOTTY)
|
||||
errno = EOPNOTSUPP;
|
||||
save_errno = errno;
|
||||
}
|
||||
*flags = f;
|
||||
close(fd);
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return r;
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
63
jni/e2fsprogs/lib/e2p/fgetproject.c
Executable file
63
jni/e2fsprogs/lib/e2p/fgetproject.c
Executable file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* fgetproject.c --- get project id
|
||||
*
|
||||
* Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "project.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 fgetproject(const char *name, unsigned long *project)
|
||||
{
|
||||
#ifndef FS_IOC_FSGETXATTR
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#else
|
||||
int fd, r, save_errno = 0;
|
||||
struct fsxattr fsx;
|
||||
|
||||
fd = open (name, OPEN_FLAGS);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
r = ioctl (fd, FS_IOC_FSGETXATTR, &fsx);
|
||||
if (r == 0)
|
||||
*project = fsx.fsx_projid;
|
||||
save_errno = errno;
|
||||
close (fd);
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
74
jni/e2fsprogs/lib/e2p/fgetversion.c
Executable file
74
jni/e2fsprogs/lib/e2p/fgetversion.c
Executable file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* fgetversion.c - Get a file version on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#if HAVE_SYS_IOCTL_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 fgetversion(const char *name, unsigned long *version)
|
||||
{
|
||||
unsigned int ver = -1;
|
||||
int rc = -1;
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
# if !APPLE_DARWIN
|
||||
int fd, save_errno = 0;
|
||||
|
||||
fd = open(name, OPEN_FLAGS);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
rc = ioctl(fd, EXT2_IOC_GETVERSION, &ver);
|
||||
if (rc == -1)
|
||||
save_errno = errno;
|
||||
close(fd);
|
||||
if (rc == -1)
|
||||
errno = save_errno;
|
||||
# else /* APPLE_DARWIN */
|
||||
rc = syscall(SYS_fsctl, name, EXT2_IOC_GETVERSION, &ver, 0);
|
||||
# endif /* !APPLE_DARWIN */
|
||||
#else /* ! HAVE_EXT2_IOCTLS */
|
||||
errno = EOPNOTSUPP;
|
||||
#endif /* ! HAVE_EXT2_IOCTLS */
|
||||
if (rc == 0)
|
||||
*version = ver;
|
||||
|
||||
return rc;
|
||||
}
|
||||
118
jni/e2fsprogs/lib/e2p/fsetflags.c
Executable file
118
jni/e2fsprogs/lib/e2p/fsetflags.c
Executable file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* fsetflags.c - Set a file flags on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
/*
|
||||
* Deal with lame glibc's that define this function without actually
|
||||
* implementing it. Can you say "attractive nuisance", boys and girls?
|
||||
* I knew you could!
|
||||
*/
|
||||
#ifdef __linux__
|
||||
#undef HAVE_CHFLAGS
|
||||
#endif
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef O_NOFOLLOW
|
||||
#define O_NOFOLLOW 0
|
||||
#endif
|
||||
|
||||
#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_NOFOLLOW)
|
||||
|
||||
int fsetflags (const char * name, unsigned long flags)
|
||||
{
|
||||
#if HAVE_CHFLAGS && !(APPLE_DARWIN && HAVE_EXT2_IOCTLS)
|
||||
unsigned long bsd_flags = 0;
|
||||
|
||||
#ifdef UF_IMMUTABLE
|
||||
if (flags & EXT2_IMMUTABLE_FL)
|
||||
bsd_flags |= UF_IMMUTABLE;
|
||||
#endif
|
||||
#ifdef UF_APPEND
|
||||
if (flags & EXT2_APPEND_FL)
|
||||
bsd_flags |= UF_APPEND;
|
||||
#endif
|
||||
#ifdef UF_NODUMP
|
||||
if (flags & EXT2_NODUMP_FL)
|
||||
bsd_flags |= UF_NODUMP;
|
||||
#endif
|
||||
|
||||
return chflags (name, bsd_flags);
|
||||
#elif APPLE_DARWIN && HAVE_EXT2_IOCTLS
|
||||
int f = (int) flags;
|
||||
return syscall(SYS_fsctl, name, EXT2_IOC_SETFLAGS, &f, 0);
|
||||
#elif 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)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
fd = open(name, OPEN_FLAGS);
|
||||
if (fd == -1) {
|
||||
if (errno == ELOOP || errno == ENXIO)
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
if (!fstat(fd, &buf) &&
|
||||
!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
|
||||
close(fd);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
f = (int) flags;
|
||||
r = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
|
||||
if (r == -1) {
|
||||
if (errno == ENOTTY)
|
||||
errno = EOPNOTSUPP;
|
||||
save_errno = errno;
|
||||
}
|
||||
close(fd);
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return r;
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
69
jni/e2fsprogs/lib/e2p/fsetproject.c
Executable file
69
jni/e2fsprogs/lib/e2p/fsetproject.c
Executable file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* fgetproject.c --- get project id
|
||||
*
|
||||
* Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "project.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 fsetproject(const char *name, unsigned long project)
|
||||
{
|
||||
#ifndef FS_IOC_FSGETXATTR
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#else
|
||||
int fd, r, save_errno = 0;
|
||||
struct fsxattr fsx;
|
||||
|
||||
fd = open (name, OPEN_FLAGS);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
r = ioctl (fd, FS_IOC_FSGETXATTR, &fsx);
|
||||
if (r == -1) {
|
||||
save_errno = errno;
|
||||
goto errout;
|
||||
}
|
||||
fsx.fsx_projid = project;
|
||||
r = ioctl (fd, FS_IOC_FSSETXATTR, &fsx);
|
||||
if (r == -1)
|
||||
save_errno = errno;
|
||||
errout:
|
||||
close (fd);
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
71
jni/e2fsprogs/lib/e2p/fsetversion.c
Executable file
71
jni/e2fsprogs/lib/e2p/fsetversion.c
Executable file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* fsetversion.c - Set a file version on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#if HAVE_SYS_IOCTL_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 fsetversion (const char * name, unsigned long version)
|
||||
{
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#if !APPLE_DARWIN
|
||||
int fd, r, ver, save_errno = 0;
|
||||
|
||||
fd = open (name, OPEN_FLAGS);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
ver = (int) version;
|
||||
r = ioctl (fd, EXT2_IOC_SETVERSION, &ver);
|
||||
if (r == -1)
|
||||
save_errno = errno;
|
||||
close (fd);
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return r;
|
||||
#else
|
||||
int ver = (int)version;
|
||||
return syscall(SYS_fsctl, name, EXT2_IOC_SETVERSION, &ver, 0);
|
||||
#endif
|
||||
#else /* ! HAVE_EXT2_IOCTLS */
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#endif /* ! HAVE_EXT2_IOCTLS */
|
||||
}
|
||||
71
jni/e2fsprogs/lib/e2p/getflags.c
Executable file
71
jni/e2fsprogs/lib/e2p/getflags.c
Executable file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* getflags.c - Get a file flags on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
int getflags (int fd, unsigned long * flags)
|
||||
{
|
||||
#if HAVE_STAT_FLAGS
|
||||
struct stat buf;
|
||||
|
||||
if (fstat (fd, &buf) == -1)
|
||||
return -1;
|
||||
|
||||
*flags = 0;
|
||||
#ifdef UF_IMMUTABLE
|
||||
if (buf.st_flags & UF_IMMUTABLE)
|
||||
*flags |= EXT2_IMMUTABLE_FL;
|
||||
#endif
|
||||
#ifdef UF_APPEND
|
||||
if (buf.st_flags & UF_APPEND)
|
||||
*flags |= EXT2_APPEND_FL;
|
||||
#endif
|
||||
#ifdef UF_NODUMP
|
||||
if (buf.st_flags & UF_NODUMP)
|
||||
*flags |= EXT2_NODUMP_FL;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#else
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
struct stat buf;
|
||||
int r, f;
|
||||
|
||||
if (!fstat(fd, &buf) &&
|
||||
!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode))
|
||||
goto notsupp;
|
||||
r = ioctl(fd, EXT2_IOC_GETFLAGS, &f);
|
||||
*flags = f;
|
||||
|
||||
return r;
|
||||
notsupp:
|
||||
#endif /* HAVE_EXT2_IOCTLS */
|
||||
#endif
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
41
jni/e2fsprogs/lib/e2p/getversion.c
Executable file
41
jni/e2fsprogs/lib/e2p/getversion.c
Executable file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* getversion.c - Get a file version on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
int getversion (int fd, unsigned long * version)
|
||||
{
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
int r, ver;
|
||||
|
||||
r = ioctl (fd, EXT2_IOC_GETVERSION, &ver);
|
||||
*version = ver;
|
||||
return r;
|
||||
#else /* ! HAVE_EXT2_IOCTLS */
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#endif /* ! HAVE_EXT2_IOCTLS */
|
||||
}
|
||||
72
jni/e2fsprogs/lib/e2p/hashstr.c
Executable file
72
jni/e2fsprogs/lib/e2p/hashstr.c
Executable file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* feature.c --- convert between features and strings
|
||||
*
|
||||
* Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
76
jni/e2fsprogs/lib/e2p/iod.c
Executable file
76
jni/e2fsprogs/lib/e2p/iod.c
Executable file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* iod.c - Iterate a function on each entry of a directory
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "e2p.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#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 = -1, len, ret = 0;
|
||||
|
||||
#if HAVE_PATHCONF && defined(_PC_NAME_MAX)
|
||||
max_len = pathconf(dir_name, _PC_NAME_MAX);
|
||||
#endif
|
||||
if (max_len == -1) {
|
||||
#ifdef _POSIX_NAME_MAX
|
||||
max_len = _POSIX_NAME_MAX;
|
||||
#else
|
||||
#ifdef NAME_MAX
|
||||
max_len = NAME_MAX;
|
||||
#else
|
||||
max_len = 256;
|
||||
#endif /* NAME_MAX */
|
||||
#endif /* _POSIX_NAME_MAX */
|
||||
}
|
||||
max_len += sizeof(struct dirent);
|
||||
|
||||
de = malloc(max_len+1);
|
||||
if (!de)
|
||||
return -1;
|
||||
memset(de, 0, max_len+1);
|
||||
|
||||
dir = opendir (dir_name);
|
||||
if (dir == NULL) {
|
||||
free(de);
|
||||
return -1;
|
||||
}
|
||||
while ((dep = readdir (dir))) {
|
||||
#ifdef HAVE_RECLEN_DIRENT
|
||||
len = dep->d_reclen;
|
||||
if (len > max_len)
|
||||
len = max_len;
|
||||
#else
|
||||
len = sizeof(struct dirent);
|
||||
#endif
|
||||
memcpy(de, dep, len);
|
||||
if ((*func)(dir_name, de, private))
|
||||
ret++;
|
||||
}
|
||||
free(de);
|
||||
closedir(dir);
|
||||
return ret;
|
||||
}
|
||||
134
jni/e2fsprogs/lib/e2p/ljs.c
Executable file
134
jni/e2fsprogs/lib/e2p/ljs.c
Executable file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* ljs.c - List the contents of an journal superblock
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2fs/ext2_fs.h"
|
||||
#include "ext2fs/ext2fs.h"
|
||||
#include "e2p.h"
|
||||
#include "ext2fs/kernel-jbd.h"
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define e2p_be32(x) (x)
|
||||
#else
|
||||
static __u32 e2p_swab32(__u32 val)
|
||||
{
|
||||
return ((val>>24) | ((val>>8)&0xFF00) |
|
||||
((val<<8)&0xFF0000) | (val<<24));
|
||||
}
|
||||
|
||||
#define e2p_be32(x) e2p_swab32(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function is copied from kernel-jbd.h's function
|
||||
* jbd2_journal_get_num_fc_blks() to avoid inter-library dependencies.
|
||||
*/
|
||||
static inline int get_num_fc_blks(journal_superblock_t *jsb)
|
||||
{
|
||||
int num_fc_blocks = e2p_be32(jsb->s_num_fc_blks);
|
||||
|
||||
return num_fc_blocks ? num_fc_blocks : JBD2_DEFAULT_FAST_COMMIT_BLOCKS;
|
||||
}
|
||||
|
||||
static const char *journal_checksum_type_str(__u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case JBD2_CRC32C_CHKSUM:
|
||||
return "crc32c";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void e2p_list_journal_super(FILE *f, char *journal_sb_buf,
|
||||
int exp_block_size, int flags)
|
||||
{
|
||||
journal_superblock_t *jsb = (journal_superblock_t *) journal_sb_buf;
|
||||
__u32 *mask_ptr, mask, m;
|
||||
unsigned int size;
|
||||
int j, printed = 0;
|
||||
unsigned int i, nr_users;
|
||||
int num_fc_blks = 0;
|
||||
int journal_blks = 0;
|
||||
|
||||
if (flags & E2P_LIST_JOURNAL_FLAG_FC)
|
||||
num_fc_blks = get_num_fc_blks((journal_superblock_t *)journal_sb_buf);
|
||||
journal_blks = ntohl(jsb->s_maxlen) - num_fc_blks;
|
||||
fprintf(f, "%s", "Journal features: ");
|
||||
for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) {
|
||||
mask = e2p_be32(*mask_ptr);
|
||||
for (j=0,m=1; j < 32; j++, m<<=1) {
|
||||
if (mask & m) {
|
||||
fprintf(f, " %s", e2p_jrnl_feature2string(i, m));
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (printed == 0)
|
||||
fprintf(f, " (none)");
|
||||
fputc('\n', f);
|
||||
fputs("Total journal size: ", f);
|
||||
size = (ntohl(jsb->s_blocksize) / 1024) * ntohl(jsb->s_maxlen);
|
||||
if (size < 8192)
|
||||
fprintf(f, "%uk\n", size);
|
||||
else
|
||||
fprintf(f, "%uM\n", size >> 10);
|
||||
nr_users = (unsigned int) ntohl(jsb->s_nr_users);
|
||||
if (exp_block_size != (int) ntohl(jsb->s_blocksize))
|
||||
fprintf(f, "Journal block size: %u\n",
|
||||
(unsigned int)ntohl(jsb->s_blocksize));
|
||||
fprintf(f, "Total journal blocks: %u\n",
|
||||
(unsigned int)(journal_blks + num_fc_blks));
|
||||
fprintf(f, "Max transaction length: %u\n",
|
||||
(unsigned int)journal_blks);
|
||||
fprintf(f, "Fast commit length: %u\n",
|
||||
(unsigned int)num_fc_blks);
|
||||
|
||||
if (ntohl(jsb->s_first) != 1)
|
||||
fprintf(f, "Journal first block: %u\n",
|
||||
(unsigned int)ntohl(jsb->s_first));
|
||||
fprintf(f, "Journal sequence: 0x%08x\n"
|
||||
"Journal start: %u\n",
|
||||
(unsigned int)ntohl(jsb->s_sequence),
|
||||
(unsigned int)ntohl(jsb->s_start));
|
||||
if (nr_users != 1)
|
||||
fprintf(f, "Journal number of users: %u\n", nr_users);
|
||||
if (jsb->s_feature_compat & e2p_be32(JBD2_FEATURE_COMPAT_CHECKSUM))
|
||||
fprintf(f, "%s", "Journal checksum type: crc32\n");
|
||||
if ((jsb->s_feature_incompat &
|
||||
e2p_be32(JBD2_FEATURE_INCOMPAT_CSUM_V3)) ||
|
||||
(jsb->s_feature_incompat &
|
||||
e2p_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2)))
|
||||
fprintf(f, "Journal checksum type: %s\n"
|
||||
"Journal checksum: 0x%08x\n",
|
||||
journal_checksum_type_str(jsb->s_checksum_type),
|
||||
e2p_be32(jsb->s_checksum));
|
||||
if ((nr_users > 1) ||
|
||||
!e2p_is_null_uuid(&jsb->s_users[0])) {
|
||||
for (i=0; i < nr_users && i < JBD2_USERS_MAX; i++) {
|
||||
printf(i ? " %s\n"
|
||||
: "Journal users: %s\n",
|
||||
e2p_uuid2str(&jsb->s_users[i * UUID_SIZE]));
|
||||
}
|
||||
}
|
||||
if (jsb->s_errno != 0)
|
||||
fprintf(f, "Journal errno: %d\n",
|
||||
(int) ntohl(jsb->s_errno));
|
||||
}
|
||||
491
jni/e2fsprogs/lib/e2p/ls.c
Executable file
491
jni/e2fsprogs/lib/e2p/ls.c
Executable file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* ls.c - List the contents of an ext2fs superblock
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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"
|
||||
#include "support/quotaio.h"
|
||||
|
||||
static void print_user (unsigned short uid, FILE *f)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
fprintf(f, "%u ", uid);
|
||||
pw = getpwuid (uid);
|
||||
if (pw == NULL)
|
||||
fprintf(f, "(user unknown)\n");
|
||||
else
|
||||
fprintf(f, "(user %s)\n", pw->pw_name);
|
||||
}
|
||||
|
||||
static void print_group (unsigned short gid, FILE *f)
|
||||
{
|
||||
struct group *gr;
|
||||
|
||||
fprintf(f, "%u ", gid);
|
||||
gr = getgrgid (gid);
|
||||
if (gr == NULL)
|
||||
fprintf(f, "(group unknown)\n");
|
||||
else
|
||||
fprintf(f, "(group %s)\n", 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
|
||||
}
|
||||
|
||||
static void print_super_flags(struct ext2_super_block * s, FILE *f)
|
||||
{
|
||||
int flags_found = 0;
|
||||
|
||||
if (s->s_flags == 0)
|
||||
return;
|
||||
|
||||
fputs("Filesystem flags: ", f);
|
||||
if (s->s_flags & EXT2_FLAGS_SIGNED_HASH) {
|
||||
fputs("signed_directory_hash ", f);
|
||||
flags_found++;
|
||||
}
|
||||
if (s->s_flags & EXT2_FLAGS_UNSIGNED_HASH) {
|
||||
fputs("unsigned_directory_hash ", f);
|
||||
flags_found++;
|
||||
}
|
||||
if (s->s_flags & EXT2_FLAGS_TEST_FILESYS) {
|
||||
fputs("test_filesystem ", f);
|
||||
flags_found++;
|
||||
}
|
||||
if (flags_found)
|
||||
fputs("\n", f);
|
||||
else
|
||||
fputs("(none)\n", f);
|
||||
}
|
||||
|
||||
static __u64 e2p_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_blocks_count_hi << 32 : 0);
|
||||
}
|
||||
|
||||
static __u64 e2p_r_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_r_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_r_blocks_count_hi << 32 : 0);
|
||||
}
|
||||
|
||||
static __u64 e2p_free_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_free_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_free_blocks_hi << 32 : 0);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
static const char *checksum_type(__u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case EXT2_CRC32C_CHKSUM:
|
||||
return "crc32c";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *quota_prefix[MAXQUOTAS] = {
|
||||
[USRQUOTA] = "User quota inode:",
|
||||
[GRPQUOTA] = "Group quota inode:",
|
||||
[PRJQUOTA] = "Project quota inode:",
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert type of quota to written representation
|
||||
*/
|
||||
static const char *quota_type2prefix(enum quota_type qtype)
|
||||
{
|
||||
return quota_prefix[qtype];
|
||||
}
|
||||
|
||||
void list_super2(struct ext2_super_block * sb, FILE *f)
|
||||
{
|
||||
int inode_blocks_per_group;
|
||||
char *str;
|
||||
time_t tm;
|
||||
enum quota_type qtype;
|
||||
|
||||
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])
|
||||
fprintf(f, "Filesystem volume name: %.*s\n",
|
||||
EXT2_LEN_STR(sb->s_volume_name));
|
||||
else
|
||||
fprintf(f, "Filesystem volume name: <none>\n");
|
||||
if (sb->s_last_mounted[0])
|
||||
fprintf(f, "Last mounted on: %.*s\n",
|
||||
EXT2_LEN_STR(sb->s_last_mounted));
|
||||
else
|
||||
fprintf(f, "Last mounted on: <not available>\n");
|
||||
fprintf(f, "Filesystem UUID: %s\n", e2p_uuid2str(sb->s_uuid));
|
||||
fprintf(f, "Filesystem magic number: 0x%04X\n", sb->s_magic);
|
||||
fprintf(f, "Filesystem revision #: %d", 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_super_flags(sb, f);
|
||||
print_mntopts(sb, f);
|
||||
if (sb->s_mount_opts[0])
|
||||
fprintf(f, "Mount options: %.*s\n",
|
||||
EXT2_LEN_STR(sb->s_mount_opts));
|
||||
fprintf(f, "Filesystem state: ");
|
||||
print_fs_state (f, sb->s_state);
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "Errors behavior: ");
|
||||
print_fs_errors(f, sb->s_errors);
|
||||
fprintf(f, "\n");
|
||||
str = e2p_os2string(sb->s_creator_os);
|
||||
fprintf(f, "Filesystem OS type: %s\n", str);
|
||||
free(str);
|
||||
fprintf(f, "Inode count: %u\n", sb->s_inodes_count);
|
||||
fprintf(f, "Block count: %llu\n",
|
||||
(unsigned long long) e2p_blocks_count(sb));
|
||||
fprintf(f, "Reserved block count: %llu\n",
|
||||
(unsigned long long) e2p_r_blocks_count(sb));
|
||||
if (sb->s_overhead_clusters)
|
||||
fprintf(f, "Overhead clusters: %u\n",
|
||||
sb->s_overhead_clusters);
|
||||
fprintf(f, "Free blocks: %llu\n",
|
||||
(unsigned long long) e2p_free_blocks_count(sb));
|
||||
fprintf(f, "Free inodes: %u\n", sb->s_free_inodes_count);
|
||||
fprintf(f, "First block: %u\n", sb->s_first_data_block);
|
||||
fprintf(f, "Block size: %u\n", EXT2_BLOCK_SIZE(sb));
|
||||
if (ext2fs_has_feature_bigalloc(sb))
|
||||
fprintf(f, "Cluster size: %u\n",
|
||||
EXT2_CLUSTER_SIZE(sb));
|
||||
else
|
||||
fprintf(f, "Fragment size: %u\n",
|
||||
EXT2_CLUSTER_SIZE(sb));
|
||||
if (ext2fs_has_feature_64bit(sb))
|
||||
fprintf(f, "Group descriptor size: %u\n", sb->s_desc_size);
|
||||
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", sb->s_blocks_per_group);
|
||||
if (ext2fs_has_feature_bigalloc(sb))
|
||||
fprintf(f, "Clusters per group: %u\n",
|
||||
sb->s_clusters_per_group);
|
||||
else
|
||||
fprintf(f, "Fragments per group: %u\n",
|
||||
sb->s_clusters_per_group);
|
||||
fprintf(f, "Inodes per group: %u\n", sb->s_inodes_per_group);
|
||||
fprintf(f, "Inode blocks per group: %u\n", inode_blocks_per_group);
|
||||
if (sb->s_raid_stride)
|
||||
fprintf(f, "RAID stride: %u\n",
|
||||
sb->s_raid_stride);
|
||||
if (sb->s_raid_stripe_width)
|
||||
fprintf(f, "RAID stripe width: %u\n",
|
||||
sb->s_raid_stripe_width);
|
||||
if (sb->s_first_meta_bg)
|
||||
fprintf(f, "First meta block group: %u\n",
|
||||
sb->s_first_meta_bg);
|
||||
if (sb->s_log_groups_per_flex)
|
||||
fprintf(f, "Flex block group size: %u\n",
|
||||
1U << sb->s_log_groups_per_flex);
|
||||
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", ctime(&tm));
|
||||
fprintf(f, "Mount count: %u\n", sb->s_mnt_count);
|
||||
fprintf(f, "Maximum mount count: %d\n", sb->s_max_mnt_count);
|
||||
tm = sb->s_lastcheck;
|
||||
fprintf(f, "Last checked: %s", ctime(&tm));
|
||||
fprintf(f, "Check interval: %u (%s)\n", 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));
|
||||
}
|
||||
#define POW2(x) ((__u64) 1 << (x))
|
||||
if (sb->s_kbytes_written) {
|
||||
fprintf(f, "Lifetime writes: ");
|
||||
if (sb->s_kbytes_written < POW2(13))
|
||||
fprintf(f, "%llu kB\n",
|
||||
(unsigned long long) sb->s_kbytes_written);
|
||||
else if (sb->s_kbytes_written < POW2(23))
|
||||
fprintf(f, "%llu MB\n", (unsigned long long)
|
||||
(sb->s_kbytes_written + POW2(9)) >> 10);
|
||||
else if (sb->s_kbytes_written < POW2(33))
|
||||
fprintf(f, "%llu GB\n", (unsigned long long)
|
||||
(sb->s_kbytes_written + POW2(19)) >> 20);
|
||||
else if (sb->s_kbytes_written < POW2(43))
|
||||
fprintf(f, "%llu TB\n", (unsigned long long)
|
||||
(sb->s_kbytes_written + POW2(29)) >> 30);
|
||||
else
|
||||
fprintf(f, "%llu PB\n", (unsigned long long)
|
||||
(sb->s_kbytes_written + POW2(39)) >> 40);
|
||||
}
|
||||
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", sb->s_first_ino);
|
||||
fprintf(f, "Inode size: %d\n", sb->s_inode_size);
|
||||
if (sb->s_min_extra_isize)
|
||||
fprintf(f, "Required extra isize: %d\n",
|
||||
sb->s_min_extra_isize);
|
||||
if (sb->s_want_extra_isize)
|
||||
fprintf(f, "Desired extra isize: %d\n",
|
||||
sb->s_want_extra_isize);
|
||||
}
|
||||
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 (ext2fs_has_feature_dir_index(sb) ||
|
||||
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: ");
|
||||
switch (sb->s_jnl_backup_type) {
|
||||
case 1:
|
||||
fprintf(f, "inode blocks\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(f, "type %u\n", sb->s_jnl_backup_type);
|
||||
}
|
||||
}
|
||||
if (sb->s_backup_bgs[0] || sb->s_backup_bgs[1]) {
|
||||
fprintf(f, "Backup block groups: ");
|
||||
if (sb->s_backup_bgs[0])
|
||||
fprintf(f, "%u ", sb->s_backup_bgs[0]);
|
||||
if (sb->s_backup_bgs[1])
|
||||
fprintf(f, "%u ", sb->s_backup_bgs[1]);
|
||||
fputc('\n', f);
|
||||
}
|
||||
if (sb->s_snapshot_inum) {
|
||||
fprintf(f, "Snapshot inode: %u\n",
|
||||
sb->s_snapshot_inum);
|
||||
fprintf(f, "Snapshot ID: %u\n",
|
||||
sb->s_snapshot_id);
|
||||
fprintf(f, "Snapshot reserved blocks: %llu\n",
|
||||
(unsigned long long) sb->s_snapshot_r_blocks_count);
|
||||
}
|
||||
if (sb->s_snapshot_list)
|
||||
fprintf(f, "Snapshot list head: %u\n",
|
||||
sb->s_snapshot_list);
|
||||
if (sb->s_error_count)
|
||||
fprintf(f, "FS Error count: %u\n",
|
||||
sb->s_error_count);
|
||||
if (sb->s_first_error_time) {
|
||||
tm = sb->s_first_error_time;
|
||||
fprintf(f, "First error time: %s", ctime(&tm));
|
||||
fprintf(f, "First error function: %.*s\n",
|
||||
EXT2_LEN_STR(sb->s_first_error_func));
|
||||
fprintf(f, "First error line #: %u\n",
|
||||
sb->s_first_error_line);
|
||||
if (sb->s_first_error_ino)
|
||||
fprintf(f, "First error inode #: %u\n",
|
||||
sb->s_first_error_ino);
|
||||
if (sb->s_first_error_block)
|
||||
fprintf(f, "First error block #: %llu\n",
|
||||
(unsigned long long) sb->s_first_error_block);
|
||||
if (sb->s_first_error_errcode)
|
||||
fprintf(f, "First error err: %s\n",
|
||||
e2p_errcode2str(sb->s_first_error_errcode));
|
||||
}
|
||||
if (sb->s_last_error_time) {
|
||||
tm = sb->s_last_error_time;
|
||||
fprintf(f, "Last error time: %s", ctime(&tm));
|
||||
fprintf(f, "Last error function: %.*s\n",
|
||||
EXT2_LEN_STR(sb->s_last_error_func));
|
||||
fprintf(f, "Last error line #: %u\n",
|
||||
sb->s_last_error_line);
|
||||
if (sb->s_last_error_ino)
|
||||
fprintf(f, "Last error inode #: %u\n",
|
||||
sb->s_last_error_ino);
|
||||
if (sb->s_last_error_block)
|
||||
fprintf(f, "Last error block #: %llu\n",
|
||||
(unsigned long long) sb->s_last_error_block);
|
||||
if (sb->s_last_error_errcode)
|
||||
fprintf(f, "Last error err: %s\n",
|
||||
e2p_errcode2str(sb->s_last_error_errcode));
|
||||
}
|
||||
if (ext2fs_has_feature_mmp(sb)) {
|
||||
fprintf(f, "MMP block number: %llu\n",
|
||||
(unsigned long long) sb->s_mmp_block);
|
||||
fprintf(f, "MMP update interval: %u\n",
|
||||
sb->s_mmp_update_interval);
|
||||
}
|
||||
for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
|
||||
if (*quota_sb_inump(sb, qtype) != 0)
|
||||
fprintf(f, "%-26s%u\n",
|
||||
quota_type2prefix(qtype),
|
||||
*quota_sb_inump(sb, qtype));
|
||||
}
|
||||
|
||||
if (ext2fs_has_feature_metadata_csum(sb)) {
|
||||
fprintf(f, "Checksum type: %s\n",
|
||||
checksum_type(sb->s_checksum_type));
|
||||
fprintf(f, "Checksum: 0x%08x\n",
|
||||
sb->s_checksum);
|
||||
}
|
||||
if (!e2p_is_null_uuid(sb->s_encrypt_pw_salt))
|
||||
fprintf(f, "Encryption PW Salt: %s\n",
|
||||
e2p_uuid2str(sb->s_encrypt_pw_salt));
|
||||
|
||||
if (ext2fs_has_feature_csum_seed(sb))
|
||||
fprintf(f, "Checksum seed: 0x%08x\n",
|
||||
sb->s_checksum_seed);
|
||||
if (ext2fs_has_feature_casefold(sb))
|
||||
fprintf(f, "Character encoding: %s\n",
|
||||
e2p_encoding2str(sb->s_encoding));
|
||||
}
|
||||
|
||||
void list_super (struct ext2_super_block * s)
|
||||
{
|
||||
list_super2(s, stdout);
|
||||
}
|
||||
|
||||
150
jni/e2fsprogs/lib/e2p/mntopts.c
Executable file
150
jni/e2fsprogs/lib/e2p/mntopts.c
Executable file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* mountopts.c --- convert between default mount options and strings
|
||||
*
|
||||
* Copyright (C) 2002 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
struct mntopt {
|
||||
unsigned int mask;
|
||||
const char *string;
|
||||
};
|
||||
|
||||
static 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" },
|
||||
{ EXT4_DEFM_NOBARRIER, "nobarrier" },
|
||||
{ EXT4_DEFM_BLOCK_VALIDITY, "block_validity" },
|
||||
{ EXT4_DEFM_DISCARD, "discard"},
|
||||
{ EXT4_DEFM_NODELALLOC, "nodelalloc"},
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const char *e2p_mntopt2string(unsigned int mask)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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_", 7))
|
||||
return 1;
|
||||
|
||||
if (string[8] == 0)
|
||||
return 1;
|
||||
num = strtol(string+8, &eptr, 10);
|
||||
if (num > 31 || 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;
|
||||
int rc = 0;
|
||||
|
||||
buf = malloc(strlen(str)+1);
|
||||
if (!buf)
|
||||
return 1;
|
||||
strcpy(buf, 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++;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
cp++;
|
||||
break;
|
||||
}
|
||||
if (e2p_string2mntopt(cp, &mask)) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
if (ok && !(ok & mask)) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
if (mask & EXT3_DEFM_JMODE)
|
||||
*mntopts &= ~EXT3_DEFM_JMODE;
|
||||
if (neg)
|
||||
*mntopts &= ~mask;
|
||||
else
|
||||
*mntopts |= mask;
|
||||
cp = next ? next+1 : 0;
|
||||
}
|
||||
free(buf);
|
||||
return rc;
|
||||
}
|
||||
79
jni/e2fsprogs/lib/e2p/ostype.c
Executable file
79
jni/e2fsprogs/lib/e2p/ostype.c
Executable file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* getostype.c - Get the Filesystem OS type
|
||||
*
|
||||
* Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "e2p.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char *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 >= 0 && os_type <= EXT2_OS_LITES)
|
||||
os = os_tab[os_type];
|
||||
else
|
||||
os = "(unknown os)";
|
||||
|
||||
ret = malloc(strlen(os)+1);
|
||||
if (ret)
|
||||
strcpy(ret, os);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an os_type to a string
|
||||
*/
|
||||
int e2p_string2os(char *str)
|
||||
{
|
||||
const char **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);
|
||||
free(s);
|
||||
if (i != os) {
|
||||
fprintf(stderr, "Failure!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
91
jni/e2fsprogs/lib/e2p/parse_num.c
Executable file
91
jni/e2fsprogs/lib/e2p/parse_num.c
Executable file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* parse_num.c - Parse the number of blocks
|
||||
*
|
||||
* Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "e2p.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned long long parse_num_blocks2(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;
|
||||
/* fallthrough */
|
||||
case 'G': case 'g':
|
||||
num <<= 10;
|
||||
/* fallthrough */
|
||||
case 'M': case 'm':
|
||||
num <<= 10;
|
||||
/* fallthrough */
|
||||
case 'K': case 'k':
|
||||
if (log_block_size < 0)
|
||||
num <<= 10;
|
||||
else
|
||||
num >>= log_block_size;
|
||||
break;
|
||||
case 's':
|
||||
if (log_block_size < 0)
|
||||
num <<= 9;
|
||||
else
|
||||
num >>= (1+log_block_size);
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
unsigned long parse_num_blocks(const char *arg, int log_block_size)
|
||||
{
|
||||
return parse_num_blocks2(arg, log_block_size);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
unsigned long num;
|
||||
int log_block_size = 0;
|
||||
|
||||
if (argc != 2 && argc != 3) {
|
||||
fprintf(stderr, "Usage: %s arg [log_block_size]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
char *p;
|
||||
|
||||
log_block_size = strtol(argv[2], &p, 0);
|
||||
if (*p) {
|
||||
fprintf(stderr, "Bad log_block_size: %s\n", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
num = parse_num_blocks(argv[1], log_block_size);
|
||||
|
||||
printf("Parsed number: %lu\n", num);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
40
jni/e2fsprogs/lib/e2p/pe.c
Executable file
40
jni/e2fsprogs/lib/e2p/pe.c
Executable file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* pe.c - Print a second extended filesystem errors behavior
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 94/01/09 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
void print_fs_errors (FILE * f, unsigned short errors)
|
||||
{
|
||||
switch (errors)
|
||||
{
|
||||
case EXT2_ERRORS_CONTINUE:
|
||||
fprintf (f, "Continue");
|
||||
break;
|
||||
case EXT2_ERRORS_RO:
|
||||
fprintf (f, "Remount read-only");
|
||||
break;
|
||||
case EXT2_ERRORS_PANIC:
|
||||
fprintf (f, "Panic");
|
||||
break;
|
||||
default:
|
||||
fprintf (f, "Unknown (continue)");
|
||||
}
|
||||
}
|
||||
67
jni/e2fsprogs/lib/e2p/percent.c
Executable file
67
jni/e2fsprogs/lib/e2p/percent.c
Executable file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* percent.c - Take percentage of a number
|
||||
*
|
||||
* Copyright (C) 2006 Theodore Ts'o <tytso@mit.edu>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "e2p.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* We work really hard to calculate this accurately, while avoiding
|
||||
* an overflow. "Is there a hyphen in anal-retentive?" :-)
|
||||
*/
|
||||
unsigned int e2p_percent(int percent, unsigned int base)
|
||||
{
|
||||
unsigned int mask = ~((1 << (sizeof(unsigned int) - 1) * 8) - 1);
|
||||
|
||||
if (!percent)
|
||||
return 0;
|
||||
if (100 % percent == 0)
|
||||
return base / (100 / percent);
|
||||
if (mask & base)
|
||||
return (base / 100) * percent;
|
||||
return base * percent / 100;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
unsigned int base;
|
||||
int percent;
|
||||
char *p;
|
||||
int log_block_size = 0;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s percent base\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
percent = strtoul(argv[1], &p, 0);
|
||||
if (p[0] && p[1]) {
|
||||
fprintf(stderr, "Bad percent: %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
base = strtoul(argv[2], &p, 0);
|
||||
if (p[0] && p[1]) {
|
||||
fprintf(stderr, "Bad base: %s\n", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("%d percent of %u is %u.\n", percent, base,
|
||||
e2p_percent(percent, base));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
79
jni/e2fsprogs/lib/e2p/pf.c
Executable file
79
jni/e2fsprogs/lib/e2p/pf.c
Executable file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* pf.c - Print file attributes on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
struct flags_name {
|
||||
unsigned long flag;
|
||||
const char *short_name;
|
||||
const char *long_name;
|
||||
};
|
||||
|
||||
static 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" },
|
||||
{ EXT4_ENCRYPT_FL, "E", "Encrypted" },
|
||||
{ EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" },
|
||||
{ EXT2_INDEX_FL, "I", "Indexed_directory" },
|
||||
{ EXT2_NOTAIL_FL, "t", "No_Tailmerging" },
|
||||
{ EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
|
||||
{ EXT4_EXTENTS_FL, "e", "Extents" },
|
||||
{ FS_NOCOW_FL, "C", "No_COW" },
|
||||
{ FS_DAX_FL, "x", "DAX" },
|
||||
{ EXT4_CASEFOLD_FL, "F", "Casefold" },
|
||||
{ EXT4_INLINE_DATA_FL, "N", "Inline_Data" },
|
||||
{ EXT4_PROJINHERIT_FL, "P", "Project_Hierarchy" },
|
||||
{ EXT4_VERITY_FL, "V", "Verity" },
|
||||
{ EXT2_NOCOMPR_FL, "m", "Dont_Compress" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
void print_flags (FILE * f, unsigned long flags, unsigned options)
|
||||
{
|
||||
int long_opt = (options & PFOPT_LONG);
|
||||
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);
|
||||
}
|
||||
32
jni/e2fsprogs/lib/e2p/ps.c
Executable file
32
jni/e2fsprogs/lib/e2p/ps.c
Executable file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ps.c - Print filesystem state
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/12/22 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
void print_fs_state (FILE * f, unsigned short state)
|
||||
{
|
||||
if (state & EXT2_VALID_FS)
|
||||
fprintf (f, " clean");
|
||||
else
|
||||
fprintf (f, " not clean");
|
||||
if (state & EXT2_ERROR_FS)
|
||||
fprintf (f, " with errors");
|
||||
}
|
||||
77
jni/e2fsprogs/lib/e2p/setflags.c
Executable file
77
jni/e2fsprogs/lib/e2p/setflags.c
Executable file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* setflags.c - Set a file flags on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
/*
|
||||
* Deal with lame glibc's that define this function without actually
|
||||
* implementing it. Can you say "attractive nuisance", boys and girls?
|
||||
* I knew you could!
|
||||
*/
|
||||
#ifdef __linux__
|
||||
#undef HAVE_CHFLAGS
|
||||
#endif
|
||||
|
||||
int setflags (int fd, unsigned long flags)
|
||||
{
|
||||
#if HAVE_CHFLAGS
|
||||
unsigned long bsd_flags = 0;
|
||||
|
||||
#ifdef UF_IMMUTABLE
|
||||
if (flags & EXT2_IMMUTABLE_FL)
|
||||
bsd_flags |= UF_IMMUTABLE;
|
||||
#endif
|
||||
#ifdef UF_APPEND
|
||||
if (flags & EXT2_APPEND_FL)
|
||||
bsd_flags |= UF_APPEND;
|
||||
#endif
|
||||
#ifdef UF_NODUMP
|
||||
if (flags & EXT2_NODUMP_FL)
|
||||
bsd_flags |= UF_NODUMP;
|
||||
#endif
|
||||
|
||||
return fchflags (fd, bsd_flags);
|
||||
#else /* ! HAVE_CHFLAGS */
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
struct stat buf;
|
||||
int f;
|
||||
|
||||
if (!fstat(fd, &buf) &&
|
||||
!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
f = (int) flags;
|
||||
|
||||
return ioctl(fd, EXT2_IOC_SETFLAGS, &f);
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#endif /* HAVE_EXT2_IOCTLS */
|
||||
#endif /* HAVE_CHFLAGS */
|
||||
}
|
||||
40
jni/e2fsprogs/lib/e2p/setversion.c
Executable file
40
jni/e2fsprogs/lib/e2p/setversion.c
Executable file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* setversion.c - Set a file version on an ext2 file system
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
|
||||
* Laboratoire MASI, Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 93/10/30 - Creation
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "e2p.h"
|
||||
|
||||
int setversion (int fd, unsigned long version)
|
||||
{
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
int ver;
|
||||
|
||||
ver = (int) version;
|
||||
return ioctl (fd, EXT2_IOC_SETVERSION, &ver);
|
||||
#else /* ! HAVE_EXT2_IOCTLS */
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
#endif /* ! HAVE_EXT2_IOCTLS */
|
||||
}
|
||||
85
jni/e2fsprogs/lib/e2p/uuid.c
Executable file
85
jni/e2fsprogs/lib/e2p/uuid.c
Executable file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* uuid.c -- utility routines for manipulating UUID's.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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;
|
||||
}
|
||||
|
||||
105
jni/e2fsprogs/lib/et/com_err.c
Executable file
105
jni/e2fsprogs/lib/et/com_err.c
Executable file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 1987, 1988 by MIT Student Information Processing Board.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose is hereby granted, provided that
|
||||
* the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. M.I.T. and the
|
||||
* M.I.T. S.I.P.B. make no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without
|
||||
* express or implied warranty.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "com_err.h"
|
||||
#include "error_table.h"
|
||||
#include "internal.h"
|
||||
|
||||
static void
|
||||
default_com_err_proc (const char *whoami, errcode_t code, const
|
||||
char *fmt, va_list args)
|
||||
COM_ERR_ATTR((format(printf, 3, 0)));
|
||||
|
||||
static void
|
||||
default_com_err_proc (const char *whoami, errcode_t code, const
|
||||
char *fmt, va_list args)
|
||||
{
|
||||
int do_cr = 1, fd = fileno(stderr);
|
||||
|
||||
if (whoami) {
|
||||
fputs(whoami, stderr);
|
||||
fputs(": ", stderr);
|
||||
}
|
||||
if (code) {
|
||||
fputs(error_message(code), stderr);
|
||||
fputs(" ", stderr);
|
||||
}
|
||||
if (fmt) {
|
||||
vfprintf (stderr, fmt, args);
|
||||
}
|
||||
if (!isatty(fd))
|
||||
do_cr = 0;
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
else {
|
||||
struct termios t;
|
||||
|
||||
if ((tcgetattr(fd, &t)) == 0 &&
|
||||
(t.c_oflag & OPOST) && (t.c_oflag & ONLCR))
|
||||
do_cr = 0;
|
||||
}
|
||||
#endif
|
||||
if (do_cr)
|
||||
fputc('\r', stderr);
|
||||
fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
typedef void (*errf) (const char *, errcode_t, const char *, va_list)
|
||||
COM_ERR_ATTR((format(printf, 3, 0)));
|
||||
|
||||
errf com_err_hook = default_com_err_proc;
|
||||
|
||||
void com_err_va (const char *whoami, errcode_t code, const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
(*com_err_hook) (whoami, code, fmt, args);
|
||||
}
|
||||
|
||||
void com_err (const char *whoami,
|
||||
errcode_t code,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list pvar;
|
||||
|
||||
if (!com_err_hook)
|
||||
com_err_hook = default_com_err_proc;
|
||||
va_start(pvar, fmt);
|
||||
com_err_va (whoami, code, fmt, pvar);
|
||||
va_end(pvar);
|
||||
}
|
||||
|
||||
errf set_com_err_hook(errf new_proc)
|
||||
{
|
||||
errf x = com_err_hook;
|
||||
|
||||
if (new_proc)
|
||||
com_err_hook = new_proc;
|
||||
else
|
||||
com_err_hook = default_com_err_proc;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
errf reset_com_err_hook(void) {
|
||||
errf x = com_err_hook;
|
||||
com_err_hook = default_com_err_proc;
|
||||
return x;
|
||||
}
|
||||
120
jni/e2fsprogs/lib/et/com_right.c
Executable file
120
jni/e2fsprogs/lib/et/com_right.c
Executable file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* com_right.c -- provide Heimdall / Kerberos4kth com_err interfaces
|
||||
* for backwards compatibility
|
||||
*
|
||||
* Copyright (c) 2003 by Theodore Ts'o
|
||||
*
|
||||
* Taken from lib/com_err/error.c from Kerberos4kth distribution.
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 2001 Kungliga Tekniska H<>gskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 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. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "com_err.h"
|
||||
#include "error_table.h"
|
||||
|
||||
const char *
|
||||
com_right(struct et_list *list, long code)
|
||||
{
|
||||
struct et_list *p;
|
||||
for (p = list; p; p = p->next) {
|
||||
if (code >= p->table->base && code < p->table->base + p->table->n_msgs)
|
||||
return p->table->msgs[code - p->table->base];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
com_right_r(struct et_list *list, long code, char *str, size_t len)
|
||||
{
|
||||
struct et_list *p;
|
||||
for (p = list; p; p = p->next) {
|
||||
if ((code >= p->table->base) &&
|
||||
(code < p->table->base + p->table->n_msgs)) {
|
||||
strncpy(str, p->table->msgs[code - p->table->base], len);
|
||||
str[len-1] = '\0';
|
||||
return str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct foobar {
|
||||
struct et_list etl;
|
||||
struct error_table tab;
|
||||
};
|
||||
|
||||
/*
|
||||
* We provide this routine for compatibility with Heimdall generated
|
||||
* foo_err.c files, but we don't use this ourselves for foo_err.c
|
||||
* files generated by our compile_et. This is so our foo_err.c
|
||||
* files can be used with older com_err libraries without running
|
||||
* afoul of dependencies.
|
||||
*/
|
||||
void
|
||||
initialize_error_table_r(struct et_list **list,
|
||||
const char **messages,
|
||||
int num_errors,
|
||||
long base)
|
||||
{
|
||||
struct et_list *et, **end;
|
||||
struct error_table *tab;
|
||||
struct foobar *f;
|
||||
|
||||
for (end = list, et = *list; et; end = &et->next, et = et->next)
|
||||
if (et->table->msgs == messages)
|
||||
return;
|
||||
f = malloc(sizeof(*f));
|
||||
if (f == NULL)
|
||||
return;
|
||||
et = &f->etl;
|
||||
et->table = tab = &f->tab;
|
||||
tab->msgs = messages;
|
||||
tab->n_msgs = num_errors;
|
||||
tab->base = base;
|
||||
et->next = NULL;
|
||||
*end = et;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_error_table(struct et_list *et)
|
||||
{
|
||||
while(et){
|
||||
struct et_list *p = et;
|
||||
et = et->next;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
355
jni/e2fsprogs/lib/et/error_message.c
Executable file
355
jni/e2fsprogs/lib/et/error_message.c
Executable file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* $Header$
|
||||
* $Source$
|
||||
* $Locker$
|
||||
*
|
||||
* Copyright 1987 by the Student Information Processing Board
|
||||
* of the Massachusetts Institute of Technology
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose is hereby granted, provided that
|
||||
* the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. M.I.T. and the
|
||||
* M.I.T. S.I.P.B. make no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without
|
||||
* express or implied warranty.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#else
|
||||
#define PR_GET_DUMPABLE 3
|
||||
#endif
|
||||
#if (!defined(HAVE_PRCTL) && defined(linux))
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
#ifdef HAVE_SEMAPHORE_H
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_FCNTL
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include "com_err.h"
|
||||
#include "error_table.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef TLS
|
||||
#define THREAD_LOCAL static TLS
|
||||
#else
|
||||
#define THREAD_LOCAL static
|
||||
#endif
|
||||
|
||||
THREAD_LOCAL char buffer[25];
|
||||
|
||||
struct et_list * _et_list = (struct et_list *) NULL;
|
||||
struct et_list * _et_dynamic_list = (struct et_list *) NULL;
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define COMERR_ATTR(x) __attribute__(x)
|
||||
#else
|
||||
#define COMERR_ATTR(x)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SEM_INIT
|
||||
static sem_t _et_lock;
|
||||
static int _et_lock_initialized;
|
||||
|
||||
static void COMERR_ATTR((constructor)) setup_et_lock(void)
|
||||
{
|
||||
sem_init(&_et_lock, 0, 1);
|
||||
_et_lock_initialized = 1;
|
||||
}
|
||||
|
||||
static void COMERR_ATTR((destructor)) fini_et_lock(void)
|
||||
{
|
||||
sem_destroy(&_et_lock);
|
||||
_et_lock_initialized = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int et_list_lock(void)
|
||||
{
|
||||
#ifdef HAVE_SEM_INIT
|
||||
if (!_et_lock_initialized)
|
||||
setup_et_lock();
|
||||
return sem_wait(&_et_lock);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int et_list_unlock(void)
|
||||
{
|
||||
#ifdef HAVE_SEM_INIT
|
||||
if (_et_lock_initialized)
|
||||
return sem_post(&_et_lock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef char *(*gettextf) (const char *);
|
||||
|
||||
static gettextf com_err_gettext = NULL;
|
||||
|
||||
gettextf set_com_err_gettext(gettextf new_proc)
|
||||
{
|
||||
gettextf x = com_err_gettext;
|
||||
|
||||
com_err_gettext = new_proc;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef __GNU__
|
||||
#define SYS_ERR_BASE 0x40000000
|
||||
#else
|
||||
#define SYS_ERR_BASE 0
|
||||
#endif
|
||||
|
||||
const char * error_message (errcode_t code)
|
||||
{
|
||||
int offset;
|
||||
struct et_list *et;
|
||||
errcode_t table_num;
|
||||
int started = 0;
|
||||
char *cp;
|
||||
|
||||
offset = (int) (code & ((1<<ERRCODE_RANGE)-1));
|
||||
table_num = code - offset;
|
||||
if (table_num == SYS_ERR_BASE) {
|
||||
#ifdef HAS_SYS_ERRLIST
|
||||
if (code < sys_nerr)
|
||||
return(sys_errlist[code]);
|
||||
else
|
||||
goto oops;
|
||||
#else
|
||||
cp = strerror(code);
|
||||
if (cp)
|
||||
return(cp);
|
||||
else
|
||||
goto oops;
|
||||
#endif
|
||||
}
|
||||
et_list_lock();
|
||||
for (et = _et_list; et; et = et->next) {
|
||||
if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) {
|
||||
/* This is the right table */
|
||||
if (et->table->n_msgs <= offset) {
|
||||
break;
|
||||
} else {
|
||||
const char *msg = et->table->msgs[offset];
|
||||
et_list_unlock();
|
||||
if (com_err_gettext)
|
||||
return (*com_err_gettext)(msg);
|
||||
else
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (et = _et_dynamic_list; et; et = et->next) {
|
||||
if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) {
|
||||
/* This is the right table */
|
||||
if (et->table->n_msgs <= offset) {
|
||||
break;
|
||||
} else {
|
||||
const char *msg = et->table->msgs[offset];
|
||||
et_list_unlock();
|
||||
if (com_err_gettext)
|
||||
return (*com_err_gettext)(msg);
|
||||
else
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
et_list_unlock();
|
||||
oops:
|
||||
strcpy (buffer, "Unknown code ");
|
||||
if (table_num) {
|
||||
strcat (buffer, error_table_name (table_num));
|
||||
strcat (buffer, " ");
|
||||
}
|
||||
for (cp = buffer; *cp; cp++)
|
||||
;
|
||||
if (offset >= 100) {
|
||||
*cp++ = '0' + offset / 100;
|
||||
offset %= 100;
|
||||
started++;
|
||||
}
|
||||
if (started || offset >= 10) {
|
||||
*cp++ = '0' + offset / 10;
|
||||
offset %= 10;
|
||||
}
|
||||
*cp++ = '0' + offset;
|
||||
*cp = '\0';
|
||||
return(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will only return a value if the we are not running as
|
||||
* a privileged process.
|
||||
*/
|
||||
static char *safe_getenv(const char *arg)
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
if ((getuid() != geteuid()) || (getgid() != getegid()))
|
||||
return NULL;
|
||||
#endif
|
||||
#if HAVE_PRCTL
|
||||
if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
|
||||
return NULL;
|
||||
#else
|
||||
#if (defined(linux) && defined(SYS_prctl))
|
||||
if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
|
||||
return NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SECURE_GETENV)
|
||||
return secure_getenv(arg);
|
||||
#elif defined(HAVE___SECURE_GETENV)
|
||||
return __secure_getenv(arg);
|
||||
#else
|
||||
return getenv(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DEBUG_INIT 0x8000
|
||||
#define DEBUG_ADDREMOVE 0x0001
|
||||
|
||||
static int debug_mask = 0;
|
||||
static FILE *debug_f = 0;
|
||||
|
||||
static void init_debug(void)
|
||||
{
|
||||
char *dstr, *fn, *tmp;
|
||||
|
||||
if (debug_mask & DEBUG_INIT)
|
||||
return;
|
||||
|
||||
dstr = getenv("COMERR_DEBUG");
|
||||
if (dstr) {
|
||||
debug_mask = strtoul(dstr, &tmp, 0);
|
||||
if (*tmp || errno)
|
||||
debug_mask = 0;
|
||||
}
|
||||
|
||||
debug_mask |= DEBUG_INIT;
|
||||
if (debug_mask == DEBUG_INIT)
|
||||
return;
|
||||
|
||||
fn = safe_getenv("COMERR_DEBUG_FILE");
|
||||
if (fn)
|
||||
debug_f = fopen(fn, "a");
|
||||
if (!debug_f)
|
||||
debug_f = fopen("/dev/tty", "a");
|
||||
if (debug_f) {
|
||||
#ifdef HAVE_FCNTL
|
||||
int fd = fileno(debug_f);
|
||||
|
||||
if (fd >= 0) {
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
|
||||
if (flags >= 0)
|
||||
flags = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
||||
if (flags < 0) {
|
||||
fprintf(debug_f, "Couldn't set FD_CLOEXEC "
|
||||
"on debug FILE: %s\n", strerror(errno));
|
||||
fclose(debug_f);
|
||||
debug_f = NULL;
|
||||
debug_mask = DEBUG_INIT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
debug_mask = DEBUG_INIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* New interface provided by krb5's com_err library
|
||||
*/
|
||||
errcode_t add_error_table(const struct error_table * et)
|
||||
{
|
||||
struct et_list *el;
|
||||
|
||||
if (!(el = (struct et_list *) malloc(sizeof(struct et_list))))
|
||||
return ENOMEM;
|
||||
|
||||
if (et_list_lock() != 0) {
|
||||
free(el);
|
||||
return errno;
|
||||
}
|
||||
|
||||
el->table = et;
|
||||
el->next = _et_dynamic_list;
|
||||
_et_dynamic_list = el;
|
||||
|
||||
init_debug();
|
||||
if (debug_mask & DEBUG_ADDREMOVE)
|
||||
fprintf(debug_f, "add_error_table: %s (0x%p)\n",
|
||||
error_table_name(et->base),
|
||||
(const void *) et);
|
||||
|
||||
et_list_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* New interface provided by krb5's com_err library
|
||||
*/
|
||||
errcode_t remove_error_table(const struct error_table * et)
|
||||
{
|
||||
struct et_list *el;
|
||||
struct et_list *el2 = 0;
|
||||
|
||||
if (et_list_lock() != 0)
|
||||
return ENOENT;
|
||||
|
||||
el = _et_dynamic_list;
|
||||
init_debug();
|
||||
while (el) {
|
||||
if (el->table->base == et->base) {
|
||||
if (el2) /* Not the beginning of the list */
|
||||
el2->next = el->next;
|
||||
else
|
||||
_et_dynamic_list = el->next;
|
||||
(void) free(el);
|
||||
if (debug_mask & DEBUG_ADDREMOVE)
|
||||
fprintf(debug_f,
|
||||
"remove_error_table: %s (0x%p)\n",
|
||||
error_table_name(et->base),
|
||||
(const void *) et);
|
||||
et_list_unlock();
|
||||
return 0;
|
||||
}
|
||||
el2 = el;
|
||||
el = el->next;
|
||||
}
|
||||
if (debug_mask & DEBUG_ADDREMOVE)
|
||||
fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n",
|
||||
error_table_name(et->base),
|
||||
(const void *) et);
|
||||
et_list_unlock();
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Variant of the interface provided by Heimdal's com_err library
|
||||
*/
|
||||
void
|
||||
add_to_error_table(struct et_list *new_table)
|
||||
{
|
||||
add_error_table(new_table->table);
|
||||
}
|
||||
43
jni/e2fsprogs/lib/et/et_name.c
Executable file
43
jni/e2fsprogs/lib/et/et_name.c
Executable file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 1987 by MIT Student Information Processing Board
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose is hereby granted, provided that
|
||||
* the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. M.I.T. and the
|
||||
* M.I.T. S.I.P.B. make no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without
|
||||
* express or implied warranty.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "com_err.h"
|
||||
#include "error_table.h"
|
||||
#include "internal.h"
|
||||
|
||||
static const char char_set[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
|
||||
|
||||
static char buf[6];
|
||||
|
||||
const char * error_table_name(errcode_t num)
|
||||
{
|
||||
int ch;
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
/* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */
|
||||
p = buf;
|
||||
num >>= ERRCODE_RANGE;
|
||||
/* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */
|
||||
num &= 077777777L;
|
||||
/* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */
|
||||
for (i = 4; i >= 0; i--) {
|
||||
ch = (int)((num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1));
|
||||
if (ch != 0)
|
||||
*p++ = char_set[ch-1];
|
||||
}
|
||||
*p = '\0';
|
||||
return(buf);
|
||||
}
|
||||
53
jni/e2fsprogs/lib/et/init_et.c
Executable file
53
jni/e2fsprogs/lib/et/init_et.c
Executable file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* $Header$
|
||||
* $Source$
|
||||
* $Locker$
|
||||
*
|
||||
* Copyright 1986, 1987, 1988 by MIT Information Systems and
|
||||
* the MIT Student Information Processing Board.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose is hereby granted, provided that
|
||||
* the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. M.I.T. and the
|
||||
* M.I.T. S.I.P.B. make no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without
|
||||
* express or implied warranty.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "com_err.h"
|
||||
#include "error_table.h"
|
||||
|
||||
struct foobar {
|
||||
struct et_list etl;
|
||||
struct error_table et;
|
||||
};
|
||||
|
||||
extern struct et_list * _et_dynamic_list;
|
||||
|
||||
int init_error_table(const char * const *msgs, long base, int count)
|
||||
{
|
||||
struct foobar * new_et;
|
||||
|
||||
if (!base || !count || !msgs)
|
||||
return 0;
|
||||
|
||||
new_et = (struct foobar *) malloc(sizeof(struct foobar));
|
||||
if (!new_et)
|
||||
return ENOMEM; /* oops */
|
||||
new_et->etl.table = &new_et->et;
|
||||
new_et->et.msgs = msgs;
|
||||
new_et->et.base = base;
|
||||
new_et->et.n_msgs= count;
|
||||
|
||||
new_et->etl.next = _et_dynamic_list;
|
||||
_et_dynamic_list = &new_et->etl;
|
||||
return 0;
|
||||
}
|
||||
554
jni/e2fsprogs/lib/ext2fs/alloc.c
Executable file
554
jni/e2fsprogs/lib/ext2fs/alloc.c
Executable file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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"
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
|
||||
#else
|
||||
# define dbg_printf(f, a...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clear the uninit block bitmap flag if necessary
|
||||
*/
|
||||
void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
if (group >= fs->group_desc_count ||
|
||||
!ext2fs_has_group_desc_csum(fs) ||
|
||||
!(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
|
||||
return;
|
||||
|
||||
/* uninit block bitmaps are now initialized in read_bitmaps() */
|
||||
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for uninit inode bitmaps and deal with them appropriately
|
||||
*/
|
||||
static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map,
|
||||
dgrp_t group)
|
||||
{
|
||||
ext2_ino_t i, ino;
|
||||
|
||||
if (group >= fs->group_desc_count ||
|
||||
!ext2fs_has_group_desc_csum(fs) ||
|
||||
!(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
|
||||
return;
|
||||
|
||||
ino = (group * fs->super->s_inodes_per_group) + 1;
|
||||
for (i=0; i < fs->super->s_inodes_per_group; i++, ino++)
|
||||
ext2fs_fast_unmark_inode_bitmap2(map, ino);
|
||||
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
|
||||
/* Mimics what the kernel does */
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
ext2fs_mark_ib_dirty(fs);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 start_inode = 0;
|
||||
ext2_ino_t i, ino_in_group, upto, first_zero;
|
||||
errcode_t retval;
|
||||
dgrp_t group;
|
||||
|
||||
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) {
|
||||
group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
|
||||
start_inode = (group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
|
||||
}
|
||||
if (start_inode < EXT2_FIRST_INODE(fs->super))
|
||||
start_inode = EXT2_FIRST_INODE(fs->super);
|
||||
if (start_inode > fs->super->s_inodes_count)
|
||||
return EXT2_ET_INODE_ALLOC_FAIL;
|
||||
i = start_inode;
|
||||
do {
|
||||
ino_in_group = (i - 1) % EXT2_INODES_PER_GROUP(fs->super);
|
||||
group = (i - 1) / EXT2_INODES_PER_GROUP(fs->super);
|
||||
|
||||
check_inode_uninit(fs, map, group);
|
||||
upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group);
|
||||
if (i < start_inode && upto >= start_inode)
|
||||
upto = start_inode - 1;
|
||||
if (upto > fs->super->s_inodes_count)
|
||||
upto = fs->super->s_inodes_count;
|
||||
|
||||
retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto,
|
||||
&first_zero);
|
||||
if (retval == 0) {
|
||||
i = first_zero;
|
||||
break;
|
||||
}
|
||||
if (retval != ENOENT)
|
||||
return EXT2_ET_INODE_ALLOC_FAIL;
|
||||
i = upto + 1;
|
||||
if (i > fs->super->s_inodes_count)
|
||||
i = EXT2_FIRST_INODE(fs->super);
|
||||
} while (i != start_inode);
|
||||
|
||||
if (ext2fs_test_inode_bitmap2(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_block3(ext2_filsys fs, blk64_t goal,
|
||||
ext2fs_block_bitmap map, blk64_t *ret,
|
||||
struct blk_alloc_ctx *ctx)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t b = 0;
|
||||
errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret);
|
||||
errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *,
|
||||
struct blk_alloc_ctx *);
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (!map) {
|
||||
/*
|
||||
* In case there are clients out there whose get_alloc_block
|
||||
* handlers call ext2fs_new_block2 with a NULL block map,
|
||||
* temporarily swap out the function pointer so that we don't
|
||||
* end up in an infinite loop.
|
||||
*/
|
||||
if (fs->get_alloc_block2) {
|
||||
gab2 = fs->get_alloc_block2;
|
||||
fs->get_alloc_block2 = NULL;
|
||||
retval = gab2(fs, goal, &b, ctx);
|
||||
fs->get_alloc_block2 = gab2;
|
||||
goto allocated;
|
||||
} else if (fs->get_alloc_block) {
|
||||
gab = fs->get_alloc_block;
|
||||
fs->get_alloc_block = NULL;
|
||||
retval = gab(fs, goal, &b);
|
||||
fs->get_alloc_block = gab;
|
||||
goto allocated;
|
||||
}
|
||||
}
|
||||
if (!map)
|
||||
map = fs->block_map;
|
||||
if (!map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
if (!goal || (goal >= ext2fs_blocks_count(fs->super)))
|
||||
goal = fs->super->s_first_data_block;
|
||||
goal &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(map,
|
||||
goal, ext2fs_blocks_count(fs->super) - 1, &b);
|
||||
if ((retval == ENOENT) && (goal != fs->super->s_first_data_block))
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(map,
|
||||
fs->super->s_first_data_block, goal - 1, &b);
|
||||
allocated:
|
||||
if (retval == ENOENT)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ext2fs_clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b));
|
||||
*ret = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
|
||||
ext2fs_block_bitmap map, blk64_t *ret)
|
||||
{
|
||||
return ext2fs_new_block3(fs, goal, map, ret, NULL);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
|
||||
ext2fs_block_bitmap map, blk_t *ret)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t val;
|
||||
retval = ext2fs_new_block2(fs, goal, map, &val);
|
||||
if (!retval)
|
||||
*ret = (blk_t) val;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function zeros out the allocated block, and updates all of the
|
||||
* appropriate filesystem records.
|
||||
*/
|
||||
errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf,
|
||||
blk64_t *ret, struct blk_alloc_ctx *ctx)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t block;
|
||||
|
||||
if (fs->get_alloc_block2) {
|
||||
retval = (fs->get_alloc_block2)(fs, goal, &block, ctx);
|
||||
if (retval)
|
||||
goto fail;
|
||||
} else if (fs->get_alloc_block) {
|
||||
retval = (fs->get_alloc_block)(fs, goal, &block);
|
||||
if (retval)
|
||||
goto fail;
|
||||
} else {
|
||||
if (!fs->block_map) {
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
retval = ext2fs_new_block3(fs, goal, 0, &block, ctx);
|
||||
if (retval)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (block_buf) {
|
||||
memset(block_buf, 0, fs->blocksize);
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, block_buf);
|
||||
} else
|
||||
retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
ext2fs_block_alloc_stats2(fs, block, +1);
|
||||
*ret = block;
|
||||
|
||||
fail:
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
|
||||
char *block_buf, blk64_t *ret)
|
||||
{
|
||||
return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
|
||||
char *block_buf, blk_t *ret)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t ret64, goal64 = goal;
|
||||
retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL);
|
||||
if (!retval)
|
||||
*ret = (blk_t)ret64;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish,
|
||||
int num, ext2fs_block_bitmap map, blk64_t *ret)
|
||||
{
|
||||
blk64_t b = start;
|
||||
int c_ratio;
|
||||
|
||||
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;
|
||||
c_ratio = 1 << ext2fs_get_bitmap_granularity(map);
|
||||
b &= ~(c_ratio - 1);
|
||||
finish &= ~(c_ratio -1);
|
||||
do {
|
||||
if (b + num - 1 >= ext2fs_blocks_count(fs->super)) {
|
||||
if (finish > start)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
b = fs->super->s_first_data_block;
|
||||
}
|
||||
if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) {
|
||||
*ret = b;
|
||||
return 0;
|
||||
}
|
||||
b += c_ratio;
|
||||
} while (b != finish);
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
|
||||
int num, ext2fs_block_bitmap map, blk_t *ret)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t val;
|
||||
retval = ext2fs_get_free_blocks2(fs, start, finish, num, map, &val);
|
||||
if(!retval)
|
||||
*ret = (blk_t) val;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ext2fs_set_alloc_block_callback(ext2_filsys fs,
|
||||
errcode_t (*func)(ext2_filsys fs,
|
||||
blk64_t goal,
|
||||
blk64_t *ret),
|
||||
errcode_t (**old)(ext2_filsys fs,
|
||||
blk64_t goal,
|
||||
blk64_t *ret))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
|
||||
if (old)
|
||||
*old = fs->get_alloc_block;
|
||||
|
||||
fs->get_alloc_block = func;
|
||||
}
|
||||
|
||||
blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t lblk)
|
||||
{
|
||||
dgrp_t group;
|
||||
__u8 log_flex;
|
||||
struct ext2fs_extent extent;
|
||||
ext2_extent_handle_t handle = NULL;
|
||||
errcode_t err;
|
||||
|
||||
/* Make sure data stored in inode->i_block is neither fast symlink nor
|
||||
* inline data.
|
||||
*/
|
||||
if (inode == NULL || ext2fs_is_fast_symlink(inode) ||
|
||||
inode->i_flags & EXT4_INLINE_DATA_FL)
|
||||
goto no_blocks;
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
err = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (err)
|
||||
goto no_blocks;
|
||||
err = ext2fs_extent_goto2(handle, 0, lblk);
|
||||
if (err)
|
||||
goto no_blocks;
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
|
||||
if (err)
|
||||
goto no_blocks;
|
||||
ext2fs_extent_free(handle);
|
||||
return extent.e_pblk + (lblk - extent.e_lblk);
|
||||
}
|
||||
|
||||
/* block mapped file; see if block zero is mapped? */
|
||||
if (inode->i_block[0])
|
||||
return inode->i_block[0];
|
||||
|
||||
no_blocks:
|
||||
ext2fs_extent_free(handle);
|
||||
log_flex = fs->super->s_log_groups_per_flex;
|
||||
group = ext2fs_group_of_ino(fs, ino);
|
||||
if (log_flex)
|
||||
group = group & ~((1 << (log_flex)) - 1);
|
||||
return ext2fs_group_first_block2(fs, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting at _goal_, scan around the filesystem to find a run of free blocks
|
||||
* that's at least _len_ blocks long. Possible flags:
|
||||
* - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_.
|
||||
* - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_.
|
||||
* - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning.
|
||||
*
|
||||
* The starting block is returned in _pblk_ and the length is returned via
|
||||
* _plen_. The blocks are not marked in the bitmap; the caller must mark
|
||||
* however much of the returned run they actually use, hopefully via
|
||||
* ext2fs_block_alloc_stats_range().
|
||||
*
|
||||
* This function can return a range that is longer than what was requested.
|
||||
*/
|
||||
errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk,
|
||||
blk64_t *plen)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t start, end, b;
|
||||
int looped = 0;
|
||||
blk64_t max_blocks = ext2fs_blocks_count(fs->super);
|
||||
errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, blk64_t *pblk, blk64_t *plen);
|
||||
|
||||
dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags,
|
||||
goal, len);
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (!map && fs->new_range) {
|
||||
/*
|
||||
* In case there are clients out there whose new_range
|
||||
* handlers call ext2fs_new_range with a NULL block map,
|
||||
* temporarily swap out the function pointer so that we don't
|
||||
* end up in an infinite loop.
|
||||
*/
|
||||
nrf = fs->new_range;
|
||||
fs->new_range = NULL;
|
||||
retval = nrf(fs, flags, goal, len, pblk, plen);
|
||||
fs->new_range = nrf;
|
||||
if (retval)
|
||||
return retval;
|
||||
start = *pblk;
|
||||
end = *pblk + *plen;
|
||||
goto allocated;
|
||||
}
|
||||
if (!map)
|
||||
map = fs->block_map;
|
||||
if (!map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
if (!goal || goal >= ext2fs_blocks_count(fs->super))
|
||||
goal = fs->super->s_first_data_block;
|
||||
|
||||
start = goal;
|
||||
while (!looped || start <= goal) {
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(map, start,
|
||||
max_blocks - 1,
|
||||
&start);
|
||||
if (retval == ENOENT) {
|
||||
/*
|
||||
* If there are no free blocks beyond the starting
|
||||
* point, try scanning the whole filesystem, unless the
|
||||
* user told us only to allocate from _goal_, or if
|
||||
* we're already scanning the whole filesystem.
|
||||
*/
|
||||
if (flags & EXT2_NEWRANGE_FIXED_GOAL ||
|
||||
start == fs->super->s_first_data_block)
|
||||
goto fail;
|
||||
start = fs->super->s_first_data_block;
|
||||
continue;
|
||||
} else if (retval)
|
||||
goto errout;
|
||||
|
||||
if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal)
|
||||
goto fail;
|
||||
|
||||
b = min(start + len - 1, max_blocks - 1);
|
||||
retval = ext2fs_find_first_set_block_bitmap2(map, start, b,
|
||||
&end);
|
||||
if (retval == ENOENT)
|
||||
end = b + 1;
|
||||
else if (retval)
|
||||
goto errout;
|
||||
|
||||
if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) ||
|
||||
(end - start) >= len) {
|
||||
/* Success! */
|
||||
*pblk = start;
|
||||
*plen = end - start;
|
||||
dbg_printf("%s: new_range goal=%llu--%llu "
|
||||
"blk=%llu--%llu %llu\n",
|
||||
__func__, goal, goal + len - 1,
|
||||
*pblk, *pblk + *plen - 1, *plen);
|
||||
allocated:
|
||||
for (b = start; b < end;
|
||||
b += fs->super->s_blocks_per_group)
|
||||
ext2fs_clear_block_uninit(fs,
|
||||
ext2fs_group_of_blk2(fs, b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & EXT2_NEWRANGE_FIXED_GOAL)
|
||||
goto fail;
|
||||
start = end;
|
||||
if (start >= max_blocks) {
|
||||
if (looped)
|
||||
goto fail;
|
||||
looped = 1;
|
||||
start = fs->super->s_first_data_block;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
retval = EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
errout:
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ext2fs_set_new_range_callback(ext2_filsys fs,
|
||||
errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, blk64_t *pblk, blk64_t *plen),
|
||||
errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, blk64_t *pblk, blk64_t *plen))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
|
||||
if (old)
|
||||
*old = fs->new_range;
|
||||
|
||||
fs->new_range = func;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk_t len, blk64_t *ret)
|
||||
{
|
||||
int newr_flags = EXT2_NEWRANGE_MIN_LENGTH;
|
||||
errcode_t retval;
|
||||
blk64_t plen;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (flags & EXT2_ALLOCRANGE_FIXED_GOAL)
|
||||
newr_flags |= EXT2_NEWRANGE_FIXED_GOAL;
|
||||
|
||||
retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (plen < len)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
|
||||
if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) {
|
||||
retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
ext2fs_block_alloc_stats_range(fs, *ret, len, +1);
|
||||
return retval;
|
||||
}
|
||||
81
jni/e2fsprogs/lib/ext2fs/alloc_sb.c
Executable file
81
jni/e2fsprogs/lib/ext2fs/alloc_sb.c
Executable file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 function reserves the superblock and block group descriptors
|
||||
* for a given block group. It currently returns the number of free
|
||||
* blocks assuming that inode table and allocation bitmaps will be in
|
||||
* the group. This is not necessarily the case when the flex_bg
|
||||
* feature is enabled, so callers should take care! It was only
|
||||
* really intended for use by mke2fs, and even there it's not that
|
||||
* useful. In the future, when we redo this function for 64-bit block
|
||||
* numbers, we should probably return the number of blocks used by the
|
||||
* super block and group descriptors instead.
|
||||
*
|
||||
* See also the comment for ext2fs_super_and_bgd_loc()
|
||||
*/
|
||||
int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
|
||||
dgrp_t group,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
blk64_t super_blk, old_desc_blk, new_desc_blk;
|
||||
blk_t used_blks;
|
||||
int old_desc_blocks, num_blocks;
|
||||
|
||||
ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
|
||||
&old_desc_blk, &new_desc_blk, &used_blks);
|
||||
|
||||
if (ext2fs_has_feature_meta_bg(fs->super))
|
||||
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_bitmap2(bmap, super_blk);
|
||||
if ((group == 0) && (fs->blocksize == 1024) &&
|
||||
EXT2FS_CLUSTER_RATIO(fs) > 1)
|
||||
ext2fs_mark_block_bitmap2(bmap, 0);
|
||||
|
||||
if (old_desc_blk) {
|
||||
num_blocks = old_desc_blocks;
|
||||
if (old_desc_blk + num_blocks >= ext2fs_blocks_count(fs->super))
|
||||
num_blocks = ext2fs_blocks_count(fs->super) -
|
||||
old_desc_blk;
|
||||
ext2fs_mark_block_bitmap_range2(bmap, old_desc_blk, num_blocks);
|
||||
}
|
||||
if (new_desc_blk)
|
||||
ext2fs_mark_block_bitmap2(bmap, new_desc_blk);
|
||||
|
||||
num_blocks = ext2fs_group_blocks_count(fs, group);
|
||||
num_blocks -= 2 + fs->inode_blocks_per_group + used_blks;
|
||||
|
||||
return num_blocks ;
|
||||
}
|
||||
165
jni/e2fsprogs/lib/ext2fs/alloc_stats.c
Executable file
165
jni/e2fsprogs/lib/ext2fs/alloc_stats.c
Executable file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 (ino > fs->super->s_inodes_count) {
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err("ext2fs_inode_alloc_stats2", 0,
|
||||
"Illegal inode number: %lu", (unsigned long) ino);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (inuse > 0)
|
||||
ext2fs_mark_inode_bitmap2(fs->inode_map, ino);
|
||||
else
|
||||
ext2fs_unmark_inode_bitmap2(fs->inode_map, ino);
|
||||
ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) - inuse);
|
||||
if (isdir)
|
||||
ext2fs_bg_used_dirs_count_set(fs, group, ext2fs_bg_used_dirs_count(fs, group) + inuse);
|
||||
|
||||
/* We don't strictly need to be clearing the uninit flag if inuse < 0
|
||||
* (i.e. freeing inodes) but it also means something is bad. */
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
|
||||
if (ext2fs_has_group_desc_csum(fs)) {
|
||||
ext2_ino_t first_unused_inode = fs->super->s_inodes_per_group -
|
||||
ext2fs_bg_itable_unused(fs, group) +
|
||||
group * fs->super->s_inodes_per_group + 1;
|
||||
|
||||
if (ino >= first_unused_inode)
|
||||
ext2fs_bg_itable_unused_set(fs, group, group * fs->super->s_inodes_per_group + fs->super->s_inodes_per_group - ino);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
}
|
||||
|
||||
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_stats2(ext2_filsys fs, blk64_t blk, int inuse)
|
||||
{
|
||||
int group = ext2fs_group_of_blk2(fs, blk);
|
||||
|
||||
if (blk < fs->super->s_first_data_block ||
|
||||
blk >= ext2fs_blocks_count(fs->super)) {
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err("ext2fs_block_alloc_stats", 0,
|
||||
"Illegal block number: %lu", (unsigned long) blk);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (inuse > 0)
|
||||
ext2fs_mark_block_bitmap2(fs->block_map, blk);
|
||||
else
|
||||
ext2fs_unmark_block_bitmap2(fs->block_map, blk);
|
||||
ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) - inuse);
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
|
||||
ext2fs_free_blocks_count_add(fs->super,
|
||||
-inuse * (blk64_t) EXT2FS_CLUSTER_RATIO(fs));
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
if (fs->block_alloc_stats)
|
||||
(fs->block_alloc_stats)(fs, (blk64_t) blk, inuse);
|
||||
}
|
||||
|
||||
void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
|
||||
{
|
||||
ext2fs_block_alloc_stats2(fs, blk, inuse);
|
||||
}
|
||||
|
||||
void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs,
|
||||
void (*func)(ext2_filsys fs,
|
||||
blk64_t blk,
|
||||
int inuse),
|
||||
void (**old)(ext2_filsys fs,
|
||||
blk64_t blk,
|
||||
int inuse))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
if (old)
|
||||
*old = fs->block_alloc_stats;
|
||||
|
||||
fs->block_alloc_stats = func;
|
||||
}
|
||||
|
||||
void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
|
||||
blk_t num, int inuse)
|
||||
{
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (blk + num > ext2fs_blocks_count(fs->super)) {
|
||||
com_err("ext2fs_block_alloc_stats_range", 0,
|
||||
"Illegal block range: %llu (%u) ",
|
||||
(unsigned long long) blk, num);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (inuse == 0)
|
||||
return;
|
||||
if (inuse > 0) {
|
||||
ext2fs_mark_block_bitmap_range2(fs->block_map, blk, num);
|
||||
inuse = 1;
|
||||
} else {
|
||||
ext2fs_unmark_block_bitmap_range2(fs->block_map, blk, num);
|
||||
inuse = -1;
|
||||
}
|
||||
while (num) {
|
||||
int group = ext2fs_group_of_blk2(fs, blk);
|
||||
blk64_t last_blk = ext2fs_group_last_block2(fs, group);
|
||||
blk64_t n = num;
|
||||
|
||||
if (blk + num > last_blk)
|
||||
n = last_blk - blk + 1;
|
||||
|
||||
ext2fs_bg_free_blocks_count_set(fs, group,
|
||||
ext2fs_bg_free_blocks_count(fs, group) -
|
||||
inuse*n/EXT2FS_CLUSTER_RATIO(fs));
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
ext2fs_free_blocks_count_add(fs->super, -inuse * (blk64_t) n);
|
||||
blk += n;
|
||||
num -= n;
|
||||
}
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
if (fs->block_alloc_stats_range)
|
||||
(fs->block_alloc_stats_range)(fs, blk, num, inuse);
|
||||
}
|
||||
|
||||
void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs,
|
||||
void (*func)(ext2_filsys fs, blk64_t blk,
|
||||
blk_t num, int inuse),
|
||||
void (**old)(ext2_filsys fs, blk64_t blk,
|
||||
blk_t num, int inuse))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
if (old)
|
||||
*old = fs->block_alloc_stats_range;
|
||||
|
||||
fs->block_alloc_stats_range = func;
|
||||
}
|
||||
278
jni/e2fsprogs/lib/ext2fs/alloc_tables.c
Executable file
278
jni/e2fsprogs/lib/ext2fs/alloc_tables.c
Executable file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 "ext2fsP.h"
|
||||
|
||||
/*
|
||||
* This routine searches for free blocks that can allocate a full
|
||||
* group of bitmaps or inode tables for a flexbg group. Returns the
|
||||
* block number with a correct offset were the bitmaps and inode
|
||||
* tables can be allocated continuously and in order.
|
||||
*/
|
||||
static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk,
|
||||
ext2fs_block_bitmap bmap, int rem_grp,
|
||||
int elem_size)
|
||||
{
|
||||
int flexbg, flexbg_size, size;
|
||||
blk64_t last_blk, first_free = 0;
|
||||
dgrp_t last_grp;
|
||||
|
||||
flexbg_size = 1U << fs->super->s_log_groups_per_flex;
|
||||
flexbg = group / flexbg_size;
|
||||
size = rem_grp * elem_size;
|
||||
|
||||
if (size > (int) (fs->super->s_blocks_per_group / 4))
|
||||
size = (int) fs->super->s_blocks_per_group / 4;
|
||||
|
||||
/*
|
||||
* Don't do a long search if the previous block search is still valid,
|
||||
* but skip minor obstructions such as group descriptor backups.
|
||||
*/
|
||||
if (start_blk && start_blk < ext2fs_blocks_count(fs->super) &&
|
||||
ext2fs_get_free_blocks2(fs, start_blk, start_blk + size, elem_size,
|
||||
bmap, &first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg);
|
||||
last_grp = group | (flexbg_size - 1);
|
||||
if (last_grp > fs->group_desc_count-1)
|
||||
last_grp = fs->group_desc_count-1;
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
|
||||
/* Find the first available block */
|
||||
if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, size,
|
||||
bmap, &first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, elem_size,
|
||||
bmap, &first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
if (ext2fs_get_free_blocks2(fs, 0, last_blk, elem_size, bmap,
|
||||
&first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
return first_free;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t group_blk, start_blk, last_blk, new_blk;
|
||||
dgrp_t last_grp = 0;
|
||||
int rem_grps = 0, flexbg_size = 0, table_offset = 0;
|
||||
|
||||
group_blk = ext2fs_group_first_block2(fs, group);
|
||||
last_blk = ext2fs_group_last_block2(fs, group);
|
||||
|
||||
if (!bmap)
|
||||
bmap = fs->block_map;
|
||||
|
||||
if (ext2fs_has_feature_flex_bg(fs->super) &&
|
||||
fs->super->s_log_groups_per_flex) {
|
||||
flexbg_size = 1U << fs->super->s_log_groups_per_flex;
|
||||
last_grp = group | (flexbg_size - 1);
|
||||
if (last_grp > fs->group_desc_count-1)
|
||||
last_grp = fs->group_desc_count-1;
|
||||
rem_grps = last_grp - group + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the block and inode bitmaps, if necessary
|
||||
*/
|
||||
if (fs->stride && !flexbg_size) {
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk,
|
||||
1, bmap, &start_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
start_blk += fs->inode_blocks_per_group;
|
||||
start_blk += ((fs->stride * group) %
|
||||
(last_blk - start_blk + 1));
|
||||
if (start_blk >= last_blk)
|
||||
start_blk = group_blk;
|
||||
} else
|
||||
start_blk = group_blk;
|
||||
|
||||
if (flexbg_size) {
|
||||
blk64_t prev_block = 0;
|
||||
|
||||
table_offset = flexbg_size;
|
||||
if (group % flexbg_size)
|
||||
prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1;
|
||||
else if (last_grp == fs->group_desc_count-1) {
|
||||
/*
|
||||
* If we are allocating for the last flex_bg
|
||||
* keep the metadata tables contiguous
|
||||
*/
|
||||
table_offset = last_grp & (flexbg_size - 1);
|
||||
if (table_offset == 0)
|
||||
table_offset = flexbg_size;
|
||||
else
|
||||
table_offset++;
|
||||
}
|
||||
/* FIXME: Take backup group descriptor blocks into account
|
||||
* if the flexbg allocations will grow to overlap them... */
|
||||
start_blk = flexbg_offset(fs, group, prev_block, bmap,
|
||||
rem_grps, 1);
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
}
|
||||
|
||||
if (!ext2fs_block_bitmap_loc(fs, group)) {
|
||||
retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk,
|
||||
1, bmap, &new_blk);
|
||||
if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk,
|
||||
last_blk, 1, bmap, &new_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_mark_block_bitmap2(bmap, new_blk);
|
||||
ext2fs_block_bitmap_loc_set(fs, group, new_blk);
|
||||
if (flexbg_size) {
|
||||
dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk);
|
||||
ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
|
||||
ext2fs_free_blocks_count_add(fs->super, -1);
|
||||
ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, gr);
|
||||
}
|
||||
}
|
||||
|
||||
if (flexbg_size) {
|
||||
blk64_t prev_block = 0;
|
||||
if (group % flexbg_size)
|
||||
prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1;
|
||||
else
|
||||
prev_block = ext2fs_block_bitmap_loc(fs, group) +
|
||||
table_offset;
|
||||
/* FIXME: Take backup group descriptor blocks into account
|
||||
* if the flexbg allocations will grow to overlap them... */
|
||||
start_blk = flexbg_offset(fs, group, prev_block, bmap,
|
||||
rem_grps, 1);
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
}
|
||||
|
||||
if (!ext2fs_inode_bitmap_loc(fs, group)) {
|
||||
retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk,
|
||||
1, bmap, &new_blk);
|
||||
if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk,
|
||||
last_blk, 1, bmap, &new_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_mark_block_bitmap2(bmap, new_blk);
|
||||
ext2fs_inode_bitmap_loc_set(fs, group, new_blk);
|
||||
if (flexbg_size) {
|
||||
dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk);
|
||||
ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
|
||||
ext2fs_free_blocks_count_add(fs->super, -1);
|
||||
ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, gr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the inode table
|
||||
*/
|
||||
if (flexbg_size) {
|
||||
blk64_t prev_block = 0;
|
||||
|
||||
if (group % flexbg_size)
|
||||
prev_block = ext2fs_inode_table_loc(fs, group - 1) +
|
||||
fs->inode_blocks_per_group;
|
||||
else
|
||||
prev_block = ext2fs_inode_bitmap_loc(fs, group) +
|
||||
table_offset;
|
||||
|
||||
/* FIXME: Take backup group descriptor blocks into account
|
||||
* if the flexbg allocations will grow to overlap them... */
|
||||
group_blk = flexbg_offset(fs, group, prev_block, bmap,
|
||||
rem_grps, fs->inode_blocks_per_group);
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
}
|
||||
|
||||
if (!ext2fs_inode_table_loc(fs, group)) {
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk,
|
||||
fs->inode_blocks_per_group,
|
||||
bmap, &new_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ext2fs_mark_block_bitmap_range2(bmap,
|
||||
new_blk, fs->inode_blocks_per_group);
|
||||
if (flexbg_size) {
|
||||
blk64_t num, blk;
|
||||
num = fs->inode_blocks_per_group;
|
||||
blk = new_blk;
|
||||
while (num) {
|
||||
int gr = ext2fs_group_of_blk2(fs, blk);
|
||||
last_blk = ext2fs_group_last_block2(fs, gr);
|
||||
blk64_t n = num;
|
||||
|
||||
if (blk + num > last_blk)
|
||||
n = last_blk - blk + 1;
|
||||
|
||||
ext2fs_bg_free_blocks_count_set(fs, gr,
|
||||
ext2fs_bg_free_blocks_count(fs, gr) -
|
||||
n/EXT2FS_CLUSTER_RATIO(fs));
|
||||
ext2fs_bg_flags_clear(fs, gr,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, gr);
|
||||
ext2fs_free_blocks_count_add(fs->super, -n);
|
||||
blk += n;
|
||||
num -= n;
|
||||
}
|
||||
}
|
||||
ext2fs_inode_table_loc_set(fs, group, new_blk);
|
||||
}
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_tables(ext2_filsys fs)
|
||||
{
|
||||
errcode_t retval;
|
||||
dgrp_t i;
|
||||
struct ext2fs_numeric_progress_struct progress;
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->init)
|
||||
(fs->progress_ops->init)(fs, &progress, NULL,
|
||||
fs->group_desc_count);
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
if (fs->progress_ops && fs->progress_ops->update)
|
||||
(fs->progress_ops->update)(fs, &progress, i);
|
||||
retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (fs->progress_ops && fs->progress_ops->close)
|
||||
(fs->progress_ops->close)(fs, &progress, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
116
jni/e2fsprogs/lib/ext2fs/atexit.c
Executable file
116
jni/e2fsprogs/lib/ext2fs/atexit.c
Executable file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* atexit.c --- Clean things up when we exit normally.
|
||||
*
|
||||
* Copyright Oracle, 2014
|
||||
* Author Darrick J. Wong <darrick.wong@oracle.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct exit_data {
|
||||
ext2_exit_fn func;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static struct exit_data *items;
|
||||
static size_t nr_items;
|
||||
|
||||
static void handle_exit(void)
|
||||
{
|
||||
struct exit_data *ed;
|
||||
|
||||
for (ed = items + nr_items - 1; ed >= items; ed--) {
|
||||
if (ed->func == NULL)
|
||||
continue;
|
||||
ed->func(ed->data);
|
||||
}
|
||||
|
||||
ext2fs_free_mem(&items);
|
||||
nr_items = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule a function to be called at (normal) program termination.
|
||||
* If you want this to be called during a signal exit, you must capture
|
||||
* the signal and call exit() yourself!
|
||||
*/
|
||||
errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data)
|
||||
{
|
||||
struct exit_data *ed, *free_ed = NULL;
|
||||
size_t x;
|
||||
errcode_t ret;
|
||||
|
||||
if (func == NULL)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
for (x = 0, ed = items; x < nr_items; x++, ed++) {
|
||||
if (ed->func == func && ed->data == data)
|
||||
return EXT2_ET_FILE_EXISTS;
|
||||
if (ed->func == NULL)
|
||||
free_ed = ed;
|
||||
}
|
||||
|
||||
if (free_ed) {
|
||||
free_ed->func = func;
|
||||
free_ed->data = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nr_items == 0) {
|
||||
ret = atexit(handle_exit);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data),
|
||||
&items);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
items[nr_items].func = func;
|
||||
items[nr_items].data = data;
|
||||
nr_items++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a function from the exit cleanup list. */
|
||||
errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data)
|
||||
{
|
||||
struct exit_data *ed;
|
||||
size_t x;
|
||||
|
||||
if (func == NULL)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
for (x = 0, ed = items; x < nr_items; x++, ed++) {
|
||||
if (ed->func == NULL)
|
||||
return 0;
|
||||
if (ed->func == func && ed->data == data) {
|
||||
size_t sz = (nr_items - (x + 1)) *
|
||||
sizeof(struct exit_data);
|
||||
memmove(ed, ed + 1, sz);
|
||||
memset(items + nr_items - 1, 0,
|
||||
sizeof(struct exit_data));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
328
jni/e2fsprogs/lib/ext2fs/badblocks.c
Executable file
328
jni/e2fsprogs/lib/ext2fs/badblocks.c
Executable file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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_array(bb->size, sizeof(blk_t), &bb->list);
|
||||
if (retval) {
|
||||
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 = ((unsigned)low + (unsigned)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;
|
||||
}
|
||||
64
jni/e2fsprogs/lib/ext2fs/bb_compat.c
Executable file
64
jni/e2fsprogs/lib/ext2fs/bb_compat.c
Executable file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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);
|
||||
}
|
||||
270
jni/e2fsprogs/lib/ext2fs/bb_inode.c
Executable file
270
jni/e2fsprogs/lib/ext2fs/bb_inode.c
Executable file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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;
|
||||
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.max_ind_blocks = 10;
|
||||
retval = ext2fs_get_array(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 indirect 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 = fs->now ? fs->now : time(0);
|
||||
if (!inode.i_ctime)
|
||||
inode.i_ctime = fs->now ? fs->now : time(0);
|
||||
ext2fs_iblk_set(fs, &inode, rec.bad_block_count);
|
||||
retval = ext2fs_inode_size_set(fs, &inode,
|
||||
rec.bad_block_count * fs->blocksize);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
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 >= ext2fs_blocks_count(fs->super) ||
|
||||
*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_stats2(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_bitmap2(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_blk64(fs->io, blk, 1, rec->block_buf);
|
||||
if (retval) {
|
||||
rec->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update block counts
|
||||
*/
|
||||
ext2fs_block_alloc_stats2(fs, blk, +1);
|
||||
|
||||
*block_nr = blk;
|
||||
return BLOCK_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
320
jni/e2fsprogs/lib/ext2fs/bitmaps.c
Executable file
320
jni/e2fsprogs/lib/ext2fs/bitmaps.c
Executable file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
|
||||
void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
|
||||
{
|
||||
ext2fs_free_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
ext2fs_free_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
|
||||
ext2fs_generic_bitmap *dest)
|
||||
{
|
||||
return (ext2fs_copy_generic_bmap(src, dest));
|
||||
}
|
||||
void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
|
||||
{
|
||||
ext2fs_set_generic_bmap_padding(map);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
|
||||
const char *descr,
|
||||
ext2fs_inode_bitmap *ret)
|
||||
{
|
||||
__u64 start, end, real_end;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
|
||||
|
||||
fs->write_bitmaps = ext2fs_write_bitmaps;
|
||||
|
||||
start = 1;
|
||||
end = fs->super->s_inodes_count;
|
||||
real_end = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
|
||||
fs->group_desc_count;
|
||||
|
||||
/* Are we permitted to use new-style bitmaps? */
|
||||
if (fs->flags & EXT2_FLAG_64BITS)
|
||||
return (ext2fs_alloc_generic_bmap(fs,
|
||||
EXT2_ET_MAGIC_INODE_BITMAP64,
|
||||
fs->default_bitmap_type,
|
||||
start, end, real_end, descr, ret));
|
||||
|
||||
/* Otherwise, check to see if the file system is small enough
|
||||
* to use old-style 32-bit bitmaps */
|
||||
if ((end > ~0U) || (real_end > ~0U))
|
||||
return EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
||||
|
||||
return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, fs,
|
||||
start, end, real_end,
|
||||
descr, 0,
|
||||
(ext2fs_generic_bitmap *) ret));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
|
||||
const char *descr,
|
||||
ext2fs_block_bitmap *ret)
|
||||
{
|
||||
__u64 start, end, real_end;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
|
||||
|
||||
fs->write_bitmaps = ext2fs_write_bitmaps;
|
||||
|
||||
start = EXT2FS_B2C(fs, fs->super->s_first_data_block);
|
||||
end = EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1);
|
||||
real_end = ((__u64) EXT2_CLUSTERS_PER_GROUP(fs->super)
|
||||
* (__u64) fs->group_desc_count)-1 + start;
|
||||
|
||||
if (fs->flags & EXT2_FLAG_64BITS)
|
||||
return (ext2fs_alloc_generic_bmap(fs,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP64,
|
||||
fs->default_bitmap_type,
|
||||
start, end, real_end, descr, ret));
|
||||
|
||||
if ((end > ~0U) || (real_end > ~0U))
|
||||
return EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
||||
|
||||
return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs,
|
||||
start, end, real_end,
|
||||
descr, 0,
|
||||
(ext2fs_generic_bitmap *) ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* ext2fs_allocate_block_bitmap() really allocates a per-cluster
|
||||
* bitmap for backwards compatibility. This function allocates a
|
||||
* block bitmap which is truly per-block, even if clusters/bigalloc
|
||||
* are enabled. mke2fs and e2fsck need this for tracking the
|
||||
* allocation of the file system metadata blocks.
|
||||
*/
|
||||
errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs,
|
||||
const char *descr,
|
||||
ext2fs_block_bitmap *ret)
|
||||
{
|
||||
__u64 start, end, real_end;
|
||||
ext2fs_generic_bitmap bmap;
|
||||
ext2fs_generic_bitmap_64 bmap64;
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
|
||||
|
||||
fs->write_bitmaps = ext2fs_write_bitmaps;
|
||||
|
||||
if (!fs->cluster_ratio_bits)
|
||||
return ext2fs_allocate_block_bitmap(fs, descr, ret);
|
||||
|
||||
if ((fs->flags & EXT2_FLAG_64BITS) == 0)
|
||||
return EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
||||
|
||||
start = fs->super->s_first_data_block;
|
||||
end = ext2fs_blocks_count(fs->super)-1;
|
||||
real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super)
|
||||
* (__u64) fs->group_desc_count)-1 + start;
|
||||
|
||||
retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64,
|
||||
fs->default_bitmap_type, start,
|
||||
end, real_end, descr, &bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
bmap64 = (ext2fs_generic_bitmap_64) bmap;
|
||||
bmap64->cluster_bits = 0;
|
||||
*ret = bmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return 0;
|
||||
|
||||
return bmap->cluster_bits;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
|
||||
ext2_ino_t end, ext2_ino_t *oend)
|
||||
{
|
||||
__u64 tmp_oend;
|
||||
int retval;
|
||||
|
||||
retval = ext2fs_fudge_generic_bmap_end((ext2fs_generic_bitmap) bitmap,
|
||||
EXT2_ET_FUDGE_INODE_BITMAP_END,
|
||||
end, &tmp_oend);
|
||||
if (oend)
|
||||
*oend = tmp_oend;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
|
||||
blk_t end, blk_t *oend)
|
||||
{
|
||||
return (ext2fs_fudge_generic_bitmap_end(bitmap,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
EXT2_ET_FUDGE_BLOCK_BITMAP_END,
|
||||
end, oend));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap,
|
||||
blk64_t end, blk64_t *oend)
|
||||
{
|
||||
return (ext2fs_fudge_generic_bmap_end(bitmap,
|
||||
EXT2_ET_FUDGE_BLOCK_BITMAP_END,
|
||||
end, oend));
|
||||
}
|
||||
|
||||
void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
|
||||
{
|
||||
ext2fs_clear_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
ext2fs_clear_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
|
||||
ext2fs_inode_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP,
|
||||
new_end, new_real_end, bmap));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, __u64 new_real_end,
|
||||
ext2fs_inode_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
new_end, new_real_end, bmap));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_block_bitmap2(__u64 new_end, __u64 new_real_end,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
|
||||
ext2fs_block_bitmap bm2)
|
||||
{
|
||||
return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_BLOCK_BITMAP,
|
||||
bm1, bm2));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
|
||||
ext2fs_inode_bitmap bm2)
|
||||
{
|
||||
return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_INODE_BITMAP,
|
||||
bm1, bm2));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
|
||||
ext2_ino_t start, unsigned int num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_INODE_BITMAP,
|
||||
start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_inode_bitmap_range2(ext2fs_inode_bitmap bmap,
|
||||
__u64 start, size_t num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bmap_range(bmap, start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
|
||||
ext2_ino_t start, unsigned int num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_INODE_BITMAP,
|
||||
start, num, out));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_inode_bitmap_range2(ext2fs_inode_bitmap bmap,
|
||||
__u64 start, size_t num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bmap_range(bmap, start, num, out));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
|
||||
blk_t start, unsigned int num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_block_bitmap_range2(ext2fs_block_bitmap bmap,
|
||||
blk64_t start, size_t num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bmap_range(bmap, start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
|
||||
blk_t start, unsigned int num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
start, num, out));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap,
|
||||
blk64_t start, size_t num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bmap_range(bmap, start, num, out));
|
||||
}
|
||||
148
jni/e2fsprogs/lib/ext2fs/bitops.c
Executable file
148
jni/e2fsprogs/lib/ext2fs/bitops.c
Executable file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* C language bitmap functions 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);
|
||||
}
|
||||
|
||||
void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
|
||||
const char *description)
|
||||
{
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (description)
|
||||
com_err(0, errcode, "#%lu for %s", arg, description);
|
||||
else
|
||||
com_err(0, errcode, "#%lu", arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Bitmap functions that take a 64-bit offset */
|
||||
|
||||
int ext2fs_set_bit64(__u64 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_bit64(__u64 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_bit64(__u64 nr, const void * addr)
|
||||
{
|
||||
int mask;
|
||||
const unsigned char *ADDR = (const unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
return (mask & *ADDR);
|
||||
}
|
||||
|
||||
static unsigned int popcount8(unsigned int w)
|
||||
{
|
||||
unsigned int res = w - ((w >> 1) & 0x55);
|
||||
res = (res & 0x33) + ((res >> 2) & 0x33);
|
||||
return (res + (res >> 4)) & 0x0F;
|
||||
}
|
||||
|
||||
static unsigned int popcount32(unsigned int w)
|
||||
{
|
||||
unsigned int res = w - ((w >> 1) & 0x55555555);
|
||||
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
|
||||
res = (res + (res >> 4)) & 0x0F0F0F0F;
|
||||
res = res + (res >> 8);
|
||||
return (res + (res >> 16)) & 0x000000FF;
|
||||
}
|
||||
|
||||
unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes)
|
||||
{
|
||||
const unsigned char *cp = addr;
|
||||
const __u32 *p;
|
||||
unsigned int res = 0;
|
||||
|
||||
while (((((uintptr_t) cp) & 3) != 0) && (nbytes > 0)) {
|
||||
res += popcount8(*cp++);
|
||||
nbytes--;
|
||||
}
|
||||
p = (const __u32 *) cp;
|
||||
|
||||
while (nbytes > 4) {
|
||||
res += popcount32(*p++);
|
||||
nbytes -= 4;
|
||||
}
|
||||
cp = (const unsigned char *) p;
|
||||
|
||||
while (nbytes > 0) {
|
||||
res += popcount8(*cp++);
|
||||
nbytes--;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
492
jni/e2fsprogs/lib/ext2fs/blkmap64_ba.c
Executable file
492
jni/e2fsprogs/lib/ext2fs/blkmap64_ba.c
Executable file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* blkmap64_ba.c --- Simple bitarray implementation for bitmaps
|
||||
*
|
||||
* Copyright (C) 2008 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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"
|
||||
#include "bmap64.h"
|
||||
|
||||
/*
|
||||
* Private data for bit array implementation of bitmap ops.
|
||||
* Currently, this is just a pointer to our big flat hunk of memory,
|
||||
* exactly equivalent to the old-skool char * bitmap member.
|
||||
*/
|
||||
|
||||
struct ext2fs_ba_private_struct {
|
||||
char *bitarray;
|
||||
};
|
||||
|
||||
typedef struct ext2fs_ba_private_struct *ext2fs_ba_private;
|
||||
|
||||
static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* Since we only have the one pointer, we could just shove our
|
||||
* private data in the void *private field itself, but then
|
||||
* we'd have to do a fair bit of rewriting if we ever added a
|
||||
* field. I'm agnostic.
|
||||
*/
|
||||
retval = ext2fs_get_mem(sizeof (ext2fs_ba_private), &bp);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
|
||||
|
||||
retval = ext2fs_get_mem(size, &bp->bitarray);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bp);
|
||||
bp = 0;
|
||||
return retval;
|
||||
}
|
||||
bitmap->private = (void *) bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
|
||||
ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
retval = ba_alloc_private_data (bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bp = (ext2fs_ba_private) bitmap->private;
|
||||
size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
|
||||
memset(bp->bitarray, 0, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ba_free_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
if (!bp)
|
||||
return;
|
||||
|
||||
if (bp->bitarray) {
|
||||
ext2fs_free_mem (&bp->bitarray);
|
||||
bp->bitarray = 0;
|
||||
}
|
||||
ext2fs_free_mem (&bp);
|
||||
bp = 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_copy_bmap(ext2fs_generic_bitmap_64 src,
|
||||
ext2fs_generic_bitmap_64 dest)
|
||||
{
|
||||
ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private;
|
||||
ext2fs_ba_private dest_bp;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
retval = ba_alloc_private_data (dest);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
dest_bp = (ext2fs_ba_private) dest->private;
|
||||
|
||||
size = (size_t) (((src->real_end - src->start) / 8) + 1);
|
||||
memcpy (dest_bp->bitarray, src_bp->bitarray, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_resize_bmap(ext2fs_generic_bitmap_64 bmap,
|
||||
__u64 new_end, __u64 new_real_end)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private;
|
||||
errcode_t retval;
|
||||
size_t size, new_size;
|
||||
__u64 bitno;
|
||||
|
||||
/*
|
||||
* 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_bit64(bitno - bmap->start, bp->bitarray);
|
||||
}
|
||||
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, &bp->bitarray);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (new_size > size)
|
||||
memset(bp->bitarray + size, 0, new_size - size);
|
||||
|
||||
bmap->end = new_end;
|
||||
bmap->real_end = new_real_end;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int ba_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
|
||||
return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static int ba_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
|
||||
return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static int ba_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
|
||||
return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static void ba_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static void ba_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, unsigned int len)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
__u64 start_byte, len_byte = len >> 3;
|
||||
unsigned int start_bit, len_bit = len % 8;
|
||||
unsigned int first_bit = 0;
|
||||
unsigned int last_bit = 0;
|
||||
int mark_count = 0;
|
||||
int mark_bit = 0;
|
||||
int i;
|
||||
const char *ADDR;
|
||||
|
||||
ADDR = bp->bitarray;
|
||||
start -= bitmap->start;
|
||||
start_byte = start >> 3;
|
||||
start_bit = start % 8;
|
||||
|
||||
if (start_bit != 0) {
|
||||
/*
|
||||
* The compared start block number or start inode number
|
||||
* is not the first bit in a byte.
|
||||
*/
|
||||
mark_count = 8 - start_bit;
|
||||
if (len < 8 - start_bit) {
|
||||
mark_count = (int)len;
|
||||
mark_bit = len + start_bit - 1;
|
||||
} else
|
||||
mark_bit = 7;
|
||||
|
||||
for (i = mark_count; i > 0; i--, mark_bit--)
|
||||
first_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the first byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (first_bit & ADDR[start_byte])
|
||||
return 0;
|
||||
else if (len <= 8 - start_bit)
|
||||
return 1;
|
||||
|
||||
start_byte++;
|
||||
len_bit = (len - mark_count) % 8;
|
||||
len_byte = (len - mark_count) >> 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* The compared start block number or start inode number is
|
||||
* the first bit in a byte.
|
||||
*/
|
||||
if (len_bit != 0) {
|
||||
/*
|
||||
* The compared end block number or end inode number is
|
||||
* not the last bit in a byte.
|
||||
*/
|
||||
for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--)
|
||||
last_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the last byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (last_bit & ADDR[start_byte + len_byte])
|
||||
return 0;
|
||||
else if (len_byte == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check whether all bytes are 0 */
|
||||
return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
|
||||
}
|
||||
|
||||
|
||||
static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *in)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
memcpy (bp->bitarray + (start >> 3), in, (num + 7) >> 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *out)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
memcpy (out, bp->bitarray + (start >> 3), (num + 7) >> 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ba_clear_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
memset(bp->bitarray, 0,
|
||||
(size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
static void ba_print_stats(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
fprintf(stderr, "%16llu Bytes used by bitarray\n", (unsigned long long)
|
||||
((bitmap->real_end - bitmap->start) >> 3) + 1 +
|
||||
sizeof(struct ext2fs_ba_private_struct));
|
||||
}
|
||||
#else
|
||||
static void ba_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Find the first zero bit between start and end, inclusive. */
|
||||
static errcode_t ba_find_first_zero(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
|
||||
unsigned long bitpos = start - bitmap->start;
|
||||
unsigned long count = end - start + 1;
|
||||
int byte_found = 0; /* whether a != 0xff byte has been found */
|
||||
const unsigned char *pos;
|
||||
unsigned long max_loop_count, i;
|
||||
|
||||
/* scan bits until we hit a byte boundary */
|
||||
while ((bitpos & 0x7) != 0 && count > 0) {
|
||||
if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
count--;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return ENOENT;
|
||||
|
||||
pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3);
|
||||
/* scan bytes until 8-byte (64-bit) aligned */
|
||||
while (count >= 8 && (((uintptr_t)pos) & 0x07)) {
|
||||
if (*pos != 0xff) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
count -= 8;
|
||||
bitpos += 8;
|
||||
}
|
||||
|
||||
if (!byte_found) {
|
||||
max_loop_count = count >> 6; /* 8-byte blocks */
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*((const __u64 *)pos) != ((__u64)-1))
|
||||
break;
|
||||
pos += 8;
|
||||
i--;
|
||||
}
|
||||
count -= 64 * (max_loop_count - i);
|
||||
bitpos += 64 * (max_loop_count - i);
|
||||
|
||||
max_loop_count = count >> 3;
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*pos != 0xff) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
i--;
|
||||
}
|
||||
count -= 8 * (max_loop_count - i);
|
||||
bitpos += 8 * (max_loop_count - i);
|
||||
}
|
||||
|
||||
/* Here either count < 8 or byte_found == 1. */
|
||||
while (count-- > 0) {
|
||||
if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/* Find the first one bit between start and end, inclusive. */
|
||||
static errcode_t ba_find_first_set(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
|
||||
unsigned long bitpos = start - bitmap->start;
|
||||
unsigned long count = end - start + 1;
|
||||
int byte_found = 0; /* whether a != 0xff byte has been found */
|
||||
const unsigned char *pos;
|
||||
unsigned long max_loop_count, i;
|
||||
|
||||
/* scan bits until we hit a byte boundary */
|
||||
while ((bitpos & 0x7) != 0 && count > 0) {
|
||||
if (ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
count--;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return ENOENT;
|
||||
|
||||
pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3);
|
||||
/* scan bytes until 8-byte (64-bit) aligned */
|
||||
while (count >= 8 && (((uintptr_t)pos) & 0x07)) {
|
||||
if (*pos != 0) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
count -= 8;
|
||||
bitpos += 8;
|
||||
}
|
||||
|
||||
if (!byte_found) {
|
||||
max_loop_count = count >> 6; /* 8-byte blocks */
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*((const __u64 *)pos) != 0)
|
||||
break;
|
||||
pos += 8;
|
||||
i--;
|
||||
}
|
||||
count -= 64 * (max_loop_count - i);
|
||||
bitpos += 64 * (max_loop_count - i);
|
||||
|
||||
max_loop_count = count >> 3;
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*pos != 0) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
i--;
|
||||
}
|
||||
count -= 8 * (max_loop_count - i);
|
||||
bitpos += 8 * (max_loop_count - i);
|
||||
}
|
||||
|
||||
/* Here either count < 8 or byte_found == 1. */
|
||||
while (count-- > 0) {
|
||||
if (ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = {
|
||||
.type = EXT2FS_BMAP64_BITARRAY,
|
||||
.new_bmap = ba_new_bmap,
|
||||
.free_bmap = ba_free_bmap,
|
||||
.copy_bmap = ba_copy_bmap,
|
||||
.resize_bmap = ba_resize_bmap,
|
||||
.mark_bmap = ba_mark_bmap,
|
||||
.unmark_bmap = ba_unmark_bmap,
|
||||
.test_bmap = ba_test_bmap,
|
||||
.test_clear_bmap_extent = ba_test_clear_bmap_extent,
|
||||
.mark_bmap_extent = ba_mark_bmap_extent,
|
||||
.unmark_bmap_extent = ba_unmark_bmap_extent,
|
||||
.set_bmap_range = ba_set_bmap_range,
|
||||
.get_bmap_range = ba_get_bmap_range,
|
||||
.clear_bmap = ba_clear_bmap,
|
||||
.print_stats = ba_print_stats,
|
||||
.find_first_zero = ba_find_first_zero,
|
||||
.find_first_set = ba_find_first_set
|
||||
};
|
||||
998
jni/e2fsprogs/lib/ext2fs/blkmap64_rb.c
Executable file
998
jni/e2fsprogs/lib/ext2fs/blkmap64_rb.c
Executable file
@@ -0,0 +1,998 @@
|
||||
/*
|
||||
* blkmap64_rb.c --- Simple rb-tree implementation for bitmaps
|
||||
*
|
||||
* (C)2010 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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
|
||||
#if HAVE_LINUX_TYPES_H
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
#include "rbtree.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
struct bmap_rb_extent {
|
||||
struct rb_node node;
|
||||
__u64 start;
|
||||
__u64 count;
|
||||
};
|
||||
|
||||
struct ext2fs_rb_private {
|
||||
struct rb_root root;
|
||||
struct bmap_rb_extent *wcursor;
|
||||
struct bmap_rb_extent *rcursor;
|
||||
struct bmap_rb_extent *rcursor_next;
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
__u64 mark_hit;
|
||||
__u64 test_hit;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline static struct bmap_rb_extent *node_to_extent(struct rb_node *node)
|
||||
{
|
||||
/*
|
||||
* This depends on the fact the struct rb_node is at the
|
||||
* beginning of the bmap_rb_extent structure. We use this
|
||||
* instead of the ext2fs_rb_entry macro because it causes gcc
|
||||
* -Wall to generate a huge amount of noise.
|
||||
*/
|
||||
return (struct bmap_rb_extent *) node;
|
||||
}
|
||||
|
||||
static int rb_insert_extent(__u64 start, __u64 count,
|
||||
struct ext2fs_rb_private *);
|
||||
static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64);
|
||||
|
||||
/* #define DEBUG_RB */
|
||||
|
||||
#ifdef DEBUG_RB
|
||||
static void print_tree(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *node = NULL;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
fprintf(stderr, "\t\t\t=================================\n");
|
||||
node = ext2fs_rb_first(root);
|
||||
for (node = ext2fs_rb_first(root); node != NULL;
|
||||
node = ext2fs_rb_next(node)) {
|
||||
ext = node_to_extent(node);
|
||||
fprintf(stderr, "\t\t\t--> (%llu -> %llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count);
|
||||
}
|
||||
fprintf(stderr, "\t\t\t=================================\n");
|
||||
}
|
||||
|
||||
static void check_tree(struct rb_root *root, const char *msg)
|
||||
{
|
||||
struct rb_node *node;
|
||||
struct bmap_rb_extent *ext, *old = NULL;
|
||||
|
||||
for (node = ext2fs_rb_first(root); node;
|
||||
node = ext2fs_rb_next(node)) {
|
||||
ext = node_to_extent(node);
|
||||
if (ext->count == 0) {
|
||||
fprintf(stderr, "Tree Error: count is zero\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
if (ext->start + ext->count < ext->start) {
|
||||
fprintf(stderr,
|
||||
"Tree Error: start or count is crazy\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (old) {
|
||||
if (old->start > ext->start) {
|
||||
fprintf(stderr, "Tree Error: start is crazy\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) old->start,
|
||||
(unsigned long long) old->start + old->count,
|
||||
(unsigned long long) old->count);
|
||||
fprintf(stderr,
|
||||
"extent next: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
if ((old->start + old->count) >= ext->start) {
|
||||
fprintf(stderr,
|
||||
"Tree Error: extent is crazy\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) old->start,
|
||||
(unsigned long long) old->start + old->count,
|
||||
(unsigned long long) old->count);
|
||||
fprintf(stderr,
|
||||
"extent next: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
old = ext;
|
||||
}
|
||||
return;
|
||||
|
||||
err_out:
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
print_tree(root);
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
#define check_tree(root, msg) do {} while (0)
|
||||
#define print_tree(root) do {} while (0)
|
||||
#endif
|
||||
|
||||
static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start,
|
||||
__u64 count)
|
||||
{
|
||||
struct bmap_rb_extent *new_ext;
|
||||
int retval;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent),
|
||||
&new_ext);
|
||||
if (retval)
|
||||
abort();
|
||||
|
||||
new_ext->start = start;
|
||||
new_ext->count = count;
|
||||
*ext = new_ext;
|
||||
}
|
||||
|
||||
inline
|
||||
static void rb_free_extent(struct ext2fs_rb_private *bp,
|
||||
struct bmap_rb_extent *ext)
|
||||
{
|
||||
if (bp->wcursor == ext)
|
||||
bp->wcursor = NULL;
|
||||
if (bp->rcursor == ext)
|
||||
bp->rcursor = NULL;
|
||||
if (bp->rcursor_next == ext)
|
||||
bp->rcursor_next = NULL;
|
||||
ext2fs_free_mem(&ext);
|
||||
}
|
||||
|
||||
static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof (struct ext2fs_rb_private), &bp);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bp->root = RB_ROOT;
|
||||
bp->rcursor = NULL;
|
||||
bp->rcursor_next = NULL;
|
||||
bp->wcursor = NULL;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bp->test_hit = 0;
|
||||
bp->mark_hit = 0;
|
||||
#endif
|
||||
|
||||
bitmap->private = (void *) bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
|
||||
ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
errcode_t retval;
|
||||
|
||||
retval = rb_alloc_private_data (bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rb_free_tree(struct rb_root *root)
|
||||
{
|
||||
struct bmap_rb_extent *ext;
|
||||
struct rb_node *node, *next;
|
||||
|
||||
for (node = ext2fs_rb_first(root); node; node = next) {
|
||||
next = ext2fs_rb_next(node);
|
||||
ext = node_to_extent(node);
|
||||
ext2fs_rb_erase(node, root);
|
||||
ext2fs_free_mem(&ext);
|
||||
}
|
||||
}
|
||||
|
||||
static void rb_free_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
rb_free_tree(&bp->root);
|
||||
ext2fs_free_mem(&bp);
|
||||
bp = 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_copy_bmap(ext2fs_generic_bitmap_64 src,
|
||||
ext2fs_generic_bitmap_64 dest)
|
||||
{
|
||||
struct ext2fs_rb_private *src_bp, *dest_bp;
|
||||
struct bmap_rb_extent *src_ext, *dest_ext;
|
||||
struct rb_node *dest_node, *src_node, *dest_last, **n;
|
||||
errcode_t retval = 0;
|
||||
|
||||
retval = rb_alloc_private_data (dest);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
src_bp = (struct ext2fs_rb_private *) src->private;
|
||||
dest_bp = (struct ext2fs_rb_private *) dest->private;
|
||||
src_bp->rcursor = NULL;
|
||||
dest_bp->rcursor = NULL;
|
||||
|
||||
src_node = ext2fs_rb_first(&src_bp->root);
|
||||
while (src_node) {
|
||||
src_ext = node_to_extent(src_node);
|
||||
retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent),
|
||||
&dest_ext);
|
||||
if (retval)
|
||||
break;
|
||||
|
||||
memcpy(dest_ext, src_ext, sizeof(struct bmap_rb_extent));
|
||||
|
||||
dest_node = &dest_ext->node;
|
||||
n = &dest_bp->root.rb_node;
|
||||
|
||||
dest_last = NULL;
|
||||
if (*n) {
|
||||
dest_last = ext2fs_rb_last(&dest_bp->root);
|
||||
n = &(dest_last)->rb_right;
|
||||
}
|
||||
|
||||
ext2fs_rb_link_node(dest_node, dest_last, n);
|
||||
ext2fs_rb_insert_color(dest_node, &dest_bp->root);
|
||||
|
||||
src_node = ext2fs_rb_next(src_node);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rb_truncate(__u64 new_max, struct rb_root *root)
|
||||
{
|
||||
struct bmap_rb_extent *ext;
|
||||
struct rb_node *node;
|
||||
|
||||
node = ext2fs_rb_last(root);
|
||||
while (node) {
|
||||
ext = node_to_extent(node);
|
||||
|
||||
if ((ext->start + ext->count - 1) <= new_max)
|
||||
break;
|
||||
else if (ext->start > new_max) {
|
||||
ext2fs_rb_erase(node, root);
|
||||
ext2fs_free_mem(&ext);
|
||||
node = ext2fs_rb_last(root);
|
||||
continue;
|
||||
} else
|
||||
ext->count = new_max - ext->start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static errcode_t rb_resize_bmap(ext2fs_generic_bitmap_64 bmap,
|
||||
__u64 new_end, __u64 new_real_end)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bmap->private;
|
||||
bp->rcursor = NULL;
|
||||
bp->wcursor = NULL;
|
||||
|
||||
rb_truncate(((new_end < bmap->end) ? new_end : bmap->end) - bmap->start,
|
||||
&bp->root);
|
||||
|
||||
bmap->end = new_end;
|
||||
bmap->real_end = new_real_end;
|
||||
|
||||
if (bmap->end < bmap->real_end)
|
||||
rb_insert_extent(bmap->end + 1 - bmap->start,
|
||||
bmap->real_end - bmap->end, bp);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
inline static int
|
||||
rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit)
|
||||
{
|
||||
struct bmap_rb_extent *rcursor, *next_ext = NULL;
|
||||
struct rb_node *parent = NULL, *next;
|
||||
struct rb_node **n = &bp->root.rb_node;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
rcursor = bp->rcursor;
|
||||
if (!rcursor)
|
||||
goto search_tree;
|
||||
|
||||
if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) {
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bp->test_hit++;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
next_ext = bp->rcursor_next;
|
||||
if (!next_ext) {
|
||||
next = ext2fs_rb_next(&rcursor->node);
|
||||
if (next)
|
||||
next_ext = node_to_extent(next);
|
||||
bp->rcursor_next = next_ext;
|
||||
}
|
||||
if (next_ext) {
|
||||
if ((bit >= rcursor->start + rcursor->count) &&
|
||||
(bit < next_ext->start)) {
|
||||
#ifdef BMAP_STATS_OPS
|
||||
bp->test_hit++;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
bp->rcursor = NULL;
|
||||
bp->rcursor_next = NULL;
|
||||
|
||||
rcursor = bp->wcursor;
|
||||
if (!rcursor)
|
||||
goto search_tree;
|
||||
|
||||
if (bit >= rcursor->start && bit < rcursor->start + rcursor->count)
|
||||
return 1;
|
||||
|
||||
search_tree:
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (bit < ext->start)
|
||||
n = &(*n)->rb_left;
|
||||
else if (bit >= (ext->start + ext->count))
|
||||
n = &(*n)->rb_right;
|
||||
else {
|
||||
bp->rcursor = ext;
|
||||
bp->rcursor_next = NULL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rb_insert_extent(__u64 start, __u64 count,
|
||||
struct ext2fs_rb_private *bp)
|
||||
{
|
||||
struct rb_root *root = &bp->root;
|
||||
struct rb_node *parent = NULL, **n = &root->rb_node;
|
||||
struct rb_node *new_node, *node, *next;
|
||||
struct bmap_rb_extent *new_ext;
|
||||
struct bmap_rb_extent *ext;
|
||||
int retval = 0;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
bp->rcursor_next = NULL;
|
||||
ext = bp->wcursor;
|
||||
if (ext) {
|
||||
if (start >= ext->start &&
|
||||
start <= (ext->start + ext->count)) {
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bp->mark_hit++;
|
||||
#endif
|
||||
goto got_extent;
|
||||
}
|
||||
}
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start > (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else {
|
||||
got_extent:
|
||||
if ((start + count) <= (ext->start + ext->count))
|
||||
return 1;
|
||||
|
||||
if ((ext->start + ext->count) == start)
|
||||
retval = 0;
|
||||
else
|
||||
retval = 1;
|
||||
|
||||
count += (start - ext->start);
|
||||
start = ext->start;
|
||||
new_ext = ext;
|
||||
new_node = &ext->node;
|
||||
|
||||
goto skip_insert;
|
||||
}
|
||||
}
|
||||
|
||||
rb_get_new_extent(&new_ext, start, count);
|
||||
|
||||
new_node = &new_ext->node;
|
||||
ext2fs_rb_link_node(new_node, parent, n);
|
||||
ext2fs_rb_insert_color(new_node, root);
|
||||
bp->wcursor = new_ext;
|
||||
|
||||
node = ext2fs_rb_prev(new_node);
|
||||
if (node) {
|
||||
ext = node_to_extent(node);
|
||||
if ((ext->start + ext->count) == start) {
|
||||
start = ext->start;
|
||||
count += ext->count;
|
||||
ext2fs_rb_erase(node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
}
|
||||
}
|
||||
|
||||
skip_insert:
|
||||
/* See if we can merge extent to the right */
|
||||
for (node = ext2fs_rb_next(new_node); node != NULL; node = next) {
|
||||
next = ext2fs_rb_next(node);
|
||||
ext = node_to_extent(node);
|
||||
|
||||
if ((ext->start + ext->count) <= start)
|
||||
continue;
|
||||
|
||||
/* No more merging */
|
||||
if ((start + count) < ext->start)
|
||||
break;
|
||||
|
||||
/* ext is embedded in new_ext interval */
|
||||
if ((start + count) >= (ext->start + ext->count)) {
|
||||
ext2fs_rb_erase(node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
continue;
|
||||
} else {
|
||||
/* merge ext with new_ext */
|
||||
count += ((ext->start + ext->count) -
|
||||
(start + count));
|
||||
ext2fs_rb_erase(node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new_ext->start = start;
|
||||
new_ext->count = count;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rb_remove_extent(__u64 start, __u64 count,
|
||||
struct ext2fs_rb_private *bp)
|
||||
{
|
||||
struct rb_root *root = &bp->root;
|
||||
struct rb_node *parent = NULL, **n = &root->rb_node;
|
||||
struct rb_node *node;
|
||||
struct bmap_rb_extent *ext;
|
||||
__u64 new_start, new_count;
|
||||
int retval = 0;
|
||||
|
||||
if (ext2fs_rb_empty_root(root))
|
||||
return 0;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
continue;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((start > ext->start) &&
|
||||
(start + count) < (ext->start + ext->count)) {
|
||||
/* We have to split extent into two */
|
||||
new_start = start + count;
|
||||
new_count = (ext->start + ext->count) - new_start;
|
||||
|
||||
ext->count = start - ext->start;
|
||||
|
||||
rb_insert_extent(new_start, new_count, bp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((start + count) >= (ext->start + ext->count)) {
|
||||
ext->count = start - ext->start;
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
if (0 == ext->count) {
|
||||
parent = ext2fs_rb_next(&ext->node);
|
||||
ext2fs_rb_erase(&ext->node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
break;
|
||||
}
|
||||
|
||||
if (start == ext->start) {
|
||||
ext->start += count;
|
||||
ext->count -= count;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if we should delete or truncate extent on the right */
|
||||
for (; parent != NULL; parent = node) {
|
||||
node = ext2fs_rb_next(parent);
|
||||
ext = node_to_extent(parent);
|
||||
if ((ext->start + ext->count) <= start)
|
||||
continue;
|
||||
|
||||
/* No more extents to be removed/truncated */
|
||||
if ((start + count) < ext->start)
|
||||
break;
|
||||
|
||||
/* The entire extent is within the region to be removed */
|
||||
if ((start + count) >= (ext->start + ext->count)) {
|
||||
ext2fs_rb_erase(parent, root);
|
||||
rb_free_extent(bp, ext);
|
||||
retval = 1;
|
||||
continue;
|
||||
} else {
|
||||
/* modify the last extent in region to be removed */
|
||||
ext->count -= ((start + count) - ext->start);
|
||||
ext->start = start + count;
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rb_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
int retval;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
retval = rb_insert_extent(arg, 1, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rb_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
int retval;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
retval = rb_remove_extent(arg, 1, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline
|
||||
static int rb_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
return rb_test_bit(bp, arg);
|
||||
}
|
||||
|
||||
static void rb_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
rb_insert_extent(arg, num, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
static void rb_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
rb_remove_extent(arg, num, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, unsigned int len)
|
||||
{
|
||||
struct rb_node *parent = NULL, **n;
|
||||
struct rb_node *node, *next;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
int retval = 1;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
|
||||
if (len == 0 || ext2fs_rb_empty_root(&bp->root))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If we find nothing, we should examine whole extent, but
|
||||
* when we find match, the extent is not clean, thus be return
|
||||
* false.
|
||||
*/
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else {
|
||||
/*
|
||||
* We found extent int the tree -> extent is not
|
||||
* clean
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node = parent;
|
||||
while (node) {
|
||||
next = ext2fs_rb_next(node);
|
||||
ext = node_to_extent(node);
|
||||
node = next;
|
||||
|
||||
if ((ext->start + ext->count) <= start)
|
||||
continue;
|
||||
|
||||
/* No more merging */
|
||||
if ((start + len) <= ext->start)
|
||||
break;
|
||||
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *in)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
unsigned char *cp = in;
|
||||
size_t i;
|
||||
int first_set = -1;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((i & 7) == 0) {
|
||||
unsigned char c = cp[i/8];
|
||||
if (c == 0xFF) {
|
||||
if (first_set == -1)
|
||||
first_set = i;
|
||||
i += 7;
|
||||
continue;
|
||||
}
|
||||
if ((c == 0x00) && (first_set == -1)) {
|
||||
i += 7;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ext2fs_test_bit(i, in)) {
|
||||
if (first_set == -1)
|
||||
first_set = i;
|
||||
continue;
|
||||
}
|
||||
if (first_set == -1)
|
||||
continue;
|
||||
|
||||
rb_insert_extent(start + first_set - bitmap->start,
|
||||
i - first_set, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
first_set = -1;
|
||||
}
|
||||
if (first_set != -1) {
|
||||
rb_insert_extent(start + first_set - bitmap->start,
|
||||
num - first_set, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *out)
|
||||
{
|
||||
|
||||
struct rb_node *parent = NULL, *next, **n;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
__u64 count, pos;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
|
||||
if (ext2fs_rb_empty_root(&bp->root))
|
||||
return 0;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
memset(out, 0, (num + 7) >> 3);
|
||||
|
||||
for (; parent != NULL; parent = next) {
|
||||
next = ext2fs_rb_next(parent);
|
||||
ext = node_to_extent(parent);
|
||||
|
||||
pos = ext->start;
|
||||
count = ext->count;
|
||||
if (pos >= start + num)
|
||||
break;
|
||||
if (pos < start) {
|
||||
if (pos + count < start)
|
||||
continue;
|
||||
count -= start - pos;
|
||||
pos = start;
|
||||
}
|
||||
if (pos + count > start + num)
|
||||
count = start + num - pos;
|
||||
|
||||
while (count > 0) {
|
||||
if ((count >= 8) &&
|
||||
((pos - start) % 8) == 0) {
|
||||
int nbytes = count >> 3;
|
||||
int offset = (pos - start) >> 3;
|
||||
|
||||
memset(((char *) out) + offset, 0xFF, nbytes);
|
||||
pos += nbytes << 3;
|
||||
count -= nbytes << 3;
|
||||
continue;
|
||||
}
|
||||
ext2fs_fast_set_bit64((pos - start), out);
|
||||
pos++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rb_clear_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
rb_free_tree(&bp->root);
|
||||
bp->rcursor = NULL;
|
||||
bp->rcursor_next = NULL;
|
||||
bp->wcursor = NULL;
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
static errcode_t rb_find_first_zero(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
struct rb_node *parent = NULL, **n;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
end -= bitmap->start;
|
||||
|
||||
if (start > end)
|
||||
return EINVAL;
|
||||
|
||||
if (ext2fs_rb_empty_root(&bp->root))
|
||||
return ENOENT;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else if (ext->start + ext->count <= end) {
|
||||
*out = ext->start + ext->count + bitmap->start;
|
||||
return 0;
|
||||
} else
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
*out = start + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_find_first_set(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
struct rb_node *parent = NULL, **n;
|
||||
struct rb_node *node;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
end -= bitmap->start;
|
||||
|
||||
if (start > end)
|
||||
return EINVAL;
|
||||
|
||||
if (ext2fs_rb_empty_root(&bp->root))
|
||||
return ENOENT;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else {
|
||||
/* The start bit is set */
|
||||
*out = start + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node = parent;
|
||||
ext = node_to_extent(node);
|
||||
if (ext->start < start) {
|
||||
node = ext2fs_rb_next(node);
|
||||
if (node == NULL)
|
||||
return ENOENT;
|
||||
ext = node_to_extent(node);
|
||||
}
|
||||
if (ext->start <= end) {
|
||||
*out = ext->start + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct rb_node *node = NULL;
|
||||
struct bmap_rb_extent *ext;
|
||||
__u64 count = 0;
|
||||
__u64 max_size = 0;
|
||||
__u64 min_size = ULONG_MAX;
|
||||
__u64 size = 0, avg_size = 0;
|
||||
double eff;
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
__u64 mark_all, test_all;
|
||||
double m_hit = 0.0, t_hit = 0.0;
|
||||
#endif
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
for (node = ext2fs_rb_first(&bp->root); node != NULL;
|
||||
node = ext2fs_rb_next(node)) {
|
||||
ext = node_to_extent(node);
|
||||
count++;
|
||||
if (ext->count > max_size)
|
||||
max_size = ext->count;
|
||||
if (ext->count < min_size)
|
||||
min_size = ext->count;
|
||||
size += ext->count;
|
||||
}
|
||||
|
||||
if (count)
|
||||
avg_size = size / count;
|
||||
if (min_size == ULONG_MAX)
|
||||
min_size = 0;
|
||||
eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) /
|
||||
(bitmap->real_end - bitmap->start);
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count;
|
||||
test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count;
|
||||
if (mark_all)
|
||||
m_hit = ((double)bp->mark_hit / mark_all) * 100;
|
||||
if (test_all)
|
||||
t_hit = ((double)bp->test_hit / test_all) * 100;
|
||||
|
||||
fprintf(stderr, "%16llu cache hits on test (%.2f%%)\n"
|
||||
"%16llu cache hits on mark (%.2f%%)\n",
|
||||
bp->test_hit, t_hit, bp->mark_hit, m_hit);
|
||||
#endif
|
||||
fprintf(stderr, "%16llu extents (%llu bytes)\n",
|
||||
(unsigned long long) count, (unsigned long long)
|
||||
((count * sizeof(struct bmap_rb_extent)) +
|
||||
sizeof(struct ext2fs_rb_private)));
|
||||
fprintf(stderr, "%16llu bits minimum size\n",
|
||||
(unsigned long long) min_size);
|
||||
fprintf(stderr, "%16llu bits maximum size\n"
|
||||
"%16llu bits average size\n",
|
||||
(unsigned long long) max_size, (unsigned long long) avg_size);
|
||||
fprintf(stderr, "%16llu bits set in bitmap (out of %llu)\n",
|
||||
(unsigned long long) size,
|
||||
(unsigned long long) bitmap->real_end - bitmap->start);
|
||||
fprintf(stderr,
|
||||
"%16.4lf memory / bitmap bit memory ratio (bitarray = 1)\n",
|
||||
eff);
|
||||
}
|
||||
#else
|
||||
static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
|
||||
.type = EXT2FS_BMAP64_RBTREE,
|
||||
.new_bmap = rb_new_bmap,
|
||||
.free_bmap = rb_free_bmap,
|
||||
.copy_bmap = rb_copy_bmap,
|
||||
.resize_bmap = rb_resize_bmap,
|
||||
.mark_bmap = rb_mark_bmap,
|
||||
.unmark_bmap = rb_unmark_bmap,
|
||||
.test_bmap = rb_test_bmap,
|
||||
.test_clear_bmap_extent = rb_test_clear_bmap_extent,
|
||||
.mark_bmap_extent = rb_mark_bmap_extent,
|
||||
.unmark_bmap_extent = rb_unmark_bmap_extent,
|
||||
.set_bmap_range = rb_set_bmap_range,
|
||||
.get_bmap_range = rb_get_bmap_range,
|
||||
.clear_bmap = rb_clear_bmap,
|
||||
.print_stats = rb_print_stats,
|
||||
.find_first_zero = rb_find_first_zero,
|
||||
.find_first_set = rb_find_first_set,
|
||||
};
|
||||
606
jni/e2fsprogs/lib/ext2fs/blknum.c
Executable file
606
jni/e2fsprogs/lib/ext2fs/blknum.c
Executable file
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
* blknum.c --- Functions to handle blk64_t and high/low 64-bit block
|
||||
* number.
|
||||
*
|
||||
* Copyright IBM Corporation, 2007
|
||||
* Author Jose R. Santos <jrs@us.ibm.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* Return the group # of a block
|
||||
*/
|
||||
dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk)
|
||||
{
|
||||
return (blk - fs->super->s_first_data_block) /
|
||||
fs->super->s_blocks_per_group;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the first block (inclusive) in a group
|
||||
*/
|
||||
blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
return fs->super->s_first_data_block +
|
||||
EXT2_GROUPS_TO_BLOCKS(fs->super, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the last block (inclusive) in a group
|
||||
*/
|
||||
blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
return (group == fs->group_desc_count - 1 ?
|
||||
ext2fs_blocks_count(fs->super) - 1 :
|
||||
ext2fs_group_first_block2(fs, group) +
|
||||
(fs->super->s_blocks_per_group - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of blocks in a group
|
||||
*/
|
||||
int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
int num_blocks;
|
||||
|
||||
if (group == fs->group_desc_count - 1) {
|
||||
num_blocks = (ext2fs_blocks_count(fs->super) -
|
||||
fs->super->s_first_data_block) %
|
||||
fs->super->s_blocks_per_group;
|
||||
if (!num_blocks)
|
||||
num_blocks = fs->super->s_blocks_per_group;
|
||||
} else
|
||||
num_blocks = fs->super->s_blocks_per_group;
|
||||
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode data block count
|
||||
*/
|
||||
blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
|
||||
struct ext2_inode *inode)
|
||||
{
|
||||
return (inode->i_blocks |
|
||||
(ext2fs_has_feature_huge_file(fs->super) ?
|
||||
(__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) -
|
||||
(inode->i_file_acl ? EXT2_CLUSTER_SIZE(fs->super) >> 9 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode i_blocks count
|
||||
*/
|
||||
blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
|
||||
struct ext2_inode *inode)
|
||||
{
|
||||
return (inode->i_blocks |
|
||||
(ext2fs_has_feature_huge_file(fs->super) ?
|
||||
(__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode i_blocks in stat (512 byte) units
|
||||
*/
|
||||
blk64_t ext2fs_get_stat_i_blocks(ext2_filsys fs,
|
||||
struct ext2_inode *inode)
|
||||
{
|
||||
blk64_t ret = inode->i_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super)) {
|
||||
ret += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
|
||||
if (inode->i_flags & EXT4_HUGE_FILE_FL)
|
||||
ret *= (fs->blocksize / 512);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fs block count
|
||||
*/
|
||||
blk64_t ext2fs_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_blocks_count_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fs block count
|
||||
*/
|
||||
void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
super->s_blocks_count = blk;
|
||||
if (ext2fs_has_feature_64bit(super))
|
||||
super->s_blocks_count_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to the current fs block count
|
||||
*/
|
||||
void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
blk64_t tmp;
|
||||
tmp = ext2fs_blocks_count(super) + blk;
|
||||
ext2fs_blocks_count_set(super, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fs reserved block count
|
||||
*/
|
||||
blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_r_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_r_blocks_count_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fs reserved block count
|
||||
*/
|
||||
void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
super->s_r_blocks_count = blk;
|
||||
if (ext2fs_has_feature_64bit(super))
|
||||
super->s_r_blocks_count_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to the current reserved fs block count
|
||||
*/
|
||||
void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
blk64_t tmp;
|
||||
tmp = ext2fs_r_blocks_count(super) + blk;
|
||||
ext2fs_r_blocks_count_set(super, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fs free block count
|
||||
*/
|
||||
blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_free_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_free_blocks_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fs free block count
|
||||
*/
|
||||
void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
super->s_free_blocks_count = blk;
|
||||
if (ext2fs_has_feature_64bit(super))
|
||||
super->s_free_blocks_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to the current free fs block count
|
||||
*/
|
||||
void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
blk64_t tmp;
|
||||
tmp = ext2fs_free_blocks_count(super) + blk;
|
||||
ext2fs_free_blocks_count_set(super, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to a block group descriptor. We need the explicit
|
||||
* pointer to the group desc for code that swaps block group
|
||||
* descriptors before writing them out, as it wants to make a copy and
|
||||
* do the swap there.
|
||||
*/
|
||||
struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
|
||||
struct opaque_ext2_group_desc *gdp,
|
||||
dgrp_t group)
|
||||
{
|
||||
struct ext2_group_desc *ret_gdp;
|
||||
errcode_t retval;
|
||||
static char *buf = 0;
|
||||
static unsigned bufsize = 0;
|
||||
blk64_t blk;
|
||||
int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
|
||||
int desc_per_blk = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
|
||||
if (group > fs->group_desc_count)
|
||||
return NULL;
|
||||
if (gdp)
|
||||
return (struct ext2_group_desc *)((char *)gdp +
|
||||
group * desc_size);
|
||||
/*
|
||||
* If fs->group_desc wasn't read in when the file system was
|
||||
* opened, then read it on demand here.
|
||||
*/
|
||||
if (bufsize < fs->blocksize)
|
||||
ext2fs_free_mem(&buf);
|
||||
if (!buf) {
|
||||
retval = ext2fs_get_mem(fs->blocksize, &buf);
|
||||
if (retval)
|
||||
return NULL;
|
||||
bufsize = fs->blocksize;
|
||||
}
|
||||
blk = ext2fs_descriptor_block_loc2(fs, fs->super->s_first_data_block,
|
||||
group / desc_per_blk);
|
||||
retval = io_channel_read_blk(fs->io, blk, 1, buf);
|
||||
if (retval)
|
||||
return NULL;
|
||||
ret_gdp = (struct ext2_group_desc *)
|
||||
(buf + ((group % desc_per_blk) * desc_size));
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ext2fs_swap_group_desc2(fs, ret_gdp);
|
||||
#endif
|
||||
return ret_gdp;
|
||||
}
|
||||
|
||||
/* Do the same but as an ext4 group desc for internal use here */
|
||||
static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
|
||||
struct opaque_ext2_group_desc *gdp,
|
||||
dgrp_t group)
|
||||
{
|
||||
return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the block bitmap checksum of a group
|
||||
*/
|
||||
__u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
__u32 csum;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
csum = gdp->bg_block_bitmap_csum_lo;
|
||||
if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
|
||||
csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16);
|
||||
return csum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the block bitmap block of a group
|
||||
*/
|
||||
blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_block_bitmap |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u64)gdp->bg_block_bitmap_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the block bitmap block of a group
|
||||
*/
|
||||
void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_block_bitmap = blk;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode bitmap checksum of a group
|
||||
*/
|
||||
__u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
__u32 csum;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
csum = gdp->bg_inode_bitmap_csum_lo;
|
||||
if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
|
||||
csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16);
|
||||
return csum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode bitmap block of a group
|
||||
*/
|
||||
blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_inode_bitmap |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u64) gdp->bg_inode_bitmap_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the inode bitmap block of a group
|
||||
*/
|
||||
void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_inode_bitmap = blk;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_inode_bitmap_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode table block of a group
|
||||
*/
|
||||
blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_inode_table |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u64) gdp->bg_inode_table_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the inode table block of a group
|
||||
*/
|
||||
void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_inode_table = blk;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_inode_table_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the free blocks count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_free_blocks_count |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_free_blocks_count_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the free blocks count of a group
|
||||
*/
|
||||
void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_free_blocks_count = n;
|
||||
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_free_blocks_count_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the free inodes count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_free_inodes_count |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_free_inodes_count_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the free inodes count of a group
|
||||
*/
|
||||
void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_free_inodes_count = n;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_free_inodes_count_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the used dirs count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_used_dirs_count |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_used_dirs_count_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the used dirs count of a group
|
||||
*/
|
||||
void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_used_dirs_count = n;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_used_dirs_count_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the unused inodes count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_itable_unused |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_itable_unused_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the unused inodes count of a group
|
||||
*/
|
||||
void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_itable_unused = n;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_itable_unused_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the flags for this block group
|
||||
*/
|
||||
__u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero out the flags for this block group
|
||||
*/
|
||||
void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the value of a particular flag for this block group
|
||||
*/
|
||||
int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_flags & bg_flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a flag or set of flags for this block group
|
||||
*/
|
||||
void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_flags |= bg_flags;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear a flag or set of flags for this block group
|
||||
*/
|
||||
void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_flags &= ~bg_flags;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the checksum for this block group
|
||||
*/
|
||||
__u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_checksum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the checksum for this block group to a previously calculated value
|
||||
*/
|
||||
void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_checksum = checksum;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the acl block of a file
|
||||
*/
|
||||
blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode)
|
||||
{
|
||||
blk64_t blk = inode->i_file_acl;
|
||||
|
||||
if (fs && ext2fs_has_feature_64bit(fs->super))
|
||||
blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32;
|
||||
return blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the acl block of a file
|
||||
*/
|
||||
void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t blk)
|
||||
{
|
||||
inode->i_file_acl = blk;
|
||||
if (fs && ext2fs_has_feature_64bit(fs->super))
|
||||
inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the size of the inode
|
||||
*/
|
||||
errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode,
|
||||
ext2_off64_t size)
|
||||
{
|
||||
if (size < 0)
|
||||
return EINVAL;
|
||||
|
||||
/* If writing a large inode, set the large_file or large_dir flag */
|
||||
if (ext2fs_needs_large_file_feature(size)) {
|
||||
int dirty_sb = 0;
|
||||
|
||||
if (LINUX_S_ISREG(inode->i_mode)) {
|
||||
if (!ext2fs_has_feature_large_file(fs->super)) {
|
||||
ext2fs_set_feature_large_file(fs->super);
|
||||
dirty_sb = 1;
|
||||
}
|
||||
} else if (LINUX_S_ISDIR(inode->i_mode)) {
|
||||
if (!ext2fs_has_feature_largedir(fs->super)) {
|
||||
ext2fs_set_feature_largedir(fs->super);
|
||||
dirty_sb = 1;
|
||||
}
|
||||
} else {
|
||||
/* Only regular files get to be larger than 4GB */
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
}
|
||||
if (dirty_sb) {
|
||||
if (fs->super->s_rev_level == EXT2_GOOD_OLD_REV)
|
||||
ext2fs_update_dynamic_rev(fs);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
}
|
||||
|
||||
inode->i_size = size & 0xffffffff;
|
||||
inode->i_size_high = (size >> 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
659
jni/e2fsprogs/lib/ext2fs/block.c
Executable file
659
jni/e2fsprogs/lib/ext2fs/block.c
Executable file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t bcount,
|
||||
blk64_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;
|
||||
};
|
||||
|
||||
#define check_for_ro_violation_return(ctx, ret) \
|
||||
do { \
|
||||
if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
|
||||
((ret) & BLOCK_CHANGED)) { \
|
||||
(ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
|
||||
ret |= BLOCK_ABORT | BLOCK_ERROR; \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define check_for_ro_violation_goto(ctx, ret, label) \
|
||||
do { \
|
||||
if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
|
||||
((ret) & BLOCK_CHANGED)) { \
|
||||
(ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
|
||||
ret |= BLOCK_ABORT | BLOCK_ERROR; \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
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;
|
||||
blk64_t blk64;
|
||||
|
||||
limit = ctx->fs->blocksize >> 2;
|
||||
if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
|
||||
!(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
|
||||
blk64 = *ind_block;
|
||||
ret = (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_IND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*ind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
if (!*ind_block || (ret & BLOCK_ABORT)) {
|
||||
ctx->bcount += limit;
|
||||
return ret;
|
||||
}
|
||||
if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) ||
|
||||
*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++) {
|
||||
blk64 = *block_nr;
|
||||
flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
|
||||
*ind_block, offset,
|
||||
ctx->priv_data);
|
||||
*block_nr = blk64;
|
||||
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)
|
||||
goto skip_sparse;
|
||||
blk64 = *block_nr;
|
||||
flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
|
||||
*ind_block, offset,
|
||||
ctx->priv_data);
|
||||
*block_nr = blk64;
|
||||
changed |= flags;
|
||||
if (flags & BLOCK_ABORT) {
|
||||
ret |= BLOCK_ABORT;
|
||||
break;
|
||||
}
|
||||
skip_sparse:
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_return(ctx, changed);
|
||||
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)) {
|
||||
blk64 = *ind_block;
|
||||
ret |= (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_IND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*ind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
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;
|
||||
blk64_t blk64;
|
||||
|
||||
limit = ctx->fs->blocksize >> 2;
|
||||
if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
|
||||
BLOCK_FLAG_DATA_ONLY))) {
|
||||
blk64 = *dind_block;
|
||||
ret = (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_DIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*dind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
if (!*dind_block || (ret & BLOCK_ABORT)) {
|
||||
ctx->bcount += limit*limit;
|
||||
return ret;
|
||||
}
|
||||
if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) ||
|
||||
*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);
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_return(ctx, changed);
|
||||
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)) {
|
||||
blk64 = *dind_block;
|
||||
ret |= (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_DIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*dind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
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;
|
||||
blk64_t blk64;
|
||||
|
||||
limit = ctx->fs->blocksize >> 2;
|
||||
if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
|
||||
BLOCK_FLAG_DATA_ONLY))) {
|
||||
blk64 = *tind_block;
|
||||
ret = (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_TIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*tind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
if (!*tind_block || (ret & BLOCK_ABORT)) {
|
||||
ctx->bcount += ((unsigned long long) limit)*limit*limit;
|
||||
return ret;
|
||||
}
|
||||
if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) ||
|
||||
*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);
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_return(ctx, changed);
|
||||
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)) {
|
||||
blk64 = *tind_block;
|
||||
ret |= (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_TIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*tind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_block_iterate3(ext2_filsys fs,
|
||||
ext2_ino_t ino,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_t ref_blk,
|
||||
int ref_offset,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
int i;
|
||||
int r, ret = 0;
|
||||
struct ext2_inode inode;
|
||||
errcode_t retval;
|
||||
struct block_context ctx;
|
||||
int limit;
|
||||
blk64_t blk64;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (ctx.errcode)
|
||||
return ctx.errcode;
|
||||
|
||||
/*
|
||||
* An inode with inline data has no blocks over which to
|
||||
* iterate, so return an error code indicating this fact.
|
||||
*/
|
||||
if (inode.i_flags & EXT4_INLINE_DATA_FL)
|
||||
return EXT2_ET_INLINE_DATA_CANT_ITERATE;
|
||||
|
||||
/*
|
||||
* Check to see if we need to limit large files
|
||||
*/
|
||||
if (flags & BLOCK_FLAG_NO_LARGE) {
|
||||
if (!LINUX_S_ISDIR(inode.i_mode) &&
|
||||
(inode.i_size_high != 0))
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
}
|
||||
|
||||
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_array(3, fs->blocksize, &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)) {
|
||||
if (inode.osd1.hurd1.h_i_translator) {
|
||||
blk64 = inode.osd1.hurd1.h_i_translator;
|
||||
ret |= (*ctx.func)(fs, &blk64,
|
||||
BLOCK_COUNT_TRANSLATOR,
|
||||
0, 0, priv_data);
|
||||
inode.osd1.hurd1.h_i_translator = (blk_t) blk64;
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
check_for_ro_violation_goto(&ctx, ret, abort_exit);
|
||||
}
|
||||
}
|
||||
|
||||
if (inode.i_flags & EXT4_EXTENTS_FL) {
|
||||
ext2_extent_handle_t handle;
|
||||
struct ext2fs_extent extent, next;
|
||||
e2_blkcnt_t blockcnt = 0;
|
||||
blk64_t blk, new_blk;
|
||||
int op = EXT2_EXTENT_ROOT;
|
||||
int uninit;
|
||||
unsigned int j;
|
||||
|
||||
ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
|
||||
if (ctx.errcode)
|
||||
goto abort_exit;
|
||||
|
||||
while (1) {
|
||||
if (op == EXT2_EXTENT_CURRENT)
|
||||
ctx.errcode = 0;
|
||||
else
|
||||
ctx.errcode = ext2fs_extent_get(handle, op,
|
||||
&extent);
|
||||
if (ctx.errcode) {
|
||||
if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
|
||||
break;
|
||||
ctx.errcode = 0;
|
||||
if (!(flags & BLOCK_FLAG_APPEND))
|
||||
break;
|
||||
next_block_set:
|
||||
blk = 0;
|
||||
r = (*ctx.func)(fs, &blk, blockcnt,
|
||||
0, 0, priv_data);
|
||||
ret |= r;
|
||||
check_for_ro_violation_goto(&ctx, ret,
|
||||
extent_done);
|
||||
if (r & BLOCK_CHANGED) {
|
||||
ctx.errcode =
|
||||
ext2fs_extent_set_bmap(handle,
|
||||
(blk64_t) blockcnt++,
|
||||
(blk64_t) blk, 0);
|
||||
if (ctx.errcode || (ret & BLOCK_ABORT))
|
||||
break;
|
||||
if (blk)
|
||||
goto next_block_set;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
op = EXT2_EXTENT_NEXT;
|
||||
blk = extent.e_pblk;
|
||||
if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
|
||||
if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
|
||||
continue;
|
||||
if ((!(extent.e_flags &
|
||||
EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
|
||||
!(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
|
||||
((extent.e_flags &
|
||||
EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
|
||||
(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
|
||||
ret |= (*ctx.func)(fs, &blk,
|
||||
-1, 0, 0, priv_data);
|
||||
if (ret & BLOCK_CHANGED) {
|
||||
extent.e_pblk = blk;
|
||||
ctx.errcode =
|
||||
ext2fs_extent_replace(handle, 0, &extent);
|
||||
if (ctx.errcode)
|
||||
break;
|
||||
}
|
||||
if (ret & BLOCK_ABORT)
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
uninit = 0;
|
||||
if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
|
||||
|
||||
/*
|
||||
* Get the next extent before we start messing
|
||||
* with the current extent
|
||||
*/
|
||||
retval = ext2fs_extent_get(handle, op, &next);
|
||||
|
||||
#if 0
|
||||
printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
|
||||
extent.e_lblk, extent.e_pblk,
|
||||
extent.e_len, blockcnt);
|
||||
#endif
|
||||
if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
|
||||
continue;
|
||||
if (extent.e_lblk > (blk64_t) blockcnt)
|
||||
blockcnt = extent.e_lblk;
|
||||
j = blockcnt - extent.e_lblk;
|
||||
blk += j;
|
||||
for (blockcnt = extent.e_lblk, j = 0;
|
||||
j < extent.e_len;
|
||||
blk++, blockcnt++, j++) {
|
||||
new_blk = blk;
|
||||
r = (*ctx.func)(fs, &new_blk, blockcnt,
|
||||
0, 0, priv_data);
|
||||
ret |= r;
|
||||
check_for_ro_violation_goto(&ctx, ret,
|
||||
extent_done);
|
||||
if (r & BLOCK_CHANGED) {
|
||||
ctx.errcode =
|
||||
ext2fs_extent_set_bmap(handle,
|
||||
(blk64_t) blockcnt,
|
||||
new_blk, uninit);
|
||||
if (ctx.errcode)
|
||||
goto extent_done;
|
||||
}
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto extent_done;
|
||||
}
|
||||
if (retval == 0) {
|
||||
extent = next;
|
||||
op = EXT2_EXTENT_CURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
extent_done:
|
||||
ext2fs_extent_free(handle);
|
||||
ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over normal data blocks
|
||||
*/
|
||||
for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
|
||||
if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
blk64 = inode.i_block[i];
|
||||
ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i,
|
||||
priv_data);
|
||||
inode.i_block[i] = (blk_t) blk64;
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_goto(&ctx, ret, abort_exit);
|
||||
if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
|
||||
0, EXT2_IND_BLOCK, &ctx);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
} else
|
||||
ctx.bcount += limit;
|
||||
if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
|
||||
0, EXT2_DIND_BLOCK, &ctx);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
} else
|
||||
ctx.bcount += limit * limit;
|
||||
if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
|
||||
0, EXT2_TIND_BLOCK, &ctx);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
}
|
||||
|
||||
abort_exit:
|
||||
if (ret & BLOCK_CHANGED) {
|
||||
retval = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
ret |= BLOCK_ERROR;
|
||||
ctx.errcode = retval;
|
||||
}
|
||||
}
|
||||
errout:
|
||||
if (!block_buf)
|
||||
ext2fs_free_mem(&ctx.ind_buf);
|
||||
|
||||
return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate the old ext2fs_block_iterate function!
|
||||
*/
|
||||
|
||||
struct xlate64 {
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_blk,
|
||||
int ref_offset,
|
||||
void *priv_data);
|
||||
void *real_private;
|
||||
};
|
||||
|
||||
static int xlate64_func(ext2_filsys fs, blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt, blk64_t ref_blk,
|
||||
int ref_offset, void *priv_data)
|
||||
{
|
||||
struct xlate64 *xl = (struct xlate64 *) priv_data;
|
||||
int ret;
|
||||
blk_t block32 = *blocknr;
|
||||
|
||||
ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset,
|
||||
xl->real_private);
|
||||
*blocknr = block32;
|
||||
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)
|
||||
{
|
||||
struct xlate64 xl;
|
||||
|
||||
xl.real_private = priv_data;
|
||||
xl.func = func;
|
||||
|
||||
return ext2fs_block_iterate3(fs, ino, flags, block_buf,
|
||||
xlate64_func, &xl);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
499
jni/e2fsprogs/lib/ext2fs/bmap.c
Executable file
499
jni/e2fsprogs/lib/ext2fs/bmap.c
Executable file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
|
||||
#define _BMAP_INLINE_ __inline__
|
||||
#else
|
||||
#define _BMAP_INLINE_
|
||||
#endif
|
||||
|
||||
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 _BMAP_INLINE_ 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;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
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];
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
b = ext2fs_swab32(b);
|
||||
#endif
|
||||
|
||||
if (!b && (flags & BMAP_ALLOC)) {
|
||||
b = nr ? ext2fs_le32_to_cpu(((blk_t *)block_buf)[nr - 1]) : ind;
|
||||
retval = ext2fs_alloc_block(fs, b,
|
||||
block_buf + fs->blocksize, &b);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
|
||||
#else
|
||||
((blk_t *) block_buf)[nr] = b;
|
||||
#endif
|
||||
|
||||
retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
(*blocks_alloc)++;
|
||||
}
|
||||
|
||||
*ret_blk = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static _BMAP_INLINE_ 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 = 0;
|
||||
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 _BMAP_INLINE_ 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 = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
char *block_buf, int bmap_flags, blk64_t block,
|
||||
int *ret_flags, int *blocks_alloc,
|
||||
blk64_t *phys_blk);
|
||||
|
||||
static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
blk64_t lblk, blk64_t *phys_blk)
|
||||
{
|
||||
blk64_t base_block, pblock = 0;
|
||||
int i;
|
||||
|
||||
if (!ext2fs_has_feature_bigalloc(fs->super))
|
||||
return 0;
|
||||
|
||||
base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
/*
|
||||
* Except for the logical block (lblk) that was passed in, search all
|
||||
* blocks in this logical cluster for a mapping to a physical cluster.
|
||||
* If any such map exists, calculate the physical block that maps to
|
||||
* the logical block and return that.
|
||||
*
|
||||
* The old code wouldn't even look if (block % cluster_ratio) == 0;
|
||||
* this is incorrect if we're allocating blocks in reverse order.
|
||||
*/
|
||||
for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) {
|
||||
if (base_block + i == lblk)
|
||||
continue;
|
||||
extent_bmap(fs, ino, inode, handle, 0, 0,
|
||||
base_block + i, 0, 0, &pblock);
|
||||
if (pblock)
|
||||
break;
|
||||
}
|
||||
if (pblock == 0)
|
||||
return 0;
|
||||
*phys_blk = pblock - i + (lblk - base_block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to map a logical block to an already-allocated physical cluster. */
|
||||
errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t lblk,
|
||||
blk64_t *pblk)
|
||||
{
|
||||
ext2_extent_handle_t handle;
|
||||
errcode_t retval;
|
||||
|
||||
/* Need bigalloc and extents to be enabled */
|
||||
*pblk = 0;
|
||||
if (!ext2fs_has_feature_bigalloc(fs->super) ||
|
||||
!(inode->i_flags & EXT4_EXTENTS_FL))
|
||||
return 0;
|
||||
|
||||
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk);
|
||||
if (retval)
|
||||
goto out2;
|
||||
|
||||
out2:
|
||||
ext2fs_extent_free(handle);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
char *block_buf, int bmap_flags, blk64_t block,
|
||||
int *ret_flags, int *blocks_alloc,
|
||||
blk64_t *phys_blk)
|
||||
{
|
||||
struct blk_alloc_ctx alloc_ctx;
|
||||
struct ext2fs_extent extent;
|
||||
unsigned int offset;
|
||||
errcode_t retval = 0;
|
||||
blk64_t blk64 = 0;
|
||||
int alloc = 0;
|
||||
int set_flags;
|
||||
|
||||
set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0;
|
||||
|
||||
if (bmap_flags & BMAP_SET) {
|
||||
retval = ext2fs_extent_set_bmap(handle, block,
|
||||
*phys_blk, set_flags);
|
||||
return retval;
|
||||
}
|
||||
retval = ext2fs_extent_goto(handle, block);
|
||||
if (retval) {
|
||||
/* If the extent is not found, return phys_blk = 0 */
|
||||
if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
|
||||
extent.e_lblk = block;
|
||||
goto got_block;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
|
||||
if (retval)
|
||||
return retval;
|
||||
offset = block - extent.e_lblk;
|
||||
if (block >= extent.e_lblk && (offset <= extent.e_len)) {
|
||||
*phys_blk = extent.e_pblk + offset;
|
||||
if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
*ret_flags |= BMAP_RET_UNINIT;
|
||||
}
|
||||
got_block:
|
||||
if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
|
||||
implied_cluster_alloc(fs, ino, inode, handle, block, &blk64);
|
||||
if (blk64)
|
||||
goto set_extent;
|
||||
retval = extent_bmap(fs, ino, inode, handle, block_buf,
|
||||
0, block-1, 0, blocks_alloc, &blk64);
|
||||
if (retval)
|
||||
blk64 = ext2fs_find_inode_goal(fs, ino, inode, block);
|
||||
alloc_ctx.ino = ino;
|
||||
alloc_ctx.inode = inode;
|
||||
alloc_ctx.lblk = extent.e_lblk;
|
||||
alloc_ctx.flags = BLOCK_ALLOC_DATA;
|
||||
retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64,
|
||||
&alloc_ctx);
|
||||
if (retval)
|
||||
return retval;
|
||||
blk64 &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
blk64 += EXT2FS_CLUSTER_MASK(fs) & block;
|
||||
alloc++;
|
||||
set_extent:
|
||||
retval = ext2fs_extent_set_bmap(handle, block,
|
||||
blk64, set_flags);
|
||||
if (retval) {
|
||||
ext2fs_block_alloc_stats2(fs, blk64, -1);
|
||||
return retval;
|
||||
}
|
||||
/* Update inode after setting extent */
|
||||
retval = ext2fs_read_inode(fs, ino, inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
*blocks_alloc += alloc;
|
||||
*phys_blk = blk64;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2fs_file_block_offset_too_big(ext2_filsys fs,
|
||||
struct ext2_inode *inode,
|
||||
blk64_t offset)
|
||||
{
|
||||
blk64_t addr_per_block, max_map_block;
|
||||
|
||||
/* Kernel seems to cut us off at 4294967294 blocks */
|
||||
if (offset >= (1ULL << 32) - 1)
|
||||
return 1;
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL)
|
||||
return 0;
|
||||
|
||||
addr_per_block = fs->blocksize >> 2;
|
||||
max_map_block = addr_per_block;
|
||||
max_map_block += addr_per_block * addr_per_block;
|
||||
max_map_block += addr_per_block * addr_per_block * addr_per_block;
|
||||
max_map_block += 12;
|
||||
|
||||
return offset >= max_map_block;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
|
||||
char *block_buf, int bmap_flags, blk64_t block,
|
||||
int *ret_flags, blk64_t *phys_blk)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
ext2_extent_handle_t handle = 0;
|
||||
blk_t addr_per_block;
|
||||
blk_t b, blk32;
|
||||
blk64_t b64;
|
||||
char *buf = 0;
|
||||
errcode_t retval = 0;
|
||||
int blocks_alloc = 0, inode_dirty = 0;
|
||||
struct blk_alloc_ctx alloc_ctx = {
|
||||
.ino = ino,
|
||||
.inode = inode,
|
||||
.lblk = 0,
|
||||
.flags = BLOCK_ALLOC_DATA,
|
||||
};
|
||||
|
||||
if (!(bmap_flags & BMAP_SET))
|
||||
*phys_blk = 0;
|
||||
|
||||
if (ret_flags)
|
||||
*ret_flags = 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 (ext2fs_file_block_offset_too_big(fs, inode, block))
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
|
||||
/*
|
||||
* If an inode has inline data, that means that it doesn't have
|
||||
* any blocks and we shouldn't map any blocks for it.
|
||||
*/
|
||||
if (inode->i_flags & EXT4_INLINE_DATA_FL)
|
||||
return EXT2_ET_INLINE_DATA_NO_BLOCK;
|
||||
|
||||
if (!block_buf) {
|
||||
retval = ext2fs_get_array(2, fs->blocksize, &buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
block_buf = buf;
|
||||
}
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (retval)
|
||||
goto done;
|
||||
retval = extent_bmap(fs, ino, inode, handle, block_buf,
|
||||
bmap_flags, block, ret_flags,
|
||||
&blocks_alloc, phys_blk);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (block < EXT2_NDIR_BLOCKS) {
|
||||
if (bmap_flags & BMAP_SET) {
|
||||
b = *phys_blk;
|
||||
inode_bmap(inode, block) = b;
|
||||
inode_dirty++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*phys_blk = inode_bmap(inode, block);
|
||||
b = block ? inode_bmap(inode, block - 1) :
|
||||
ext2fs_find_inode_goal(fs, ino, inode, block);
|
||||
|
||||
if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
if (retval)
|
||||
goto done;
|
||||
inode_bmap(inode, block) = b;
|
||||
blocks_alloc++;
|
||||
*phys_blk = b;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Indirect block */
|
||||
block -= EXT2_NDIR_BLOCKS;
|
||||
blk32 = *phys_blk;
|
||||
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);
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
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, &blk32);
|
||||
if (retval == 0)
|
||||
*phys_blk = blk32;
|
||||
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);
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
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, &blk32);
|
||||
if (retval == 0)
|
||||
*phys_blk = blk32;
|
||||
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);
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
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, &blk32);
|
||||
if (retval == 0)
|
||||
*phys_blk = blk32;
|
||||
done:
|
||||
if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO))
|
||||
retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL);
|
||||
if (buf)
|
||||
ext2fs_free_mem(&buf);
|
||||
if (handle)
|
||||
ext2fs_extent_free(handle);
|
||||
if ((retval == 0) && (blocks_alloc || inode_dirty)) {
|
||||
ext2fs_iblk_add_blocks(fs, inode, blocks_alloc);
|
||||
retval = ext2fs_write_inode(fs, ino, inode);
|
||||
}
|
||||
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)
|
||||
{
|
||||
errcode_t ret;
|
||||
blk64_t ret_blk = *phys_blk;
|
||||
|
||||
ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block,
|
||||
0, &ret_blk);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret_blk >= ((long long) 1 << 32))
|
||||
return EOVERFLOW;
|
||||
*phys_blk = ret_blk;
|
||||
return 0;
|
||||
}
|
||||
167
jni/e2fsprogs/lib/ext2fs/bmove.c
Executable file
167
jni/e2fsprogs/lib/ext2fs/bmove.c
Executable file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* bmove.c --- Move blocks around to make way for a particular
|
||||
* filesystem structure.
|
||||
*
|
||||
* Copyright (C) 1997 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TIME_H
|
||||
#include <sys/time.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, blk64_t *block_nr,
|
||||
e2_blkcnt_t blockcnt, blk64_t ref_block,
|
||||
int ref_offset, void *priv_data)
|
||||
{
|
||||
struct process_block_struct *pb;
|
||||
errcode_t retval;
|
||||
int ret;
|
||||
blk64_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_bitmap2(pb->reserve, block)) {
|
||||
do {
|
||||
if (++block >= ext2fs_blocks_count(fs->super))
|
||||
block = fs->super->s_first_data_block;
|
||||
if (block == orig) {
|
||||
pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
} while (ext2fs_test_block_bitmap2(pb->reserve, block) ||
|
||||
ext2fs_test_block_bitmap2(pb->alloc_map, block));
|
||||
|
||||
retval = io_channel_read_blk64(fs->io, orig, 1, pb->buf);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, pb->buf);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
*block_nr = block;
|
||||
ext2fs_mark_block_bitmap2(pb->alloc_map, block);
|
||||
ret = BLOCK_CHANGED;
|
||||
if (pb->flags & EXT2_BMOVE_DEBUG)
|
||||
printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
|
||||
(unsigned) pb->ino, blockcnt,
|
||||
(unsigned long long) orig,
|
||||
(unsigned long long) block);
|
||||
}
|
||||
if (pb->add_dir) {
|
||||
retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
|
||||
block, 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_array(4, fs->blocksize, &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) {
|
||||
if (fs->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_blocks2(fs, &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_iterate3(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;
|
||||
}
|
||||
|
||||
199
jni/e2fsprogs/lib/ext2fs/brel_ma.c
Executable file
199
jni/e2fsprogs/lib/ext2fs/brel_ma.c
Executable file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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, blk64_t old,
|
||||
struct ext2_block_relocate_entry *ent);
|
||||
static errcode_t bma_get(ext2_brel brel, blk64_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, blk64_t *old,
|
||||
struct ext2_block_relocate_entry *ent);
|
||||
static errcode_t bma_move(ext2_brel brel, blk64_t old, blk64_t new);
|
||||
static errcode_t bma_delete(ext2_brel brel, blk64_t old);
|
||||
static errcode_t bma_free(ext2_brel brel);
|
||||
|
||||
struct brel_ma {
|
||||
__u32 magic;
|
||||
blk64_t max_block;
|
||||
struct ext2_block_relocate_entry *entries;
|
||||
};
|
||||
|
||||
errcode_t ext2fs_brel_memarray_create(char *name, blk64_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_array(max_block+1,
|
||||
sizeof(struct ext2_block_relocate_entry), &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, blk64_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, blk64_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, blk64_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, blk64_t old, blk64_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, blk64_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) {
|
||||
if (ma->entries)
|
||||
ext2fs_free_mem(&ma->entries);
|
||||
ext2fs_free_mem(&ma);
|
||||
}
|
||||
if (brel->name)
|
||||
ext2fs_free_mem(&brel->name);
|
||||
ext2fs_free_mem(&brel);
|
||||
return 0;
|
||||
}
|
||||
104
jni/e2fsprogs/lib/ext2fs/check_desc.c
Executable file
104
jni/e2fsprogs/lib/ext2fs/check_desc.c
Executable file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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)
|
||||
{
|
||||
ext2fs_block_bitmap bmap;
|
||||
errcode_t retval;
|
||||
dgrp_t i;
|
||||
blk64_t first_block = fs->super->s_first_data_block;
|
||||
blk64_t last_block = ext2fs_blocks_count(fs->super)-1;
|
||||
blk64_t blk, b;
|
||||
unsigned int j;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (EXT2_DESC_SIZE(fs->super) & (EXT2_DESC_SIZE(fs->super) - 1))
|
||||
return EXT2_ET_BAD_DESC_SIZE;
|
||||
|
||||
retval = ext2fs_allocate_subcluster_bitmap(fs, "check_desc map", &bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++)
|
||||
ext2fs_reserve_super_and_bgd(fs, i, bmap);
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
if (!ext2fs_has_feature_flex_bg(fs->super)) {
|
||||
first_block = ext2fs_group_first_block2(fs, i);
|
||||
last_block = ext2fs_group_last_block2(fs, i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to make sure the block bitmap for group is sane
|
||||
*/
|
||||
blk = ext2fs_block_bitmap_loc(fs, i);
|
||||
if (blk < first_block || blk > last_block ||
|
||||
ext2fs_test_block_bitmap2(bmap, blk)) {
|
||||
retval = EXT2_ET_GDESC_BAD_BLOCK_MAP;
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(bmap, blk);
|
||||
|
||||
/*
|
||||
* Check to make sure the inode bitmap for group is sane
|
||||
*/
|
||||
blk = ext2fs_inode_bitmap_loc(fs, i);
|
||||
if (blk < first_block || blk > last_block ||
|
||||
ext2fs_test_block_bitmap2(bmap, blk)) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_MAP;
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(bmap, blk);
|
||||
|
||||
/*
|
||||
* Check to make sure the inode table for group is sane
|
||||
*/
|
||||
blk = ext2fs_inode_table_loc(fs, i);
|
||||
if (blk < first_block ||
|
||||
((blk + fs->inode_blocks_per_group - 1) > last_block)) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
for (j = 0, b = blk; j < fs->inode_blocks_per_group;
|
||||
j++, b++) {
|
||||
if (ext2fs_test_block_bitmap2(bmap, b)) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(bmap, b);
|
||||
}
|
||||
}
|
||||
errout:
|
||||
ext2fs_free_block_bitmap(bmap);
|
||||
return retval;
|
||||
}
|
||||
521
jni/e2fsprogs/lib/ext2fs/closefs.c
Executable file
521
jni/e2fsprogs/lib/ext2fs/closefs.c
Executable file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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(unsigned int a, unsigned int b)
|
||||
{
|
||||
while (1) {
|
||||
if (a < b)
|
||||
return 0;
|
||||
if (a == b)
|
||||
return 1;
|
||||
if (a % b)
|
||||
return 0;
|
||||
a = a / b;
|
||||
}
|
||||
}
|
||||
|
||||
int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
if (group == 0)
|
||||
return 1;
|
||||
if (ext2fs_has_feature_sparse_super2(fs->super)) {
|
||||
if (group == fs->super->s_backup_bgs[0] ||
|
||||
group == fs->super->s_backup_bgs[1])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if ((group <= 1) || !ext2fs_has_feature_sparse_super(fs->super))
|
||||
return 1;
|
||||
if (!(group & 1))
|
||||
return 0;
|
||||
if (test_root(group, 3) || (test_root(group, 5)) ||
|
||||
test_root(group, 7))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext2fs_super_and_bgd_loc2()
|
||||
* @fs: ext2 fs pointer
|
||||
* @group given block group
|
||||
* @ret_super_blk: if !NULL, returns super block location
|
||||
* @ret_old_desc_blk: if !NULL, returns location of the old block
|
||||
* group descriptor
|
||||
* @ret_new_desc_blk: if !NULL, returns location of meta_bg block
|
||||
* group descriptor
|
||||
* @ret_used_blks: if !NULL, returns number of blocks used by
|
||||
* super block and group_descriptors.
|
||||
*
|
||||
* Returns errcode_t of 0
|
||||
*/
|
||||
errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs,
|
||||
dgrp_t group,
|
||||
blk64_t *ret_super_blk,
|
||||
blk64_t *ret_old_desc_blk,
|
||||
blk64_t *ret_new_desc_blk,
|
||||
blk_t *ret_used_blks)
|
||||
{
|
||||
blk64_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
|
||||
unsigned int meta_bg, meta_bg_size;
|
||||
blk_t numblocks = 0;
|
||||
blk64_t old_desc_blocks;
|
||||
int has_super;
|
||||
|
||||
group_block = ext2fs_group_first_block2(fs, group);
|
||||
if (group_block == 0 && fs->blocksize == 1024)
|
||||
group_block = 1; /* Deal with 1024 blocksize && bigalloc */
|
||||
|
||||
if (ext2fs_has_feature_meta_bg(fs->super))
|
||||
old_desc_blocks = fs->super->s_first_meta_bg;
|
||||
else
|
||||
old_desc_blocks =
|
||||
fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
|
||||
|
||||
has_super = ext2fs_bg_has_super(fs, group);
|
||||
|
||||
if (has_super) {
|
||||
super_blk = group_block;
|
||||
numblocks++;
|
||||
}
|
||||
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
meta_bg = group / meta_bg_size;
|
||||
|
||||
if (!ext2fs_has_feature_meta_bg(fs->super) ||
|
||||
(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++;
|
||||
}
|
||||
}
|
||||
|
||||
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_used_blks)
|
||||
*ret_used_blks = numblocks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the location of the superblock, block group
|
||||
* descriptors for a given block group. It currently returns the
|
||||
* number of free blocks assuming that inode table and allocation
|
||||
* bitmaps will be in the group. This is not necessarily the case
|
||||
* when the flex_bg feature is enabled, so callers should take care!
|
||||
* It was only really intended for use by mke2fs, and even there it's
|
||||
* not that useful.
|
||||
*
|
||||
* The ext2fs_super_and_bgd_loc2() function is 64-bit block number
|
||||
* capable and returns the number of blocks used by super block and
|
||||
* group descriptors.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
blk64_t ret_super_blk2;
|
||||
blk64_t ret_old_desc_blk2;
|
||||
blk64_t ret_new_desc_blk2;
|
||||
blk_t ret_used_blks;
|
||||
blk_t numblocks;
|
||||
unsigned int meta_bg_size;
|
||||
|
||||
ext2fs_super_and_bgd_loc2(fs, group, &ret_super_blk2,
|
||||
&ret_old_desc_blk2,
|
||||
&ret_new_desc_blk2,
|
||||
&ret_used_blks);
|
||||
|
||||
numblocks = ext2fs_group_blocks_count(fs, group);
|
||||
|
||||
if (ret_super_blk)
|
||||
*ret_super_blk = (blk_t)ret_super_blk2;
|
||||
if (ret_old_desc_blk)
|
||||
*ret_old_desc_blk = (blk_t)ret_old_desc_blk2;
|
||||
if (ret_new_desc_blk)
|
||||
*ret_new_desc_blk = (blk_t)ret_new_desc_blk2;
|
||||
if (ret_meta_bg) {
|
||||
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
*ret_meta_bg = group / meta_bg_size;
|
||||
}
|
||||
|
||||
numblocks -= 2 + fs->inode_blocks_per_group + ret_used_blks;
|
||||
|
||||
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) {
|
||||
fallback:
|
||||
io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
|
||||
retval = io_channel_write_blk64(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);
|
||||
#if 0
|
||||
printf("Writing %d bytes starting at %d\n",
|
||||
size, write_idx*2);
|
||||
#endif
|
||||
retval = io_channel_write_byte(fs->io,
|
||||
SUPERBLOCK_OFFSET + (2 * write_idx), size,
|
||||
new_super + write_idx);
|
||||
if (retval == EXT2_ET_UNIMPLEMENTED)
|
||||
goto fallback;
|
||||
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,
|
||||
blk64_t group_block,
|
||||
struct ext2_super_block *super_shadow)
|
||||
{
|
||||
errcode_t retval;
|
||||
dgrp_t sgrp = group;
|
||||
|
||||
if (sgrp > ((1 << 16) - 1))
|
||||
sgrp = (1 << 16) - 1;
|
||||
|
||||
super_shadow->s_block_group_nr = ext2fs_cpu_to_le16(sgrp);
|
||||
|
||||
retval = ext2fs_superblock_csum_set(fs, super_shadow);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE,
|
||||
super_shadow);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_flush(ext2_filsys fs)
|
||||
{
|
||||
return ext2fs_flush2(fs, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
|
||||
{
|
||||
dgrp_t i;
|
||||
errcode_t retval;
|
||||
unsigned long fs_state;
|
||||
__u32 feature_incompat;
|
||||
struct ext2_super_block *super_shadow = 0;
|
||||
struct opaque_ext2_group_desc *group_shadow = 0;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
struct ext2_group_desc *gdp;
|
||||
dgrp_t j;
|
||||
#endif
|
||||
char *group_ptr;
|
||||
blk64_t old_desc_blocks;
|
||||
struct ext2fs_numeric_progress_struct progress;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if ((fs->flags & EXT2_FLAG_SUPER_ONLY) == 0 &&
|
||||
!ext2fs_has_feature_journal_dev(fs->super) &&
|
||||
fs->group_desc == NULL)
|
||||
return EXT2_ET_NO_GDESC;
|
||||
|
||||
fs_state = fs->super->s_state;
|
||||
feature_incompat = fs->super->s_feature_incompat;
|
||||
|
||||
fs->super->s_wtime = fs->now ? fs->now : time(NULL);
|
||||
fs->super->s_block_group_nr = 0;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Bitmap checksums live in the group descriptor, so the
|
||||
* bitmaps need to be written before the descriptors.
|
||||
*/
|
||||
if (fs->write_bitmaps) {
|
||||
retval = fs->write_bitmaps(fs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
ext2fs_clear_feature_journal_needs_recovery(fs->super);
|
||||
|
||||
/* Byte swap the superblock and the group descriptors if necessary */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = EXT2_ET_NO_MEMORY;
|
||||
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block));
|
||||
ext2fs_swap_super(super_shadow);
|
||||
|
||||
if (((fs->flags & EXT2_FLAG_SUPER_ONLY) == 0) &&
|
||||
!ext2fs_has_feature_journal_dev(fs->super)) {
|
||||
retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
|
||||
&group_shadow);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize *
|
||||
fs->desc_blocks);
|
||||
|
||||
for (j = 0; j < fs->group_desc_count; j++) {
|
||||
gdp = ext2fs_group_desc(fs, group_shadow, j);
|
||||
ext2fs_swap_group_desc2(fs, gdp);
|
||||
}
|
||||
}
|
||||
#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 (ext2fs_has_feature_journal_dev(fs->super))
|
||||
goto write_primary_superblock_only;
|
||||
|
||||
/*
|
||||
* Write out the master group descriptors, and the backup
|
||||
* superblocks and group descriptors.
|
||||
*/
|
||||
group_ptr = (char *) group_shadow;
|
||||
if (ext2fs_has_feature_meta_bg(fs->super)) {
|
||||
old_desc_blocks = fs->super->s_first_meta_bg;
|
||||
if (old_desc_blocks > fs->desc_blocks)
|
||||
old_desc_blocks = fs->desc_blocks;
|
||||
} else
|
||||
old_desc_blocks = fs->desc_blocks;
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->init)
|
||||
(fs->progress_ops->init)(fs, &progress, NULL,
|
||||
fs->group_desc_count);
|
||||
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
blk64_t super_blk, old_desc_blk, new_desc_blk;
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->update)
|
||||
(fs->progress_ops->update)(fs, &progress, i);
|
||||
ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk,
|
||||
&new_desc_blk, 0);
|
||||
|
||||
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_blk64(fs->io,
|
||||
old_desc_blk, old_desc_blocks, group_ptr);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (new_desc_blk) {
|
||||
int meta_bg = i / EXT2_DESC_PER_BLOCK(fs->super);
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, new_desc_blk,
|
||||
1, group_ptr + (meta_bg*fs->blocksize));
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->close)
|
||||
(fs->progress_ops->close)(fs, &progress, NULL);
|
||||
|
||||
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....
|
||||
*/
|
||||
|
||||
fs->super->s_block_group_nr = 0;
|
||||
fs->super->s_state = fs_state;
|
||||
fs->super->s_feature_incompat = feature_incompat;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
*super_shadow = *fs->super;
|
||||
ext2fs_swap_super(super_shadow);
|
||||
#endif
|
||||
|
||||
retval = ext2fs_superblock_csum_set(fs, super_shadow);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) {
|
||||
retval = io_channel_flush(fs->io);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
retval = write_primary_superblock(fs, super_shadow);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
fs->flags &= ~EXT2_FLAG_DIRTY;
|
||||
|
||||
if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) {
|
||||
retval = io_channel_flush(fs->io);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
errout:
|
||||
fs->super->s_state = fs_state;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (super_shadow)
|
||||
ext2fs_free_mem(&super_shadow);
|
||||
if (group_shadow)
|
||||
ext2fs_free_mem(&group_shadow);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_close_free(ext2_filsys *fs_ptr)
|
||||
{
|
||||
errcode_t ret;
|
||||
ext2_filsys fs = *fs_ptr;
|
||||
|
||||
ret = ext2fs_close2(fs, 0);
|
||||
if (ret)
|
||||
ext2fs_free(fs);
|
||||
*fs_ptr = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_close(ext2_filsys fs)
|
||||
{
|
||||
return ext2fs_close2(fs, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_close2(ext2_filsys fs, int flags)
|
||||
{
|
||||
errcode_t retval;
|
||||
int meta_blks;
|
||||
io_stats stats = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (fs->write_bitmaps) {
|
||||
retval = fs->write_bitmaps(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (fs->super->s_kbytes_written &&
|
||||
fs->io->manager->get_stats)
|
||||
fs->io->manager->get_stats(fs->io, &stats);
|
||||
if (stats && stats->bytes_written && (fs->flags & EXT2_FLAG_RW)) {
|
||||
fs->super->s_kbytes_written += stats->bytes_written >> 10;
|
||||
meta_blks = fs->desc_blocks + 1;
|
||||
if (!(fs->flags & EXT2_FLAG_SUPER_ONLY))
|
||||
fs->super->s_kbytes_written += meta_blks /
|
||||
(fs->blocksize / 1024);
|
||||
if ((fs->flags & EXT2_FLAG_DIRTY) == 0)
|
||||
fs->flags |= EXT2_FLAG_SUPER_ONLY | EXT2_FLAG_DIRTY;
|
||||
}
|
||||
if (fs->flags & EXT2_FLAG_DIRTY) {
|
||||
retval = ext2fs_flush2(fs, flags);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_mmp_stop(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ext2fs_free(fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
74
jni/e2fsprogs/lib/ext2fs/crc16.c
Executable file
74
jni/e2fsprogs/lib/ext2fs/crc16.c
Executable file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* crc16.c
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <ext2fs/ext2_types.h>
|
||||
|
||||
#include "crc16.h"
|
||||
|
||||
/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
|
||||
static __u16 const crc16_table[256] = {
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the CRC-16 for the data buffer
|
||||
*
|
||||
* @param crc previous CRC value
|
||||
* @param buffer data pointer
|
||||
* @param len number of bytes in the buffer
|
||||
* @return the updated CRC value
|
||||
*/
|
||||
crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int len)
|
||||
{
|
||||
const unsigned char *cp = buffer;
|
||||
|
||||
while (len--)
|
||||
/*
|
||||
* for an unknown reason, PPC treats __u16 as signed
|
||||
* and keeps doing sign extension on the value.
|
||||
* Instead, use only the low 16 bits of an unsigned
|
||||
* int for holding the CRC value to avoid this.
|
||||
*/
|
||||
crc = (((crc >> 8) & 0xffU) ^
|
||||
crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
|
||||
return crc;
|
||||
}
|
||||
938
jni/e2fsprogs/lib/ext2fs/crc32c.c
Executable file
938
jni/e2fsprogs/lib/ext2fs/crc32c.c
Executable file
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* crc32c.c
|
||||
*
|
||||
* August 26, 2011 Darrick J. Wong <djwong at us.ibm.com>
|
||||
* Reuse Bob Pearson's slice-by-8 implementation for e2fsprogs.
|
||||
*
|
||||
* July 20, 2011 Bob Pearson <rpearson at systemfabricworks.com>
|
||||
* added slice by 8 algorithm to the existing conventional and
|
||||
* slice by 4 algorithms.
|
||||
*
|
||||
* Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks!
|
||||
* Code was from the public domain, copyright abandoned. Code was
|
||||
* subsequently included in the kernel, thus was re-licensed under the
|
||||
* GNU GPL v2.
|
||||
*
|
||||
* Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Same crc32 function was used in 5 other places in the kernel.
|
||||
* I made one version, and deleted the others.
|
||||
* There are various incantations of crc32(). Some use a seed of 0 or ~0.
|
||||
* Some xor at the end with ~0. The generic crc32() function takes
|
||||
* seed as an argument, and doesn't xor at the end. Then individual
|
||||
* users can do whatever they need.
|
||||
* drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
|
||||
* fs/jffs2 uses seed 0, doesn't xor with ~0.
|
||||
* fs/partitions/efi.c uses seed ~0, xor's with ~0.
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#define min(x, y) ((x) > (y) ? (y) : (x))
|
||||
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
|
||||
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
|
||||
#define PTR_ALIGN(p, a) ((__typeof__(p))ALIGN((unsigned long)(p), (a)))
|
||||
#include "crc32c_defs.h"
|
||||
|
||||
#include "ext2fs.h"
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define __constant_cpu_to_le32(x) ___constant_swab32((x))
|
||||
#define __constant_cpu_to_be32(x) (x)
|
||||
#define __be32_to_cpu(x) (x)
|
||||
#define __cpu_to_be32(x) (x)
|
||||
#define __cpu_to_le32(x) (ext2fs_cpu_to_le32((x)))
|
||||
#define __le32_to_cpu(x) (ext2fs_le32_to_cpu((x)))
|
||||
#else
|
||||
#define __constant_cpu_to_le32(x) (x)
|
||||
#define __constant_cpu_to_be32(x) ___constant_swab32((x))
|
||||
#define __be32_to_cpu(x) (ext2fs_be32_to_cpu((x)))
|
||||
#define __cpu_to_be32(x) (ext2fs_cpu_to_be32((x)))
|
||||
#define __cpu_to_le32(x) (x)
|
||||
#define __le32_to_cpu(x) (x)
|
||||
#endif
|
||||
|
||||
#if CRC_LE_BITS > 8
|
||||
# define tole(x) __constant_cpu_to_le32(x)
|
||||
#else
|
||||
# define tole(x) (x)
|
||||
#endif
|
||||
|
||||
#if CRC_BE_BITS > 8
|
||||
# define tobe(x) __constant_cpu_to_be32(x)
|
||||
#else
|
||||
# define tobe(x) (x)
|
||||
#endif
|
||||
|
||||
#include "crc32c_table.h"
|
||||
|
||||
#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8
|
||||
|
||||
#if CRC_LE_BITS < 64 && CRC_BE_BITS < 64
|
||||
#define CRC_INLINE inline
|
||||
#else
|
||||
#define CRC_INLINE
|
||||
#endif
|
||||
|
||||
/* implements slicing-by-4 or slicing-by-8 algorithm */
|
||||
static CRC_INLINE uint32_t
|
||||
crc32_body(uint32_t crc, unsigned char const *buf, size_t len,
|
||||
const uint32_t (*tab)[256])
|
||||
{
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# define DO_CRC(x) (crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8))
|
||||
# define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
|
||||
t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255])
|
||||
# define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \
|
||||
t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255])
|
||||
# else
|
||||
# define DO_CRC(x) (crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8))
|
||||
# define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \
|
||||
t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255])
|
||||
# define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \
|
||||
t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255])
|
||||
# endif
|
||||
const uint32_t *b;
|
||||
size_t rem_len;
|
||||
const uint32_t *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3];
|
||||
const uint32_t *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
|
||||
uint32_t q;
|
||||
|
||||
/* Align it */
|
||||
if (unlikely((uintptr_t)buf & 3 && len)) {
|
||||
do {
|
||||
DO_CRC(*buf++);
|
||||
} while ((--len) && ((uintptr_t)buf)&3);
|
||||
}
|
||||
|
||||
# if CRC_LE_BITS == 32
|
||||
rem_len = len & 3;
|
||||
len = len >> 2;
|
||||
# else
|
||||
rem_len = len & 7;
|
||||
len = len >> 3;
|
||||
# endif
|
||||
|
||||
b = (const uint32_t *)buf;
|
||||
for (--b; len; --len) {
|
||||
q = crc ^ *++b; /* use pre increment for speed */
|
||||
# if CRC_LE_BITS == 32
|
||||
crc = DO_CRC4;
|
||||
# else
|
||||
crc = DO_CRC8;
|
||||
q = *++b;
|
||||
crc ^= DO_CRC4;
|
||||
# endif
|
||||
}
|
||||
len = rem_len;
|
||||
/* And the last few bytes */
|
||||
if (len) {
|
||||
const uint8_t *p = (const uint8_t *)(b + 1) - 1;
|
||||
do {
|
||||
DO_CRC(*++p); /* use pre increment for speed */
|
||||
} while (--len);
|
||||
}
|
||||
return crc;
|
||||
#undef DO_CRC
|
||||
#undef DO_CRC4
|
||||
#undef DO_CRC8
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
|
||||
* @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p: pointer to buffer over which CRC is run
|
||||
* @len: length of buffer @p
|
||||
*/
|
||||
static inline uint32_t crc32_le_generic(uint32_t crc, unsigned char const *p,
|
||||
size_t len, const uint32_t (*tab)[256],
|
||||
uint32_t polynomial EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#if CRC_LE_BITS == 1
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
|
||||
}
|
||||
# elif CRC_LE_BITS == 2
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
}
|
||||
# elif CRC_LE_BITS == 4
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 4) ^ tab[0][crc & 15];
|
||||
crc = (crc >> 4) ^ tab[0][crc & 15];
|
||||
}
|
||||
# elif CRC_LE_BITS == 8
|
||||
/* aka Sarwate algorithm */
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 8) ^ tab[0][crc & 255];
|
||||
}
|
||||
# else
|
||||
crc = __cpu_to_le32(crc);
|
||||
crc = crc32_body(crc, p, len, tab);
|
||||
crc = __le32_to_cpu(crc);
|
||||
#endif
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE);
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
|
||||
* @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p: pointer to buffer over which CRC is run
|
||||
* @len: length of buffer @p
|
||||
*/
|
||||
static inline uint32_t crc32_be_generic(uint32_t crc, unsigned char const *p,
|
||||
size_t len, const uint32_t (*tab)[256],
|
||||
uint32_t polynomial EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#if CRC_BE_BITS == 1
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc =
|
||||
(crc << 1) ^ ((crc & 0x80000000) ? polynomial :
|
||||
0);
|
||||
}
|
||||
# elif CRC_BE_BITS == 2
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
}
|
||||
# elif CRC_BE_BITS == 4
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 4) ^ tab[0][crc >> 28];
|
||||
crc = (crc << 4) ^ tab[0][crc >> 28];
|
||||
}
|
||||
# elif CRC_BE_BITS == 8
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 8) ^ tab[0][crc >> 24];
|
||||
}
|
||||
# else
|
||||
crc = __cpu_to_be32(crc);
|
||||
crc = crc32_body(crc, p, len, tab);
|
||||
crc = __be32_to_cpu(crc);
|
||||
# endif
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t ext2fs_crc32_be(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
static uint8_t test_buf[] = {
|
||||
0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48,
|
||||
0xda, 0xad, 0x14, 0xbd, 0x03, 0x3a, 0x58, 0x5e,
|
||||
0x6e, 0xd1, 0x56, 0xc9, 0x2e, 0xc4, 0xcb, 0x6b,
|
||||
0xe8, 0x77, 0x52, 0x37, 0x4e, 0x0f, 0x55, 0xd2,
|
||||
0x12, 0x65, 0x90, 0xc2, 0x41, 0x49, 0x81, 0x01,
|
||||
0xf5, 0x01, 0xeb, 0x2d, 0x78, 0x74, 0x23, 0x5d,
|
||||
0x84, 0x5c, 0x81, 0x92, 0x21, 0xe9, 0x8d, 0x1d,
|
||||
0x89, 0xf2, 0x4a, 0xac, 0xdd, 0xf9, 0xaf, 0xee,
|
||||
0x44, 0xe7, 0x6e, 0xed, 0xfb, 0xd8, 0x89, 0x0e,
|
||||
0x96, 0x62, 0xcd, 0xa4, 0x4b, 0xa9, 0xe5, 0x45,
|
||||
0xb1, 0x29, 0x9b, 0x0f, 0xfc, 0xbd, 0x83, 0xab,
|
||||
0xa8, 0x54, 0x96, 0x44, 0x2c, 0x7f, 0xbb, 0xe7,
|
||||
0x52, 0x29, 0x08, 0xee, 0x14, 0xc5, 0xc2, 0xec,
|
||||
0x5a, 0xeb, 0x40, 0x40, 0xea, 0xd1, 0x3d, 0x15,
|
||||
0x73, 0xaa, 0x8c, 0x73, 0xfc, 0xf2, 0x2b, 0x49,
|
||||
0x0b, 0x13, 0x96, 0xd9, 0x8e, 0x4b, 0xbc, 0xe0,
|
||||
0xf4, 0xd2, 0xe0, 0x2e, 0x7a, 0xf0, 0x5d, 0x1f,
|
||||
0xd2, 0x92, 0x97, 0xe0, 0xaa, 0x59, 0xab, 0xc9,
|
||||
0x5c, 0xa6, 0x51, 0x1a, 0xe3, 0xd6, 0x06, 0xb9,
|
||||
0xae, 0xb8, 0x76, 0x36, 0x79, 0x37, 0x52, 0xf6,
|
||||
0x34, 0xaf, 0x27, 0x19, 0xe1, 0xc0, 0x2b, 0xdd,
|
||||
0x01, 0x15, 0xcd, 0xce, 0x44, 0xf6, 0x4c, 0x18,
|
||||
0x92, 0x69, 0xbe, 0x8a, 0x76, 0x23, 0x52, 0x13,
|
||||
0x3f, 0xf9, 0xe0, 0xf5, 0x06, 0x28, 0x7c, 0xc7,
|
||||
0xf3, 0x42, 0x0f, 0xdd, 0x40, 0x33, 0xf7, 0x99,
|
||||
0xe2, 0xad, 0x26, 0xd9, 0x53, 0x10, 0x72, 0x0c,
|
||||
0x4e, 0x43, 0x4c, 0x61, 0xfe, 0xd9, 0xc1, 0x16,
|
||||
0xa1, 0x93, 0xca, 0x3c, 0x75, 0x7f, 0x07, 0x7a,
|
||||
0x65, 0xb3, 0x53, 0x2a, 0x52, 0x00, 0xa0, 0x62,
|
||||
0xe0, 0xa3, 0x1f, 0xad, 0xd7, 0xbb, 0xc0, 0x83,
|
||||
0x5d, 0x54, 0x87, 0x5f, 0xc8, 0x2f, 0xc8, 0xbf,
|
||||
0x69, 0x04, 0x91, 0xc8, 0xa6, 0x1d, 0x4d, 0x46,
|
||||
0x91, 0xfc, 0x26, 0xf4, 0x16, 0xd1, 0xa4, 0xbf,
|
||||
0x5c, 0xa2, 0x6c, 0xdd, 0xb4, 0x40, 0xf2, 0x2e,
|
||||
0xa2, 0xad, 0xf7, 0xf4, 0xa5, 0x8a, 0x3e, 0x23,
|
||||
0x64, 0x08, 0xc8, 0xa1, 0xa0, 0xf0, 0x5d, 0x70,
|
||||
0xd2, 0x77, 0xfd, 0xc8, 0x50, 0x83, 0x0f, 0xd6,
|
||||
0x2b, 0xe4, 0x1f, 0x52, 0x34, 0x33, 0x68, 0xfd,
|
||||
0x92, 0xbe, 0x9f, 0x97, 0x6b, 0x8d, 0x81, 0x91,
|
||||
0x0f, 0xef, 0x65, 0xc8, 0x0d, 0x15, 0x01, 0x77,
|
||||
0x58, 0xb2, 0xf4, 0x1b, 0x06, 0x7e, 0xf5, 0xca,
|
||||
0x15, 0x2e, 0x38, 0xd8, 0x81, 0x1c, 0x1c, 0xa0,
|
||||
0xb6, 0x13, 0x6a, 0x2b, 0x71, 0x34, 0x52, 0xd7,
|
||||
0x1d, 0xbd, 0x37, 0x59, 0xbc, 0x86, 0x25, 0x2b,
|
||||
0xa8, 0x93, 0xce, 0x1a, 0x03, 0x16, 0xfe, 0x01,
|
||||
0x57, 0x99, 0x24, 0x25, 0x2c, 0xb3, 0xab, 0x1e,
|
||||
0x2d, 0x65, 0x20, 0x89, 0x17, 0x02, 0x0e, 0x0a,
|
||||
0xf5, 0x1e, 0xc7, 0xff, 0x1f, 0x61, 0xa9, 0x54,
|
||||
0x18, 0xd4, 0xba, 0x50, 0x57, 0x02, 0xa1, 0xab,
|
||||
0x22, 0x2e, 0x07, 0xea, 0xa9, 0xa3, 0x83, 0x4f,
|
||||
0x27, 0xf5, 0xc5, 0xee, 0x3c, 0x3b, 0x10, 0xad,
|
||||
0x32, 0x2b, 0x1c, 0x03, 0xcb, 0xaf, 0x98, 0x83,
|
||||
0x54, 0xc3, 0x68, 0x63, 0xd4, 0xe0, 0x0e, 0x3c,
|
||||
0x1a, 0x4e, 0xc0, 0x81, 0xd0, 0xe8, 0x6a, 0x62,
|
||||
0x6b, 0x3e, 0x6f, 0xc4, 0xc6, 0x33, 0x4e, 0x26,
|
||||
0x21, 0xf5, 0x04, 0xdf, 0xfa, 0xce, 0x45, 0xaf,
|
||||
0xdc, 0x5e, 0x1b, 0xad, 0x93, 0xca, 0xf5, 0xcf,
|
||||
0xd7, 0xee, 0x0c, 0x5c, 0x5e, 0xb4, 0xf0, 0x92,
|
||||
0xd2, 0xf2, 0xf0, 0xa9, 0x1e, 0xab, 0x80, 0x68,
|
||||
0x46, 0xef, 0xcc, 0x26, 0x0c, 0x5c, 0xdd, 0x4e,
|
||||
0x83, 0xb8, 0xb9, 0x53, 0x6e, 0xf8, 0x93, 0x38,
|
||||
0x67, 0xa4, 0x41, 0x87, 0x72, 0xe7, 0x7e, 0x86,
|
||||
0xc9, 0x49, 0x00, 0x33, 0xb1, 0x38, 0x6c, 0x71,
|
||||
0xd7, 0x1d, 0x8e, 0x61, 0x01, 0xb6, 0x57, 0xa9,
|
||||
0xf1, 0xac, 0x15, 0xc2, 0x83, 0x77, 0xca, 0x64,
|
||||
0xca, 0x7b, 0x6c, 0xa1, 0x10, 0x1b, 0x13, 0xd0,
|
||||
0xd3, 0x9e, 0x9e, 0x10, 0x70, 0xc8, 0x1a, 0xbb,
|
||||
0x3f, 0x19, 0x86, 0xab, 0x01, 0x0e, 0xea, 0x34,
|
||||
0x22, 0xea, 0xe2, 0x15, 0xb7, 0xed, 0x21, 0x21,
|
||||
0x75, 0xa5, 0xe7, 0x08, 0xa1, 0x38, 0xe0, 0x91,
|
||||
0x05, 0x60, 0xea, 0xa7, 0x50, 0x27, 0x18, 0x07,
|
||||
0x9d, 0xe0, 0x18, 0x2b, 0xd4, 0x07, 0x59, 0x00,
|
||||
0xe6, 0x45, 0x18, 0x2a, 0x30, 0x6e, 0xf3, 0xb4,
|
||||
0xd0, 0xef, 0xa6, 0x5b, 0x71, 0xa2, 0x5a, 0x3b,
|
||||
0x89, 0x4c, 0xaf, 0x3f, 0xcb, 0x9f, 0x03, 0xfb,
|
||||
0x43, 0x7c, 0x6b, 0xd3, 0x6a, 0xea, 0xce, 0x4a,
|
||||
0x5f, 0x64, 0xb5, 0x62, 0xda, 0x5d, 0x27, 0xb7,
|
||||
0xb8, 0x11, 0xca, 0x33, 0x30, 0xec, 0x70, 0xf0,
|
||||
0x1b, 0x03, 0x50, 0xff, 0x5e, 0xa6, 0x08, 0xde,
|
||||
0x37, 0x70, 0xc0, 0x81, 0x55, 0x60, 0x17, 0xa1,
|
||||
0x85, 0xae, 0x26, 0x44, 0xe4, 0x67, 0x3c, 0x91,
|
||||
0xfd, 0xc4, 0x3d, 0x97, 0x72, 0x23, 0xf3, 0x3c,
|
||||
0x8f, 0xe0, 0xe2, 0xf2, 0x09, 0x96, 0x10, 0x67,
|
||||
0xb5, 0xfe, 0xff, 0x3d, 0x4a, 0xc8, 0x62, 0x11,
|
||||
0xa5, 0x98, 0xc1, 0x2d, 0x40, 0x82, 0x88, 0x8b,
|
||||
0xe5, 0xb0, 0x75, 0xbf, 0x2f, 0xa8, 0x6a, 0x55,
|
||||
0x49, 0x2e, 0x9c, 0x29, 0xd2, 0x7c, 0xbf, 0xf3,
|
||||
0xaa, 0x3a, 0x16, 0x4a, 0xa4, 0x15, 0xf3, 0x48,
|
||||
0xde, 0x38, 0x13, 0x44, 0x26, 0x02, 0xe6, 0xe9,
|
||||
0xa8, 0x24, 0x89, 0xb5, 0x43, 0x95, 0xe4, 0x4c,
|
||||
0xc3, 0xa0, 0xdf, 0xcc, 0x42, 0xf8, 0x8d, 0xb0,
|
||||
0x3b, 0xea, 0x10, 0xb7, 0xe1, 0x40, 0x54, 0xb9,
|
||||
0xa3, 0x2d, 0xfb, 0xb4, 0x91, 0xc0, 0x3e, 0x94,
|
||||
0xf1, 0xa1, 0x3c, 0xbe, 0xef, 0xb8, 0x70, 0x55,
|
||||
0x0a, 0x26, 0x93, 0xbf, 0xe6, 0x21, 0x92, 0x32,
|
||||
0x3c, 0x39, 0x27, 0x6a, 0x23, 0x48, 0x02, 0x35,
|
||||
0x3c, 0xd4, 0xcc, 0x04, 0xc0, 0x4e, 0xa7, 0x02,
|
||||
0x63, 0x37, 0xc2, 0xb8, 0x56, 0x1d, 0x57, 0x57,
|
||||
0x42, 0x04, 0x8d, 0xee, 0xcf, 0x8b, 0xc9, 0xc3,
|
||||
0xba, 0x3b, 0x15, 0xd7, 0xaf, 0xbf, 0x9e, 0xcd,
|
||||
0x44, 0xcf, 0xf0, 0x00, 0xb7, 0x3a, 0xfc, 0xa8,
|
||||
0x12, 0xab, 0x3a, 0x62, 0x01, 0x21, 0x46, 0xe9,
|
||||
0x1e, 0x48, 0x37, 0xfc, 0x13, 0x4d, 0xf6, 0x2a,
|
||||
0x72, 0x40, 0x75, 0x38, 0x71, 0xf2, 0x17, 0x20,
|
||||
0x2c, 0xdd, 0xc0, 0x49, 0xbc, 0x63, 0x33, 0xea,
|
||||
0x06, 0x75, 0x41, 0xe7, 0x5c, 0x1f, 0xfb, 0xf9,
|
||||
0x68, 0x83, 0xc2, 0x5a, 0x4a, 0x1e, 0x61, 0x08,
|
||||
0x57, 0xf3, 0x00, 0xba, 0x77, 0x92, 0x63, 0xa5,
|
||||
0xb7, 0xfe, 0x97, 0x22, 0xda, 0x5e, 0xd3, 0xaf,
|
||||
0xbc, 0x89, 0x0d, 0x4c, 0x37, 0xa9, 0x27, 0x4a,
|
||||
0x7f, 0xdb, 0x81, 0x39, 0x11, 0x86, 0x12, 0xf9,
|
||||
0x10, 0x50, 0xe4, 0xdb, 0x72, 0xf9, 0xae, 0x10,
|
||||
0x7c, 0xed, 0x50, 0x5c, 0x61, 0xeb, 0x42, 0x1e,
|
||||
0xa4, 0xf4, 0xf0, 0xfa, 0x45, 0x4d, 0x95, 0x2b,
|
||||
0xd4, 0x67, 0x4a, 0xe3, 0x8a, 0x15, 0x55, 0x92,
|
||||
0x77, 0x64, 0x8c, 0x51, 0x38, 0xf9, 0x26, 0x3e,
|
||||
0x68, 0xe2, 0xac, 0xbb, 0x64, 0x77, 0xe2, 0x82,
|
||||
0xa4, 0x42, 0x41, 0x38, 0xa0, 0xf0, 0xc9, 0xd8,
|
||||
0x6c, 0xe0, 0xef, 0x4c, 0xda, 0xb4, 0x92, 0xef,
|
||||
0x1b, 0xe3, 0x9b, 0xc1, 0x44, 0x3c, 0xb9, 0xb7,
|
||||
0x39, 0xac, 0x5c, 0x32, 0x39, 0xb4, 0x21, 0x85,
|
||||
0x93, 0xbc, 0xf2, 0x51, 0x43, 0xb7, 0xae, 0x1e,
|
||||
0x61, 0x9c, 0x38, 0x9c, 0xaa, 0xff, 0xde, 0xfc,
|
||||
0xbf, 0x85, 0xef, 0x17, 0x34, 0x36, 0x71, 0x5f,
|
||||
0x04, 0x16, 0xa6, 0x9e, 0xfd, 0x3a, 0x03, 0xd8,
|
||||
0xbf, 0x71, 0x70, 0x20, 0x8f, 0x7c, 0xfb, 0xff,
|
||||
0x61, 0xe0, 0xe2, 0x60, 0xa7, 0xb1, 0xc0, 0xe0,
|
||||
0xd9, 0x3f, 0xdc, 0x8d, 0x4a, 0xa4, 0x52, 0x61,
|
||||
0xaf, 0x9d, 0xdf, 0x8a, 0x0d, 0x41, 0xc0, 0x25,
|
||||
0x68, 0x12, 0x7b, 0xd5, 0xc7, 0xdb, 0x68, 0x70,
|
||||
0x2d, 0x7d, 0x95, 0x12, 0x03, 0x23, 0x0c, 0xe8,
|
||||
0x14, 0x41, 0x11, 0x28, 0xec, 0x9d, 0xd3, 0x28,
|
||||
0x77, 0x7a, 0x3c, 0x93, 0x8e, 0x5c, 0x7e, 0xb3,
|
||||
0x42, 0x9a, 0x18, 0x25, 0x93, 0xc8, 0xea, 0x43,
|
||||
0x1b, 0xbe, 0xd5, 0x27, 0xf1, 0xd4, 0xe0, 0x1e,
|
||||
0xce, 0xc7, 0xc7, 0x2c, 0x25, 0x35, 0x58, 0xb8,
|
||||
0x6c, 0xf3, 0xa2, 0xad, 0xe7, 0x58, 0x49, 0x47,
|
||||
0xf7, 0xca, 0xde, 0x8b, 0x81, 0xb7, 0x75, 0xf4,
|
||||
0x95, 0xa7, 0x5c, 0xc3, 0x2c, 0x0e, 0x1c, 0x52,
|
||||
0x9a, 0xc3, 0x2a, 0x00, 0x21, 0xa7, 0x51, 0x6b,
|
||||
0xf0, 0x05, 0x87, 0x8c, 0x42, 0x1b, 0xc3, 0x2e,
|
||||
0xa3, 0x76, 0x22, 0xd5, 0x7f, 0x56, 0x10, 0xef,
|
||||
0x98, 0x85, 0x65, 0x86, 0x71, 0x87, 0xd2, 0x8c,
|
||||
0xc0, 0x47, 0x20, 0xe8, 0xb5, 0x1c, 0xe3, 0xdd,
|
||||
0x3c, 0x5c, 0x03, 0xbb, 0x0e, 0x97, 0x3b, 0xe1,
|
||||
0x56, 0x9a, 0xd5, 0x0a, 0x63, 0xd5, 0x33, 0xaf,
|
||||
0x36, 0xca, 0xcf, 0x8f, 0x00, 0x28, 0xa3, 0x45,
|
||||
0xb8, 0xcd, 0xde, 0x73, 0xd4, 0xfa, 0x2d, 0x6f,
|
||||
0xdb, 0x93, 0xaa, 0xdd, 0x7f, 0xd2, 0x22, 0x9c,
|
||||
0x96, 0x48, 0x1e, 0xa8, 0x63, 0xbe, 0xbc, 0x0d,
|
||||
0x14, 0x3c, 0x2e, 0x11, 0x1f, 0xd2, 0xf4, 0x57,
|
||||
0xb3, 0x47, 0xf8, 0xa6, 0x1b, 0xc3, 0xa7, 0x95,
|
||||
0x2d, 0xd4, 0xca, 0xb8, 0x0d, 0xfb, 0x06, 0x85,
|
||||
0xda, 0x63, 0xf0, 0x3e, 0x9d, 0x5e, 0xee, 0xce,
|
||||
0xed, 0x74, 0x1d, 0x2c, 0x97, 0x3f, 0x71, 0x95,
|
||||
0x12, 0x03, 0xc5, 0x92, 0x46, 0x84, 0x1b, 0x07,
|
||||
0xe6, 0xb4, 0x1d, 0x3a, 0xf1, 0x89, 0x90, 0x50,
|
||||
0x10, 0x29, 0x34, 0xc0, 0x90, 0xbe, 0x4a, 0xa9,
|
||||
0x0d, 0xb0, 0x7b, 0xfb, 0x35, 0xee, 0x4e, 0x34,
|
||||
0xec, 0x5a, 0x58, 0xbc, 0xb8, 0xda, 0x38, 0x88,
|
||||
0x8c, 0x74, 0x1e, 0xc9, 0xab, 0x78, 0x2e, 0x2a,
|
||||
0x17, 0x8a, 0x43, 0x3d, 0xa1, 0x2a, 0x41, 0xb5,
|
||||
0xd6, 0xe8, 0x5b, 0xc5, 0x4a, 0x1c, 0x3c, 0x9f,
|
||||
0x8d, 0x3a, 0x69, 0x88, 0xf8, 0x80, 0xd2, 0x11,
|
||||
0xfc, 0x7e, 0x80, 0x8e, 0x7f, 0x85, 0x64, 0x9c,
|
||||
0x46, 0x58, 0xc8, 0x48, 0x98, 0x4b, 0xf5, 0x73,
|
||||
0x3f, 0x49, 0xce, 0x53, 0x2c, 0xd5, 0xfc, 0x33,
|
||||
0xf1, 0x6f, 0xd8, 0xe9, 0x2e, 0x70, 0x2e, 0xdc,
|
||||
0xe5, 0x43, 0x80, 0x38, 0xf2, 0x87, 0xed, 0x85,
|
||||
0xe4, 0x3e, 0x45, 0x14, 0x20, 0xcf, 0xa0, 0x61,
|
||||
0x4f, 0xe8, 0xd7, 0x5b, 0xb3, 0x0d, 0x0e, 0x4e,
|
||||
0x4d, 0xce, 0xbe, 0xba, 0xaa, 0x90, 0x09, 0xcb,
|
||||
0x4b, 0x5d, 0x08, 0xff, 0x52, 0xd5, 0x23, 0xbc,
|
||||
0xad, 0x8d, 0xd3, 0x06, 0x4a, 0xa0, 0x51, 0x56,
|
||||
0xa7, 0xd8, 0x33, 0xab, 0xbc, 0xd0, 0xdf, 0x92,
|
||||
0x87, 0x20, 0x2d, 0x7b, 0x5e, 0xfa, 0x30, 0xa7,
|
||||
0x06, 0x06, 0xe5, 0x4f, 0x2c, 0xb5, 0x61, 0xd7,
|
||||
0x54, 0xd3, 0xdf, 0xd0, 0x0a, 0xb0, 0x06, 0xce,
|
||||
0xf6, 0x86, 0xb7, 0x8e, 0xaa, 0x7b, 0x78, 0xd5,
|
||||
0xb9, 0xeb, 0x07, 0xac, 0x5f, 0xc5, 0xd2, 0x8c,
|
||||
0x40, 0xe0, 0x7f, 0x98, 0xd4, 0xe5, 0x4b, 0xca,
|
||||
0xfb, 0x47, 0xef, 0xef, 0xb9, 0x4d, 0x6d, 0x8f,
|
||||
0x82, 0x68, 0x74, 0x84, 0xe0, 0x0a, 0x93, 0x0f,
|
||||
0xb2, 0x01, 0xa9, 0x9f, 0x68, 0x6a, 0xe8, 0xf7,
|
||||
0xfb, 0x0b, 0xde, 0x17, 0xe0, 0x30, 0x38, 0x51,
|
||||
0xbc, 0x07, 0xb8, 0x2c, 0x91, 0x0f, 0xc1, 0x0e,
|
||||
0xa6, 0xf9, 0xf0, 0xd5, 0x48, 0x76, 0x8a, 0xde,
|
||||
0x74, 0xe3, 0x30, 0x65, 0x56, 0xb3, 0x5c, 0xe2,
|
||||
0x89, 0x8d, 0xda, 0x80, 0xad, 0x0f, 0x22, 0xfb,
|
||||
0x24, 0x1d, 0x16, 0xdd, 0x34, 0x4b, 0x90, 0x58,
|
||||
0x4e, 0x0c, 0x13, 0x28, 0xcf, 0x1d, 0xa4, 0xaa,
|
||||
0xb7, 0xf3, 0xb1, 0x66, 0xad, 0x3b, 0xcf, 0x79,
|
||||
0x12, 0x04, 0xd7, 0x79, 0xd9, 0x5f, 0xdf, 0x89,
|
||||
0xb2, 0x5b, 0xa7, 0x9a, 0x26, 0x1e, 0x67, 0x46,
|
||||
0x7c, 0x66, 0x95, 0x67, 0xe6, 0x45, 0x8b, 0x1f,
|
||||
0x65, 0x79, 0x9f, 0x6d, 0x11, 0x81, 0x17, 0x0d,
|
||||
0x11, 0xb0, 0x5c, 0xb4, 0xc7, 0x27, 0x87, 0xab,
|
||||
0x5d, 0x0a, 0x18, 0xae, 0x4e, 0x06, 0xa3, 0x3d,
|
||||
0xc7, 0xb0, 0x22, 0xba, 0x03, 0xa4, 0x0f, 0xe5,
|
||||
0x1c, 0x72, 0x2a, 0x04, 0xce, 0x83, 0xe9, 0xf3,
|
||||
0xd7, 0xc9, 0x67, 0x6c, 0x1e, 0x6b, 0x3c, 0x9b,
|
||||
0x0b, 0x5e, 0x6a, 0xa6, 0x79, 0x0a, 0xf1, 0xbe,
|
||||
0xd7, 0xb4, 0x6f, 0x45, 0x1e, 0xfb, 0x78, 0x97,
|
||||
0xaf, 0x34, 0x76, 0x95, 0x52, 0xf7, 0x3d, 0x5d,
|
||||
0x07, 0x28, 0x57, 0x9c, 0x4a, 0x0f, 0xcf, 0x0b,
|
||||
0x1b, 0xc4, 0xc2, 0x72, 0xd7, 0x72, 0x38, 0x9b,
|
||||
0xea, 0xeb, 0xee, 0xae, 0x34, 0xc8, 0x01, 0xd7,
|
||||
0xa5, 0xe3, 0xce, 0x41, 0xad, 0x02, 0x60, 0x23,
|
||||
0x18, 0x36, 0xba, 0x17, 0xfa, 0xcf, 0xe4, 0xda,
|
||||
0xdc, 0xfc, 0x82, 0xdc, 0x7c, 0x11, 0xf4, 0xb8,
|
||||
0x52, 0x5d, 0xf7, 0x2f, 0xc8, 0xfe, 0x4a, 0xe6,
|
||||
0xb9, 0xaf, 0x4b, 0x17, 0x18, 0x91, 0xc2, 0xfe,
|
||||
0xd7, 0x3a, 0x77, 0x0c, 0xa0, 0x43, 0x9c, 0x6f,
|
||||
0x13, 0x06, 0xbe, 0x6e, 0xe0, 0x1a, 0x3c, 0xf3,
|
||||
0xf5, 0xcc, 0x78, 0xfb, 0x5d, 0xd5, 0xda, 0xb7,
|
||||
0x58, 0xea, 0x86, 0x42, 0x6b, 0x32, 0xff, 0xb2,
|
||||
0xe2, 0xee, 0x03, 0x1f, 0xf4, 0xef, 0xdb, 0x53,
|
||||
0x79, 0xd5, 0x4e, 0xaf, 0x60, 0x8e, 0x02, 0xc2,
|
||||
0xcc, 0x39, 0x97, 0x7b, 0xfd, 0xa1, 0xf8, 0x7a,
|
||||
0x26, 0xe8, 0x55, 0xd6, 0xa4, 0x8b, 0xa0, 0x1b,
|
||||
0x2d, 0x63, 0xaa, 0x73, 0x71, 0x6e, 0xbf, 0x8b,
|
||||
0x3b, 0xe3, 0x1b, 0x0d, 0xbb, 0x2e, 0x44, 0x09,
|
||||
0x64, 0xac, 0xc7, 0x9e, 0xb5, 0xc6, 0x77, 0xb0,
|
||||
0x79, 0xb3, 0xaa, 0xfc, 0x67, 0x57, 0x9a, 0x50,
|
||||
0x81, 0x37, 0x14, 0x7c, 0xd7, 0xa0, 0xd4, 0x6a,
|
||||
0x79, 0x84, 0x51, 0x0e, 0x95, 0x0a, 0x30, 0xa3,
|
||||
0x60, 0x55, 0x48, 0x05, 0x16, 0xae, 0x43, 0x90,
|
||||
0xdc, 0x8e, 0x09, 0xbe, 0x79, 0xf6, 0x90, 0x74,
|
||||
0xf8, 0x20, 0x96, 0x4d, 0xa7, 0xf5, 0x1a, 0x2b,
|
||||
0xc7, 0x15, 0x9d, 0x18, 0xf7, 0x94, 0x87, 0xf7,
|
||||
0xf4, 0xfb, 0x0d, 0x61, 0xb6, 0xd7, 0xbe, 0x10,
|
||||
0x8e, 0x47, 0x3c, 0x10, 0x44, 0x90, 0x52, 0x21,
|
||||
0x83, 0xc0, 0xf5, 0x99, 0xaa, 0xbc, 0xf6, 0x55,
|
||||
0xae, 0xf5, 0xb2, 0xa4, 0xcd, 0x4d, 0xb9, 0x38,
|
||||
0x6c, 0xbc, 0x80, 0xc3, 0xad, 0xf4, 0x46, 0x31,
|
||||
0x01, 0x58, 0x2d, 0x88, 0x57, 0xc3, 0x23, 0xd1,
|
||||
0x64, 0xc9, 0xa3, 0x21, 0x6b, 0x8b, 0x8a, 0x23,
|
||||
0x2c, 0x4f, 0xa9, 0xcd, 0x67, 0xfa, 0x77, 0xad,
|
||||
0xa3, 0x16, 0xa2, 0xe5, 0x19, 0x14, 0x70, 0x41,
|
||||
0x5b, 0xda, 0x14, 0xde, 0xe3, 0xe5, 0xc1, 0x15,
|
||||
0xb4, 0x77, 0xa4, 0x9b, 0xb8, 0xb1, 0x28, 0x51,
|
||||
0x30, 0xb4, 0xf1, 0xf3, 0xf8, 0x6d, 0xd0, 0xc3,
|
||||
0x8c, 0x4c, 0x76, 0xb0, 0x9a, 0xdf, 0xc8, 0xbe,
|
||||
0xf8, 0x4a, 0x61, 0x6e, 0x3e, 0xd6, 0x3c, 0xe8,
|
||||
0xde, 0x56, 0xa0, 0x9c, 0x25, 0xbe, 0xce, 0x93,
|
||||
0x1f, 0x88, 0xfb, 0x9a, 0x1a, 0xe2, 0xff, 0x88,
|
||||
0xad, 0x10, 0xcb, 0x6c, 0xd6, 0xe7, 0x39, 0x0b,
|
||||
0xe5, 0x1a, 0x06, 0x05, 0x64, 0x5b, 0x0a, 0xdf,
|
||||
0x22, 0x58, 0xd7, 0xfb, 0x88, 0x12, 0xdd, 0xb7,
|
||||
0x52, 0x3a, 0xc9, 0xbf, 0x49, 0xdf, 0x8c, 0x87,
|
||||
0x9f, 0x84, 0xb5, 0x0a, 0xf6, 0x00, 0x52, 0xae,
|
||||
0x67, 0x12, 0x1a, 0x8c, 0x71, 0x15, 0xf5, 0xa1,
|
||||
0x13, 0x39, 0xf0, 0x91, 0x7e, 0x88, 0x7c, 0xb3,
|
||||
0x95, 0x50, 0x02, 0xa6, 0x63, 0xb5, 0x64, 0xfb,
|
||||
0x90, 0x87, 0x61, 0xe2, 0x27, 0xaf, 0x11, 0x0c,
|
||||
0x73, 0x83, 0xef, 0xa9, 0x28, 0xfe, 0xc8, 0x85,
|
||||
0x1a, 0x3a, 0xde, 0xf2, 0xe5, 0x25, 0x64, 0x6d,
|
||||
0xaa, 0x41, 0x4c, 0x80, 0x2e, 0x84, 0xff, 0xc1,
|
||||
0xc0, 0x54, 0x0c, 0x29, 0x1b, 0xa3, 0x07, 0x7c,
|
||||
0x33, 0x4c, 0x10, 0xf6, 0x6f, 0x79, 0xdf, 0xd3,
|
||||
0xf0, 0x24, 0x57, 0xf1, 0x60, 0xe1, 0xf0, 0xbd,
|
||||
0xc4, 0x1f, 0xf4, 0x67, 0xd2, 0xd3, 0xcc, 0x6a,
|
||||
0x07, 0x72, 0x44, 0x16, 0x85, 0x46, 0xd0, 0x73,
|
||||
0x87, 0xa9, 0xc7, 0x2f, 0xd1, 0xf5, 0xec, 0xe3,
|
||||
0x28, 0xa3, 0x93, 0x4f, 0xd7, 0x76, 0xc1, 0x3c,
|
||||
0x0d, 0x13, 0x33, 0xcf, 0x5b, 0xbd, 0x6a, 0x52,
|
||||
0x4e, 0xee, 0xc8, 0x5e, 0xa1, 0x58, 0x4a, 0x08,
|
||||
0x81, 0xd9, 0x23, 0xcc, 0xfb, 0x1c, 0xb2, 0xd8,
|
||||
0xa3, 0xe4, 0x53, 0xfe, 0xf4, 0x4b, 0x48, 0xc1,
|
||||
0x20, 0xa4, 0x97, 0xf8, 0x38, 0xa3, 0x69, 0xc1,
|
||||
0x11, 0xf0, 0xa1, 0x3b, 0xa9, 0x9a, 0x12, 0x61,
|
||||
0xe8, 0x8d, 0x99, 0x44, 0x3f, 0x94, 0x72, 0x82,
|
||||
0x19, 0x96, 0x62, 0xb0, 0xa6, 0x64, 0x05, 0x19,
|
||||
0x8f, 0xd6, 0x5d, 0x05, 0xbf, 0x79, 0x9e, 0x9d,
|
||||
0xe4, 0x93, 0x4c, 0xad, 0x61, 0x8c, 0x18, 0xda,
|
||||
0xb6, 0x2e, 0xb3, 0xca, 0x14, 0x4d, 0x53, 0xa4,
|
||||
0x97, 0x27, 0x10, 0x56, 0xa2, 0x67, 0x5a, 0x5a,
|
||||
0x5e, 0x13, 0xc0, 0xdb, 0xa7, 0x9f, 0x45, 0x5b,
|
||||
0xeb, 0x1a, 0x14, 0x0c, 0x8c, 0x38, 0x5e, 0x77,
|
||||
0x9a, 0xec, 0x75, 0x68, 0x93, 0x65, 0x02, 0x9c,
|
||||
0xfb, 0x62, 0x60, 0x49, 0xdd, 0xb2, 0x2a, 0x67,
|
||||
0x86, 0xe3, 0x8a, 0x7d, 0x8c, 0x46, 0x78, 0x81,
|
||||
0x60, 0x69, 0xf2, 0x3f, 0x74, 0x11, 0x35, 0xff,
|
||||
0x77, 0xa3, 0x66, 0x20, 0xfc, 0x98, 0x4a, 0x35,
|
||||
0x7a, 0x52, 0xe4, 0x90, 0x13, 0x80, 0xb9, 0xa6,
|
||||
0x73, 0x7a, 0x7d, 0x66, 0x6e, 0x6b, 0xb6, 0x43,
|
||||
0x10, 0xd5, 0x91, 0x2b, 0x66, 0xdd, 0x89, 0x87,
|
||||
0xe3, 0x8c, 0x58, 0x53, 0x2f, 0x40, 0x74, 0x45,
|
||||
0x1b, 0x77, 0x7a, 0xa4, 0x44, 0x19, 0x78, 0xba,
|
||||
0x87, 0x10, 0x41, 0x31, 0x32, 0x5f, 0x87, 0x68,
|
||||
0xde, 0x43, 0x4a, 0xef, 0x33, 0xb3, 0x11, 0x83,
|
||||
0xa9, 0xc2, 0x6f, 0x8d, 0x34, 0xe2, 0x95, 0x84,
|
||||
0x3a, 0x4f, 0x6f, 0x8c, 0x31, 0x1d, 0xb6, 0xf5,
|
||||
0x95, 0x0d, 0x01, 0x11, 0x20, 0xdf, 0x72, 0xf3,
|
||||
0x3f, 0x9a, 0x33, 0xaa, 0xb1, 0x06, 0x6a, 0x63,
|
||||
0x47, 0x91, 0x01, 0xdf, 0xb3, 0x54, 0x36, 0xfd,
|
||||
0x06, 0x2d, 0xb8, 0x08, 0xe3, 0xd3, 0x65, 0xac,
|
||||
0x66, 0x03, 0xee, 0xa4, 0x63, 0xbd, 0xd4, 0xce,
|
||||
0xbd, 0x79, 0xa7, 0x48, 0x38, 0xc5, 0x7d, 0xb5,
|
||||
0x71, 0x9a, 0x3c, 0x11, 0x7c, 0x6c, 0xe2, 0x54,
|
||||
0x02, 0x5d, 0x42, 0xab, 0x25, 0x93, 0x66, 0x01,
|
||||
0x37, 0x78, 0x35, 0x4a, 0x8c, 0x19, 0x4d, 0x00,
|
||||
0x75, 0x4f, 0xcc, 0xc0, 0x26, 0x82, 0xc1, 0x35,
|
||||
0x8c, 0xc7, 0xc2, 0x59, 0x01, 0x3e, 0x98, 0x22,
|
||||
0x88, 0x9c, 0x90, 0x75, 0x05, 0x33, 0x07, 0xb9,
|
||||
0x39, 0x81, 0x38, 0x58, 0x10, 0x29, 0xcf, 0xc8,
|
||||
0x98, 0xb2, 0x03, 0xd7, 0x5b, 0xb3, 0x18, 0xba,
|
||||
0x34, 0x0c, 0x9f, 0xab, 0xd7, 0xed, 0x29, 0x82,
|
||||
0x41, 0xe0, 0x20, 0x97, 0x57, 0x92, 0xb2, 0xb8,
|
||||
0x10, 0x2d, 0x0b, 0xa2, 0xc5, 0x8f, 0x90, 0x6f,
|
||||
0xed, 0x12, 0x56, 0x25, 0xbe, 0xfd, 0x75, 0xf7,
|
||||
0xb6, 0xf8, 0x40, 0x67, 0x39, 0x11, 0xfa, 0x15,
|
||||
0xae, 0x6a, 0x54, 0x5f, 0x32, 0x2b, 0xf8, 0x48,
|
||||
0x55, 0xbe, 0x86, 0x2f, 0x69, 0x48, 0x5b, 0x5d,
|
||||
0x4d, 0xb7, 0x35, 0xaa, 0xb6, 0x91, 0x88, 0x19,
|
||||
0x96, 0x1c, 0x68, 0xf6, 0x85, 0x9e, 0xb3, 0xb2,
|
||||
0xa3, 0x32, 0xd4, 0x52, 0x70, 0xb7, 0x62, 0xe3,
|
||||
0x14, 0xb6, 0x78, 0x5f, 0x1b, 0x1d, 0x04, 0x9c,
|
||||
0x26, 0x0c, 0x33, 0x94, 0xb1, 0x97, 0x08, 0xdb,
|
||||
0x0b, 0x39, 0x29, 0xd4, 0xbc, 0x6d, 0xdf, 0x02,
|
||||
0xc6, 0x99, 0xab, 0x99, 0x32, 0xe5, 0xce, 0x51,
|
||||
0x4f, 0xae, 0xb8, 0x8b, 0xe0, 0xaf, 0x07, 0xc4,
|
||||
0xf9, 0x41, 0x7c, 0x59, 0xa0, 0xac, 0x74, 0x4d,
|
||||
0x7e, 0x43, 0x77, 0x9c, 0x06, 0x49, 0x79, 0x8a,
|
||||
0x14, 0x73, 0x93, 0xa8, 0x5b, 0x1b, 0x34, 0x29,
|
||||
0x78, 0x04, 0x2f, 0xd7, 0x1f, 0x13, 0x90, 0xe0,
|
||||
0xdd, 0x3b, 0x42, 0x6b, 0x79, 0x6e, 0x52, 0xc7,
|
||||
0x0f, 0x38, 0xda, 0x01, 0x2c, 0x8d, 0xe6, 0x94,
|
||||
0x5d, 0x59, 0x27, 0x1d, 0x10, 0x4e, 0x11, 0x36,
|
||||
0xfb, 0x53, 0x16, 0x05, 0x25, 0xf2, 0x64, 0xd8,
|
||||
0xf9, 0xcd, 0x5c, 0xfe, 0xb4, 0x18, 0x44, 0x80,
|
||||
0x10, 0xbc, 0x3d, 0xf3, 0x1d, 0x5a, 0xf0, 0xc1,
|
||||
0xc3, 0x55, 0xff, 0x41, 0x3e, 0xe3, 0xef, 0x44,
|
||||
0xb2, 0xc0, 0x01, 0x18, 0xa2, 0x49, 0x88, 0x78,
|
||||
0x0d, 0x4c, 0xc8, 0x73, 0xcf, 0x30, 0x85, 0x3a,
|
||||
0x88, 0x90, 0x01, 0xcf, 0x69, 0x53, 0xa3, 0x18,
|
||||
0x3f, 0xd6, 0xe7, 0x94, 0x14, 0xa7, 0xae, 0xcd,
|
||||
0x6f, 0x11, 0x72, 0xfe, 0x2b, 0xb0, 0x81, 0x53,
|
||||
0xea, 0x67, 0xd6, 0xe4, 0xca, 0x42, 0xa0, 0xf9,
|
||||
0xb1, 0xd4, 0xb5, 0x3b, 0xc9, 0xf0, 0x36, 0xc1,
|
||||
0x1c, 0xf4, 0xb1, 0xf6, 0x84, 0xd0, 0x86, 0x6c,
|
||||
0x76, 0x9a, 0x03, 0xc2, 0xb6, 0x2e, 0x9a, 0x46,
|
||||
0xf5, 0x5f, 0x2c, 0x38, 0xac, 0xad, 0x6f, 0x2e,
|
||||
0x7a, 0x18, 0x2d, 0x22, 0x95, 0x5e, 0x5e, 0xc9,
|
||||
0x7a, 0x0a, 0x56, 0xe1, 0xc7, 0x15, 0xfd, 0xbf,
|
||||
0xff, 0xf7, 0x7e, 0x85, 0x20, 0xa9, 0x8a, 0x9c,
|
||||
0xa9, 0x7d, 0xe8, 0xed, 0xfc, 0x7f, 0xbb, 0xf0,
|
||||
0x05, 0x3f, 0xce, 0x4f, 0x4c, 0xee, 0xa4, 0xa0,
|
||||
0xcc, 0x9c, 0x62, 0x1e, 0xd6, 0xd0, 0x30, 0x37,
|
||||
0xb8, 0x98, 0x56, 0x1d, 0xaa, 0xd6, 0x5e, 0x73,
|
||||
0x12, 0xe4, 0x88, 0x82, 0x48, 0x64, 0x06, 0xd7,
|
||||
0x2a, 0x31, 0x50, 0x7b, 0x10, 0x17, 0xb8, 0x4c,
|
||||
0x5a, 0x8d, 0xf1, 0xfc, 0xf1, 0x33, 0x3b, 0x98,
|
||||
0x42, 0x18, 0x5b, 0x35, 0x78, 0xca, 0x8e, 0x41,
|
||||
0x52, 0xae, 0x6d, 0xe1, 0xa2, 0x9d, 0x5b, 0xbd,
|
||||
0xf3, 0x5f, 0x49, 0xc1, 0x27, 0x06, 0xc1, 0xaf,
|
||||
0xc0, 0xa3, 0x9d, 0xf3, 0x1c, 0x8e, 0x90, 0x8a,
|
||||
0xb0, 0x69, 0xb0, 0xc5, 0x11, 0x0c, 0x91, 0x14,
|
||||
0x1f, 0x5e, 0x10, 0xe1, 0x1d, 0x14, 0x30, 0x54,
|
||||
0x1e, 0x17, 0x3d, 0x31, 0x7b, 0xbf, 0x2f, 0x9d,
|
||||
0x6d, 0x63, 0x32, 0xf0, 0x9d, 0x9f, 0x95, 0x3d,
|
||||
0x0b, 0xd2, 0x4d, 0x10, 0xe2, 0x3f, 0x67, 0x69,
|
||||
0x43, 0x9a, 0x4a, 0x2c, 0x54, 0x71, 0xa8, 0xa0,
|
||||
0x9e, 0x9f, 0x10, 0xaf, 0x1b, 0xce, 0x99, 0xe3,
|
||||
0x25, 0x32, 0x10, 0x54, 0x80, 0xfe, 0xda, 0x57,
|
||||
0xd0, 0xb2, 0x92, 0x7f, 0xbb, 0x5f, 0xe7, 0x4d,
|
||||
0x1b, 0x3d, 0x46, 0x4d, 0xe4, 0x4c, 0xd6, 0xaf,
|
||||
0x1a, 0x32, 0x12, 0x40, 0xb8, 0x84, 0x8e, 0xe4,
|
||||
0x80, 0xce, 0x7e, 0xc1, 0x13, 0x8b, 0xb0, 0xb7,
|
||||
0x6f, 0x24, 0xba, 0x85, 0x50, 0x83, 0xc3, 0xcf,
|
||||
0x19, 0xb3, 0xf0, 0xc7, 0xee, 0x68, 0xbe, 0x9e,
|
||||
0x6d, 0xb9, 0xfb, 0xd5, 0x29, 0xce, 0x82, 0xcd,
|
||||
0x69, 0x16, 0x68, 0x6b, 0x6a, 0xf4, 0x02, 0x32,
|
||||
0xce, 0x60, 0x37, 0x0c, 0xb9, 0x38, 0x92, 0x9c,
|
||||
0x42, 0xa9, 0x0b, 0x53, 0x96, 0xfe, 0x39, 0xc1,
|
||||
0x24, 0x65, 0x9b, 0xcd, 0xe7, 0x8d, 0x36, 0x07,
|
||||
0x9f, 0x1d, 0x35, 0x8e, 0xdc, 0x4c, 0xb5, 0x68,
|
||||
0xc5, 0xfd, 0x44, 0x19, 0xf2, 0x6c, 0x59, 0x1c,
|
||||
0xb1, 0x0b, 0x35, 0x48, 0x86, 0x1a, 0x05, 0x22,
|
||||
0x03, 0x0c, 0x0c, 0xa2, 0x92, 0x90, 0x35, 0xfb,
|
||||
0x37, 0x94, 0xc7, 0x15, 0x84, 0xae, 0xe8, 0x05,
|
||||
0xa0, 0xf7, 0x30, 0x11, 0x5c, 0xe4, 0x5d, 0x3e,
|
||||
0x12, 0x54, 0x80, 0x54, 0x6b, 0x09, 0x8c, 0xce,
|
||||
0x80, 0x5e, 0xa7, 0xc8, 0x6a, 0x0c, 0x56, 0xe1,
|
||||
0x18, 0x7d, 0xc9, 0x39, 0xc1, 0xef, 0xe3, 0x25,
|
||||
0xa0, 0x8b, 0x2f, 0x60, 0x3a, 0x43, 0x39, 0xa6,
|
||||
0x28, 0x28, 0x7b, 0x4c, 0x77, 0xd4, 0x49, 0x61,
|
||||
0x46, 0xe9, 0x1b, 0x45, 0xd6, 0xb1, 0x56, 0xe1,
|
||||
0x7d, 0x34, 0xcd, 0x06, 0xb6, 0x67, 0x8d, 0x7d,
|
||||
0x7a, 0xe2, 0xbe, 0x68, 0x35, 0xa6, 0x78, 0xe5,
|
||||
0x47, 0x48, 0xb7, 0xc7, 0xde, 0xcd, 0xc9, 0x05,
|
||||
0xb4, 0xe7, 0x50, 0x48, 0xe1, 0x4b, 0xfe, 0x76,
|
||||
0x77, 0xc6, 0xf7, 0x5f, 0xcb, 0xc2, 0xa8, 0xd7,
|
||||
0xd6, 0x8a, 0xe5, 0x49, 0xd9, 0xca, 0x45, 0xf4,
|
||||
0xda, 0xcd, 0x33, 0xd1, 0x59, 0x2d, 0x9e, 0xc1,
|
||||
0x5c, 0xe6, 0x01, 0x18, 0xb8, 0xf0, 0x5e, 0xb1,
|
||||
0x69, 0x95, 0x2f, 0x02, 0x2a, 0xe7, 0x4a, 0xd7,
|
||||
0xd1, 0xc3, 0xd5, 0x6f, 0x15, 0xc8, 0xdc, 0x29,
|
||||
0xde, 0xb9, 0x3f, 0x8b, 0xa6, 0xbc, 0xdd, 0x25,
|
||||
0x84, 0x35, 0x3c, 0x90, 0x2d, 0xc2, 0x1e, 0x98,
|
||||
0x8a, 0x50, 0x09, 0x77, 0x42, 0xe9, 0x35, 0x8a,
|
||||
0x7c, 0x97, 0xbf, 0xe8, 0xbf, 0x56, 0xd0, 0x8b,
|
||||
0x65, 0xd3, 0xaf, 0x1e, 0x05, 0x94, 0xfa, 0xac,
|
||||
0xa8, 0x2b, 0x28, 0xcb, 0x37, 0x3e, 0xe8, 0xbb,
|
||||
0x66, 0x3a, 0xed, 0xb2, 0x48, 0x10, 0x0f, 0x3a,
|
||||
0x5a, 0xc5, 0xdb, 0x26, 0x0e, 0xaa, 0x5e, 0x69,
|
||||
0x15, 0xd6, 0x81, 0xae, 0xbd, 0xe6, 0x03, 0xf1,
|
||||
0xf6, 0x37, 0xc8, 0xde, 0x70, 0x1f, 0x64, 0xb9,
|
||||
0x5e, 0xbf, 0x2e, 0x4f, 0xb1, 0xea, 0xa0, 0x17,
|
||||
0xe6, 0x7c, 0xf9, 0x2f, 0x1e, 0xd8, 0x58, 0xde,
|
||||
0xa7, 0xf0, 0x46, 0x52, 0x95, 0xdf, 0xa4, 0x96,
|
||||
0xd0, 0xc4, 0x97, 0x2b, 0x95, 0xcd, 0x5e, 0x40,
|
||||
0x23, 0x5c, 0x10, 0xee, 0xba, 0x72, 0x9b, 0xcf,
|
||||
0x0b, 0xe8, 0x18, 0x3a, 0x70, 0xd2, 0x5e, 0x07,
|
||||
0x68, 0x93, 0xef, 0x4a, 0x5b, 0x8d, 0x72, 0x41,
|
||||
0x4e, 0xea, 0x33, 0x6a, 0x0a, 0x5e, 0xfb, 0x02,
|
||||
0x3f, 0xd4, 0xed, 0x5b, 0xe0, 0x42, 0x84, 0xd4,
|
||||
0xaa, 0x85, 0xdc, 0x5b, 0x67, 0xee, 0x71, 0x67,
|
||||
0xba, 0x8e, 0xd2, 0xbe, 0x61, 0xdf, 0x5a, 0x26,
|
||||
0xb9, 0xf0, 0x77, 0x81, 0x53, 0x24, 0x16, 0xcb,
|
||||
0x8c, 0xb8, 0x06, 0x6e, 0x68, 0xda, 0xc8, 0x2d,
|
||||
0x17, 0x54, 0xdb, 0x46, 0xcb, 0xfd, 0x1f, 0x3d,
|
||||
0x94, 0x81, 0x09, 0x4b, 0xfa, 0xb1, 0x46, 0xd9,
|
||||
0x11, 0xa3, 0xb7, 0x31, 0x9c, 0xd2, 0x38, 0xd6,
|
||||
0xba, 0x3d, 0xa3, 0x74, 0xd8, 0xf1, 0x24, 0xe8,
|
||||
0x9c, 0xcb, 0x1d, 0xf9, 0x4a, 0xf7, 0xc8, 0x4b,
|
||||
0xfe, 0x97, 0x7c, 0xa1, 0x02, 0xeb, 0x40, 0xc3,
|
||||
0x89, 0x71, 0x01, 0xcd, 0x33, 0x2a, 0xc2, 0x82,
|
||||
0xce, 0x62, 0x8d, 0x53, 0x7c, 0xdf, 0xce, 0xd7,
|
||||
0xf5, 0xa8, 0x4f, 0xf2, 0xf2, 0x2e, 0xc1, 0xeb,
|
||||
0x97, 0x99, 0x37, 0x3c, 0x53, 0xa6, 0xb4, 0x46,
|
||||
0x05, 0x64, 0x92, 0x87, 0x08, 0x3c, 0x23, 0x4b,
|
||||
0x9d, 0x67, 0x18, 0xf9, 0xe2, 0x0b, 0x1c, 0x39,
|
||||
0xd3, 0x87, 0x70, 0xc0, 0xb9, 0x1e, 0x52, 0x0a,
|
||||
0x0f, 0x48, 0xe2, 0xe7, 0x51, 0x72, 0x94, 0xf7,
|
||||
0xa3, 0xdc, 0xe5, 0x66, 0x33, 0x39, 0x54, 0x06,
|
||||
0x55, 0x93, 0x30, 0xf9, 0x5e, 0x76, 0x8f, 0xe0,
|
||||
0x59, 0x4d, 0x0d, 0xa7, 0xf5, 0xbe, 0xdb, 0x20,
|
||||
0xad, 0x0d, 0x76, 0x88, 0x5f, 0x9c, 0x7c, 0x75,
|
||||
0x2f, 0x2a, 0x0b, 0x79, 0x6e, 0xd3, 0xe2, 0x66,
|
||||
0xf5, 0x4a, 0x2d, 0x87, 0x87, 0x49, 0x84, 0x17,
|
||||
0xa2, 0x62, 0x4c, 0xbb, 0xe4, 0x6e, 0x98, 0x10,
|
||||
0xc9, 0xfb, 0x8a, 0x04, 0x68, 0x8d, 0x22, 0x66,
|
||||
0xad, 0xea, 0x2a, 0xc9, 0x97, 0x2d, 0x3c, 0xbc,
|
||||
0xd0, 0x77, 0x5f, 0xe6, 0xb8, 0x7f, 0xe6, 0xf6,
|
||||
0x39, 0xbf, 0x56, 0x0e, 0x26, 0x6d, 0xc5, 0x3e,
|
||||
0x53, 0x19, 0xd6, 0xb4, 0x57, 0x36, 0xa3, 0xc6,
|
||||
0xd3, 0x3d, 0x66, 0x79, 0x30, 0x5c, 0x14, 0x0c,
|
||||
0x0f, 0x3e, 0x96, 0xae, 0x90, 0x97, 0xab, 0x0d,
|
||||
0x9f, 0xc3, 0xe7, 0x66, 0x3e, 0xe0, 0x31, 0x43,
|
||||
0x4b, 0x01, 0xb3, 0x0e, 0x9e, 0x8c, 0x82, 0x4a,
|
||||
0x8c, 0xc7, 0x79, 0x85, 0xdf, 0x75, 0x0d, 0xb4,
|
||||
0x2b, 0x03, 0x14, 0xef, 0x72, 0x58, 0xfd, 0x64,
|
||||
0xc8, 0xe3, 0x0d, 0x9a, 0x14, 0x6f, 0x76, 0xf9,
|
||||
0x46, 0xd1, 0xd2, 0x81, 0xb3, 0x16, 0x6e, 0xc7,
|
||||
0x76, 0x82, 0xce, 0xf4, 0xee, 0x33, 0x00, 0xe6,
|
||||
0x77, 0xc4, 0xad, 0x4f, 0x06, 0xa7, 0x48, 0x80,
|
||||
0x9e, 0x21, 0x66, 0xca, 0x75, 0x69, 0x57, 0xcb,
|
||||
0xf0, 0x67, 0x6a, 0xaa, 0x8f, 0x88, 0x14, 0xbd,
|
||||
0x65, 0x62, 0xe2, 0xad, 0xcc, 0x22, 0x88, 0x7b,
|
||||
0x94, 0xbd, 0x0e, 0xcd, 0xb6, 0x69, 0xa2, 0xcb,
|
||||
0x7d, 0x57, 0x5c, 0xb4, 0x92, 0x80, 0x13, 0x99,
|
||||
0x84, 0xf3, 0x79, 0x0a, 0x2d, 0x70, 0xa4, 0xe0,
|
||||
0xde, 0xc6, 0x32, 0xb0, 0x8a, 0x62, 0xb5, 0xcf,
|
||||
0xfa, 0x5e, 0x5a, 0x92, 0x32, 0x7d, 0x34, 0x07,
|
||||
0xb5, 0x52, 0x3a, 0xb5, 0x7d, 0x0f, 0xa1, 0xba,
|
||||
0x56, 0xd0, 0x07, 0x76, 0x11, 0xf2, 0xc3, 0x33,
|
||||
0x9d, 0xbd, 0x12, 0x35, 0x5e, 0xf7, 0x05, 0x88,
|
||||
0x76, 0x94, 0xa6, 0xbf, 0xed, 0xb8, 0xa4, 0xa2,
|
||||
0x0c, 0xbe, 0x0f, 0x6a, 0xaf, 0xf3, 0x1b, 0x33,
|
||||
0x4a, 0xb7, 0x68, 0x3f, 0xbe, 0x95, 0x13, 0x97,
|
||||
0x0f, 0x15, 0x17, 0x1b, 0x23, 0xaa, 0x08, 0x78,
|
||||
0xa6, 0x5b, 0x08, 0xa2, 0x9d, 0x03, 0xa8, 0xa7,
|
||||
0x39, 0xdc, 0xbc, 0x9a, 0x85, 0xf5, 0xe5, 0x55,
|
||||
0x59, 0x3c, 0xef, 0xf9, 0x3f, 0x22, 0x8e, 0xf8,
|
||||
0xd8, 0x3e, 0x02, 0x0b, 0xd8, 0x78, 0x4b, 0x15,
|
||||
0x7f, 0xaa, 0x2c, 0xff, 0xbe, 0x77, 0x33, 0xc7,
|
||||
0x6a, 0x12, 0xaa, 0xa4, 0xbe, 0xc0, 0x3b, 0xcb,
|
||||
0x13, 0x9d, 0x9c, 0x5a, 0x9f, 0x8a, 0x57, 0x36,
|
||||
0x4f, 0x02, 0x5a, 0xf8, 0x1d, 0x97, 0x77, 0x43,
|
||||
0xc8, 0xa5, 0xb7, 0x9b, 0x10, 0x98, 0xfd, 0x58,
|
||||
0xbf, 0x42, 0xf6, 0xbf, 0xff, 0x6c, 0x40, 0x18,
|
||||
0x18, 0xdf, 0xac, 0x57, 0x71, 0xea, 0xcc, 0x8e,
|
||||
0xfd, 0xfe, 0x10, 0xfb, 0xb9, 0xfe, 0xbc, 0x9a,
|
||||
0x9c, 0x27, 0xe4, 0x10, 0x15, 0x94, 0x41, 0xa1,
|
||||
0xcc, 0xf6, 0x25, 0x49, 0x4f, 0x96, 0xc1, 0x8c,
|
||||
0x9e, 0x3e, 0x18, 0x29, 0x49, 0x92, 0xe7, 0xfe,
|
||||
0x22, 0xff, 0xed, 0x02, 0x16, 0x90, 0xef, 0xac,
|
||||
0xec, 0x95, 0x1d, 0x5b, 0x94, 0x9c, 0xf6, 0x7c,
|
||||
0x1b, 0x5a, 0x9d, 0xb0, 0x9b, 0x05, 0x36, 0xbf,
|
||||
0xef, 0xec, 0x63, 0x35, 0x40, 0x24, 0x45, 0x40,
|
||||
0x30, 0x1a, 0x9b, 0x90, 0xc3, 0xc2, 0xf7, 0x37,
|
||||
0xfb, 0x08, 0x8e, 0x48, 0x19, 0x48, 0xed, 0xa8,
|
||||
0xa8, 0x04, 0x6f, 0xd0, 0x33, 0xe9, 0xb8, 0x8d,
|
||||
0xe7, 0x1e, 0x5c, 0x47, 0x74, 0xc0, 0x66, 0x30,
|
||||
0x4e, 0xa7, 0x86, 0x73, 0xf1, 0xe5, 0x78, 0xa6,
|
||||
0xe0, 0xc1, 0xda, 0x13, 0x72, 0x07, 0x85, 0x34,
|
||||
0x63, 0x95, 0x49, 0x30, 0x4b, 0x9d, 0x03, 0xf1,
|
||||
0x7a, 0x6b, 0x91, 0xa2, 0x85, 0x41, 0xf9, 0x4a,
|
||||
0xd6, 0xff, 0xff, 0x86, 0xf7, 0xf0, 0xce, 0xb9,
|
||||
0x07, 0xf1, 0x88, 0x04, 0x33, 0xaa, 0xeb, 0x54,
|
||||
0xb2, 0x1c, 0x8e, 0x2e, 0x7b, 0x04, 0xa8, 0xcc,
|
||||
0x2c, 0x7a, 0xb3, 0xad, 0x1a, 0x89, 0x38, 0x89,
|
||||
0xd7, 0x11, 0x3a, 0x8c, 0xcf, 0xe3, 0xc5, 0xba,
|
||||
0xb0, 0xcc, 0xc4, 0xe3, 0x33, 0xf3, 0x18, 0xba,
|
||||
0xec, 0x56, 0xd9, 0x1c, 0x40, 0x70, 0x0d, 0x4e,
|
||||
0x97, 0x01, 0x23, 0xf3, 0x5a, 0xdc, 0xbf, 0x68,
|
||||
0x93, 0xc2, 0x1d, 0x8a, 0x96, 0xb7, 0xac, 0x18,
|
||||
0x6f, 0xf7, 0x84, 0x71, 0x0d, 0x3d, 0xf8, 0xba,
|
||||
0xdf, 0xb6, 0x89, 0x1d, 0x78, 0x19, 0xf2, 0x59,
|
||||
0xe9, 0x15, 0x55, 0x29, 0x73, 0x50, 0x59, 0x14,
|
||||
0x02, 0x21, 0x16, 0x8f, 0x0f, 0xdf, 0xa5, 0xf0,
|
||||
};
|
||||
|
||||
static struct crc_test {
|
||||
uint32_t crc; /* random starting crc */
|
||||
uint32_t start; /* random offset in buf */
|
||||
uint32_t length; /* random length of test */
|
||||
uint32_t crc32c_le; /* expected crc32c_le result */
|
||||
uint32_t crc32_be; /* expected crc32_be result */
|
||||
} test[] = {
|
||||
{0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0xd8ddcdc3},
|
||||
{0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0xc863aef8},
|
||||
{0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0x173a11c4},
|
||||
{0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0xd6307c56},
|
||||
{0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x2e5c9201},
|
||||
{0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xf682c4be},
|
||||
{0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0x3d8abdf9},
|
||||
{0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0x47b4d26c},
|
||||
{0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0x62b47e8b},
|
||||
{0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xff5bc5b7},
|
||||
{0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x1a0cfacd},
|
||||
{0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x275118a7},
|
||||
{0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0xa74ecff5},
|
||||
{0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xbd800707},
|
||||
{0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0xecbde1a1},
|
||||
{0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0xfb78eb9f},
|
||||
{0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x8c116f85},
|
||||
{0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x5aa17bbe},
|
||||
{0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0xb5906aa6},
|
||||
{0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x3ad112b1},
|
||||
{0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0xbaee0339},
|
||||
{0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x6f3a3979},
|
||||
{0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xe3e52eed},
|
||||
{0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x0835bc1b},
|
||||
{0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x2ca885e6},
|
||||
{0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x79be2f78},
|
||||
{0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0x1d25f627},
|
||||
{0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xa76a5656},
|
||||
{0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0xba273974},
|
||||
{0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0xb7bc958c},
|
||||
{0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xf882b644},
|
||||
{0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xe9dc1396},
|
||||
{0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0xc6b888ee},
|
||||
{0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0x60cd2b74},
|
||||
{0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0x3a0a615b},
|
||||
{0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0xa99e60be},
|
||||
{0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0x9bfcaef2},
|
||||
{0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0x20958672},
|
||||
{0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0xd70ff2b2},
|
||||
{0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0xad716acd},
|
||||
{0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x95c71c7b},
|
||||
{0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0x44b7f99b},
|
||||
{0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x71bc01ee},
|
||||
{0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xc539b753},
|
||||
{0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0xea6073a5},
|
||||
{0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0x209aea3b},
|
||||
{0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0xe087a8b6},
|
||||
{0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x95e4b90e},
|
||||
{0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0x77611523},
|
||||
{0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0xea925faa},
|
||||
{0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1130f736},
|
||||
{0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x32459994},
|
||||
{0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0x5a632f78},
|
||||
{0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0xdf2652d5},
|
||||
{0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x3619d31b},
|
||||
{0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xea31c743},
|
||||
{0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x1f76a809},
|
||||
{0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0x63b9b93f},
|
||||
{0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x8f99c98c},
|
||||
{0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0xaf5e3091},
|
||||
{0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x53d0dce1},
|
||||
{0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x106d0905},
|
||||
{0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x62180b57},
|
||||
{0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xf44430a4},
|
||||
{0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0x587b4eb3},
|
||||
{0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x92406c32},
|
||||
{0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0x13bfe70e},
|
||||
{0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x19d3b4e4},
|
||||
{0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x3c107021},
|
||||
{0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0xb82fdc3e},
|
||||
{0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0xab0d3c1d},
|
||||
{0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x1371ad05},
|
||||
{0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0xe2e72df1},
|
||||
{0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x039de73e},
|
||||
{0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0xfe39a2bb},
|
||||
{0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xf0f794a0},
|
||||
{0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0xe66ce41c},
|
||||
{0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4cb28ef7},
|
||||
{0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x40236d1d},
|
||||
{0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xc32e420a},
|
||||
{0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0x83a67f35},
|
||||
{0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x88f1aac1},
|
||||
{0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x74274f66},
|
||||
{0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x54eff534},
|
||||
{0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x55e9363f},
|
||||
{0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0x31041c06},
|
||||
{0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x4704efba},
|
||||
{0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x4e4430c8},
|
||||
{0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x11d52a7b},
|
||||
{0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x04640f4d},
|
||||
{0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0xf7ca4a2c},
|
||||
{0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x2c4af003},
|
||||
{0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x5ae11687},
|
||||
{0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x30d47957},
|
||||
{0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0x2a14a255},
|
||||
{0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0xcb8d3b93},
|
||||
{0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x6531b509},
|
||||
{0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0xe43cc5e9},
|
||||
{0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0x8004765c},
|
||||
{0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x1378f6ff},
|
||||
{0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x676e14a5},
|
||||
{0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0xc71b429c},
|
||||
{0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x19ed14aa},
|
||||
{0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0xf654d3ed},
|
||||
{0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x3cccb57e},
|
||||
{0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x92132798},
|
||||
{0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x6160c87a},
|
||||
{0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x6f00f637},
|
||||
{0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0xb46caa6e},
|
||||
{0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0xb6c29121},
|
||||
{0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xc81cf380},
|
||||
{0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xb2464559},
|
||||
{0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0x4ccf571b},
|
||||
{0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0xae0b305a},
|
||||
{0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0x6c8a4f09},
|
||||
{0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x7e04af8c},
|
||||
{0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb3a91d12},
|
||||
{0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0xfb472fdf},
|
||||
{0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0xf347f235},
|
||||
{0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0x0b7f1521},
|
||||
{0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0x1cc67088},
|
||||
{0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x550caefd},
|
||||
{0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x9ed82a02},
|
||||
{0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0x633c38a8},
|
||||
{0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x0491452f},
|
||||
{0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x1a42fe61},
|
||||
{0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xcd0694c6},
|
||||
{0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0xf0510c72},
|
||||
{0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static int test_crc32c(void)
|
||||
{
|
||||
struct crc_test *t = test;
|
||||
int failures = 0;
|
||||
|
||||
while (t->length) {
|
||||
uint32_t be, le;
|
||||
le = ext2fs_crc32c_le(t->crc, test_buf + t->start, t->length);
|
||||
be = ext2fs_crc32_be(t->crc, test_buf + t->start, t->length);
|
||||
if (le != t->crc32c_le) {
|
||||
printf("Test %d LE fails, %x != %x\n",
|
||||
(int) (t - test), le, t->crc32c_le);
|
||||
failures++;
|
||||
}
|
||||
if (be != t->crc32_be) {
|
||||
printf("Test %d BE fails, %x != %x\n",
|
||||
(int) (t - test), be, t->crc32_be);
|
||||
failures++;
|
||||
}
|
||||
t++;
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = test_crc32c();
|
||||
if (!ret)
|
||||
printf("No failures.\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* UNITTEST */
|
||||
1011
jni/e2fsprogs/lib/ext2fs/csum.c
Executable file
1011
jni/e2fsprogs/lib/ext2fs/csum.c
Executable file
File diff suppressed because it is too large
Load Diff
403
jni/e2fsprogs/lib/ext2fs/dblist.c
Executable file
403
jni/e2fsprogs/lib/ext2fs/dblist.c
Executable file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
|
||||
static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b);
|
||||
static EXT2_QSORT_TYPE (*sortfunc32)(const void *a, const void *b);
|
||||
|
||||
/*
|
||||
* 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_entry2 *list,
|
||||
ext2_dblist *ret_dblist)
|
||||
{
|
||||
ext2_dblist dblist = NULL;
|
||||
errcode_t retval;
|
||||
ext2_ino_t num_dirs;
|
||||
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)
|
||||
goto cleanup;
|
||||
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, &num_dirs);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
dblist->size = (num_dirs * 2) + 12;
|
||||
}
|
||||
len = (size_t) sizeof(struct ext2_db_entry2) * dblist->size;
|
||||
dblist->count = count;
|
||||
retval = ext2fs_get_array(dblist->size, sizeof(struct ext2_db_entry2),
|
||||
&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:
|
||||
if (dblist)
|
||||
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_block2(ext2_dblist dblist, ext2_ino_t ino,
|
||||
blk64_t blk, e2_blkcnt_t blockcnt)
|
||||
{
|
||||
struct ext2_db_entry2 *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_entry2);
|
||||
dblist->size += dblist->size > 200 ? dblist->size / 2 : 100;
|
||||
retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
|
||||
sizeof(struct ext2_db_entry2),
|
||||
&dblist->list);
|
||||
if (retval) {
|
||||
dblist->size = old_size / sizeof(struct ext2_db_entry2);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
new_entry = dblist->list + ( 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_block2(ext2_dblist dblist, ext2_ino_t ino,
|
||||
blk64_t blk, e2_blkcnt_t 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_sort2(ext2_dblist dblist,
|
||||
EXT2_QSORT_TYPE (*sortfunc)(const void *,
|
||||
const void *))
|
||||
{
|
||||
if (!sortfunc)
|
||||
sortfunc = dir_block_cmp2;
|
||||
qsort(dblist->list, (size_t) dblist->count,
|
||||
sizeof(struct ext2_db_entry2), sortfunc);
|
||||
dblist->sorted = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function iterates over the directory block list
|
||||
*/
|
||||
errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist,
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry2 *db_info,
|
||||
void *priv_data),
|
||||
unsigned long long start,
|
||||
unsigned long long count,
|
||||
void *priv_data)
|
||||
{
|
||||
unsigned long long i, end;
|
||||
int ret;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
end = start + count;
|
||||
if (!dblist->sorted)
|
||||
ext2fs_dblist_sort2(dblist, 0);
|
||||
if (end > dblist->count)
|
||||
end = dblist->count;
|
||||
for (i = start; i < end; i++) {
|
||||
ret = (*func)(dblist->fs, &dblist->list[i], priv_data);
|
||||
if (ret & DBLIST_ABORT)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist,
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry2 *db_info,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
return ext2fs_dblist_iterate3(dblist, func, 0, dblist->count,
|
||||
priv_data);
|
||||
}
|
||||
|
||||
static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b)
|
||||
{
|
||||
const struct ext2_db_entry2 *db_a =
|
||||
(const struct ext2_db_entry2 *) a;
|
||||
const struct ext2_db_entry2 *db_b =
|
||||
(const struct ext2_db_entry2 *) 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 (db_a->blockcnt - db_b->blockcnt);
|
||||
}
|
||||
|
||||
blk64_t ext2fs_dblist_count2(ext2_dblist dblist)
|
||||
{
|
||||
return dblist->count;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_get_last2(ext2_dblist dblist,
|
||||
struct ext2_db_entry2 **entry)
|
||||
{
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count == 0)
|
||||
return EXT2_ET_DBLIST_EMPTY;
|
||||
|
||||
if (entry)
|
||||
*entry = dblist->list + ( dblist->count-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_drop_last(ext2_dblist dblist)
|
||||
{
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count == 0)
|
||||
return EXT2_ET_DBLIST_EMPTY;
|
||||
|
||||
dblist->count--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy 32-bit versions
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
return ext2fs_add_dir_block2(dblist, ino, blk, blockcnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
return ext2fs_set_dir_block2(dblist, ino, blk, blockcnt);
|
||||
}
|
||||
|
||||
void ext2fs_dblist_sort(ext2_dblist dblist,
|
||||
EXT2_QSORT_TYPE (*sortfunc)(const void *,
|
||||
const void *))
|
||||
{
|
||||
if (sortfunc) {
|
||||
sortfunc32 = sortfunc;
|
||||
sortfunc = dir_block_cmp;
|
||||
} else
|
||||
sortfunc = dir_block_cmp2;
|
||||
qsort(dblist->list, (size_t) dblist->count,
|
||||
sizeof(struct ext2_db_entry2), sortfunc);
|
||||
dblist->sorted = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function iterates over the directory block list
|
||||
*/
|
||||
struct iterate_passthrough {
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry *db_info,
|
||||
void *priv_data);
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
static int passthrough_func(ext2_filsys fs,
|
||||
struct ext2_db_entry2 *db_info,
|
||||
void *priv_data)
|
||||
{
|
||||
struct iterate_passthrough *p = priv_data;
|
||||
struct ext2_db_entry db;
|
||||
int ret;
|
||||
|
||||
db.ino = db_info->ino;
|
||||
db.blk = (blk_t) db_info->blk;
|
||||
db.blockcnt = (int) db_info->blockcnt;
|
||||
ret = (p->func)(fs, &db, p->priv_data);
|
||||
db_info->ino = db.ino;
|
||||
db_info->blk = db.blk;
|
||||
db_info->blockcnt = db.blockcnt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct iterate_passthrough pass;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
pass.func = func;
|
||||
pass.priv_data = priv_data;
|
||||
|
||||
return ext2fs_dblist_iterate2(dblist, passthrough_func, &pass);
|
||||
}
|
||||
|
||||
static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct ext2_db_entry2 *db_a =
|
||||
(const struct ext2_db_entry2 *) a;
|
||||
const struct ext2_db_entry2 *db_b =
|
||||
(const struct ext2_db_entry2 *) b;
|
||||
|
||||
struct ext2_db_entry a32, b32;
|
||||
|
||||
a32.ino = db_a->ino; a32.blk = db_a->blk;
|
||||
a32.blockcnt = db_a->blockcnt;
|
||||
|
||||
b32.ino = db_b->ino; b32.blk = db_b->blk;
|
||||
b32.blockcnt = db_b->blockcnt;
|
||||
|
||||
return sortfunc32(&a32, &b32);
|
||||
}
|
||||
|
||||
int ext2fs_dblist_count(ext2_dblist dblist)
|
||||
{
|
||||
return dblist->count;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_get_last(ext2_dblist dblist,
|
||||
struct ext2_db_entry **entry)
|
||||
{
|
||||
static struct ext2_db_entry ret_entry;
|
||||
struct ext2_db_entry2 *last;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count == 0)
|
||||
return EXT2_ET_DBLIST_EMPTY;
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
last = dblist->list + dblist->count -1;
|
||||
|
||||
ret_entry.ino = last->ino;
|
||||
ret_entry.blk = last->blk;
|
||||
ret_entry.blockcnt = last->blockcnt;
|
||||
*entry = &ret_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
88
jni/e2fsprogs/lib/ext2fs/dblist_dir.c
Executable file
88
jni/e2fsprogs/lib/ext2fs/dblist_dir.c
Executable file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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_entry2 *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_iterate2(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_entry2 *db_info,
|
||||
void *priv_data)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
struct dir_context *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = (struct dir_context *) priv_data;
|
||||
ctx->dir = db_info->ino;
|
||||
ctx->errcode = 0;
|
||||
|
||||
ctx->errcode = ext2fs_read_inode(fs, ctx->dir, &inode);
|
||||
if (ctx->errcode)
|
||||
return DBLIST_ABORT;
|
||||
if (inode.i_flags & EXT4_INLINE_DATA_FL)
|
||||
ret = ext2fs_inline_data_dir_iterate(fs, ctx->dir, ctx);
|
||||
else
|
||||
ret = ext2fs_process_dir_block(fs, &db_info->blk,
|
||||
db_info->blockcnt, 0, 0,
|
||||
priv_data);
|
||||
if ((ret & BLOCK_ABORT) && !ctx->errcode)
|
||||
return DBLIST_ABORT;
|
||||
return 0;
|
||||
}
|
||||
187
jni/e2fsprogs/lib/ext2fs/digest_encode.c
Executable file
187
jni/e2fsprogs/lib/ext2fs/digest_encode.c
Executable file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* lib/ext2fs/digest_encode.c
|
||||
*
|
||||
* A function to encode a digest using 64 characters that are valid in a
|
||||
* filename per ext2fs rules.
|
||||
*
|
||||
* Written by Uday Savagaonkar, 2014.
|
||||
*
|
||||
* Copyright 2014 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include "ext2fs.h"
|
||||
|
||||
static const char *lookup_table =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
|
||||
|
||||
/**
|
||||
* ext2fs_digest_encode() -
|
||||
*
|
||||
* Encodes the input digest using characters from the set [a-zA-Z0-9_+].
|
||||
* The encoded string is roughly 4/3 times the size of the input string.
|
||||
*/
|
||||
int ext2fs_digest_encode(const char *src, int len, char *dst)
|
||||
{
|
||||
int i = 0, bits = 0, ac = 0;
|
||||
char *cp = dst;
|
||||
|
||||
while (i < len) {
|
||||
ac += (((unsigned char) src[i]) << bits);
|
||||
bits += 8;
|
||||
do {
|
||||
*cp++ = lookup_table[ac & 0x3f];
|
||||
ac >>= 6;
|
||||
bits -= 6;
|
||||
} while (bits >= 6);
|
||||
i++;
|
||||
}
|
||||
if (bits)
|
||||
*cp++ = lookup_table[ac & 0x3f];
|
||||
return cp - dst;
|
||||
}
|
||||
|
||||
int ext2fs_digest_decode(const char *src, int len, char *dst)
|
||||
{
|
||||
int i = 0, bits = 0, ac = 0;
|
||||
const char *p;
|
||||
char *cp = dst;
|
||||
|
||||
while (i < len) {
|
||||
p = strchr(lookup_table, src[i]);
|
||||
if (p == NULL || src[i] == 0)
|
||||
return -1;
|
||||
ac += (p - lookup_table) << bits;
|
||||
bits += 6;
|
||||
if (bits >= 8) {
|
||||
*cp++ = ac & 0xff;
|
||||
ac >>= 8;
|
||||
bits -= 8;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (ac)
|
||||
return -1;
|
||||
return cp - dst;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UNITTEST
|
||||
static const struct {
|
||||
unsigned char d[32];
|
||||
unsigned int len;
|
||||
const char *ed;
|
||||
} tests[] = {
|
||||
{ { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
|
||||
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
|
||||
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
|
||||
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32,
|
||||
"jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF"
|
||||
},
|
||||
{ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
|
||||
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
|
||||
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
|
||||
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32,
|
||||
"6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K"
|
||||
},
|
||||
{ { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
|
||||
0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
|
||||
0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
|
||||
0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32,
|
||||
"k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM"
|
||||
},
|
||||
{ { 0x00, }, 1,
|
||||
"AA"
|
||||
},
|
||||
{ { 0x01, }, 1,
|
||||
"BA"
|
||||
},
|
||||
{ { 0x01, 0x02 }, 2,
|
||||
"BIA"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03 }, 3,
|
||||
"BIwA"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04 }, 4,
|
||||
"BIwAEA"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04, 0xff }, 5,
|
||||
"BIwAE8P"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6,
|
||||
"BIwAE8v,"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7,
|
||||
"BIwAE8v,9D"
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, ret, len;
|
||||
int errors = 0;
|
||||
char tmp[1024], tmp2[1024];
|
||||
|
||||
if (argc == 3 && !strcmp(argv[1], "encode")) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp);
|
||||
puts(tmp);
|
||||
exit(0);
|
||||
}
|
||||
if (argc == 3 && !strcmp(argv[1], "decode")) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp);
|
||||
puts(tmp);
|
||||
fprintf(stderr, "returned %d\n", ret);
|
||||
exit(0);
|
||||
}
|
||||
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ret = ext2fs_digest_encode((const char *) tests[i].d,
|
||||
tests[i].len, tmp);
|
||||
len = strlen(tmp);
|
||||
printf("Test Digest %d (returned %d): ", i, ret);
|
||||
if (ret != len) {
|
||||
printf("FAILED returned %d, string length was %d\n",
|
||||
ret, len);
|
||||
errors++;
|
||||
continue;
|
||||
} else if (strcmp(tmp, tests[i].ed) != 0) {
|
||||
printf("FAILED: got %s, expected %s\n", tmp,
|
||||
tests[i].ed);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
ret = ext2fs_digest_decode(tmp, len, tmp2);
|
||||
if (ret != tests[i].len) {
|
||||
printf("FAILED decode returned %d, expected %d\n",
|
||||
ret, tests[i].len);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if (memcmp(tmp2, tests[i].d, ret) != 0) {
|
||||
puts("FAILED: decode mismatched");
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
printf("OK\n");
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ret = ext2fs_digest_encode(argv[i], strlen(argv[i]), tmp);
|
||||
len = strlen(tmp);
|
||||
printf("Digest of '%s' is '%s' (returned %d, length %d)\n",
|
||||
argv[i], tmp, ret, len);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
#endif /* UNITTEST */
|
||||
315
jni/e2fsprogs/lib/ext2fs/dir_iterate.c
Executable file
315
jni/e2fsprogs/lib/ext2fs/dir_iterate.c
Executable file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.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 "ext2fsP.h"
|
||||
|
||||
#define EXT4_MAX_REC_LEN ((1<<16)-1)
|
||||
|
||||
errcode_t ext2fs_get_rec_len(ext2_filsys fs,
|
||||
struct ext2_dir_entry *dirent,
|
||||
unsigned int *rec_len)
|
||||
{
|
||||
unsigned int len = dirent->rec_len;
|
||||
|
||||
if (fs->blocksize < 65536)
|
||||
*rec_len = len;
|
||||
else if (len == EXT4_MAX_REC_LEN || len == 0)
|
||||
*rec_len = fs->blocksize;
|
||||
else
|
||||
*rec_len = (len & 65532) | ((len & 3) << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_rec_len(ext2_filsys fs,
|
||||
unsigned int len,
|
||||
struct ext2_dir_entry *dirent)
|
||||
{
|
||||
if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3))
|
||||
return EINVAL;
|
||||
if (len < 65536) {
|
||||
dirent->rec_len = len;
|
||||
return 0;
|
||||
}
|
||||
if (len == fs->blocksize) {
|
||||
if (fs->blocksize == 65536)
|
||||
dirent->rec_len = EXT4_MAX_REC_LEN;
|
||||
else
|
||||
dirent->rec_len = 0;
|
||||
} else
|
||||
dirent->rec_len = (len & 65532) | ((len >> 16) & 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(ext2_filsys fs, char *buf,
|
||||
unsigned int offset,
|
||||
unsigned int final_offset)
|
||||
{
|
||||
struct ext2_dir_entry *dirent;
|
||||
unsigned int rec_len;
|
||||
#define DIRENT_MIN_LENGTH 12
|
||||
|
||||
while ((offset < final_offset) &&
|
||||
(offset <= fs->blocksize - DIRENT_MIN_LENGTH)) {
|
||||
dirent = (struct ext2_dir_entry *)(buf + offset);
|
||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||
return 0;
|
||||
offset += rec_len;
|
||||
if ((rec_len < 8) ||
|
||||
((rec_len % 4) != 0) ||
|
||||
((ext2fs_dirent_name_len(dirent)+8) > (int) 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_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
|
||||
ext2fs_process_dir_block, &ctx);
|
||||
if (!block_buf)
|
||||
ext2fs_free_mem(&ctx.buf);
|
||||
if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) {
|
||||
(void) ext2fs_inline_data_dir_iterate(fs, dir, &ctx);
|
||||
retval = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_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;
|
||||
unsigned int rec_len, size, buflen;
|
||||
int entry;
|
||||
struct ext2_dir_entry *dirent;
|
||||
int csum_size = 0;
|
||||
int inline_data;
|
||||
errcode_t retval = 0;
|
||||
|
||||
if (blockcnt < 0)
|
||||
return 0;
|
||||
|
||||
entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
|
||||
|
||||
/* If a dir has inline data, we don't need to read block */
|
||||
inline_data = !!(ctx->flags & DIRENT_FLAG_INCLUDE_INLINE_DATA);
|
||||
if (!inline_data) {
|
||||
ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
|
||||
ctx->dir);
|
||||
if (ctx->errcode)
|
||||
return BLOCK_ABORT;
|
||||
/* If we handle a normal dir, we traverse the entire block */
|
||||
buflen = fs->blocksize;
|
||||
} else {
|
||||
buflen = ctx->buflen;
|
||||
}
|
||||
|
||||
if (ext2fs_has_feature_metadata_csum(fs->super))
|
||||
csum_size = sizeof(struct ext2_dir_entry_tail);
|
||||
|
||||
if (buflen < 8) {
|
||||
ctx->errcode = EXT2_ET_DIR_CORRUPTED;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
while (offset < buflen - 8) {
|
||||
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
|
||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||
return BLOCK_ABORT;
|
||||
if (((offset + rec_len) > buflen) ||
|
||||
(rec_len < 8) ||
|
||||
((rec_len % 4) != 0) ||
|
||||
((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) {
|
||||
ctx->errcode = EXT2_ET_DIR_CORRUPTED;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
if (!dirent->inode) {
|
||||
/*
|
||||
* We just need to check metadata_csum when this
|
||||
* dir hasn't inline data. That means that 'buflen'
|
||||
* should be blocksize.
|
||||
*/
|
||||
if (!inline_data &&
|
||||
(offset == buflen - csum_size) &&
|
||||
(dirent->rec_len == csum_size) &&
|
||||
(dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) {
|
||||
if (!(ctx->flags & DIRENT_FLAG_INCLUDE_CSUM))
|
||||
goto next;
|
||||
entry = DIRENT_CHECKSUM;
|
||||
} else if (!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
|
||||
goto next;
|
||||
}
|
||||
|
||||
ret = (ctx->func)(ctx->dir,
|
||||
(next_real_entry > offset) ?
|
||||
DIRENT_DELETED_FILE : entry,
|
||||
dirent, offset,
|
||||
buflen, ctx->buf,
|
||||
ctx->priv_data);
|
||||
if (entry < DIRENT_OTHER_FILE)
|
||||
entry++;
|
||||
|
||||
if (ret & DIRENT_CHANGED) {
|
||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||
return BLOCK_ABORT;
|
||||
changed++;
|
||||
}
|
||||
if (ret & DIRENT_ABORT) {
|
||||
do_abort++;
|
||||
break;
|
||||
}
|
||||
next:
|
||||
if (next_real_entry == offset)
|
||||
next_real_entry += rec_len;
|
||||
|
||||
if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
|
||||
size = (ext2fs_dirent_name_len(dirent) + 11) & ~3;
|
||||
|
||||
if (rec_len != size) {
|
||||
unsigned int final_offset;
|
||||
|
||||
final_offset = offset + rec_len;
|
||||
offset += size;
|
||||
while (offset < final_offset &&
|
||||
!ext2fs_validate_entry(fs, ctx->buf,
|
||||
offset,
|
||||
final_offset))
|
||||
offset += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
offset += rec_len;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (!inline_data) {
|
||||
ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr,
|
||||
ctx->buf,
|
||||
0, ctx->dir);
|
||||
if (ctx->errcode)
|
||||
return BLOCK_ABORT;
|
||||
} else {
|
||||
/*
|
||||
* return BLOCK_INLINE_DATA_CHANGED to notify caller
|
||||
* that inline data has been changed.
|
||||
*/
|
||||
retval = BLOCK_INLINE_DATA_CHANGED;
|
||||
}
|
||||
}
|
||||
if (do_abort)
|
||||
return retval | BLOCK_ABORT;
|
||||
return retval;
|
||||
}
|
||||
113
jni/e2fsprogs/lib/ext2fs/dirblock.c
Executable file
113
jni/e2fsprogs/lib/ext2fs/dirblock.c
Executable file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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_block4(ext2_filsys fs, blk64_t block,
|
||||
void *buf, int flags EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t ino)
|
||||
{
|
||||
errcode_t retval;
|
||||
int corrupt = 0;
|
||||
|
||||
retval = io_channel_read_blk64(fs->io, block, 1, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
|
||||
!ext2fs_dir_block_csum_verify(fs, ino,
|
||||
(struct ext2_dir_entry *)buf))
|
||||
corrupt = 1;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = ext2fs_dirent_swab_in(fs, buf, flags);
|
||||
#endif
|
||||
if (!retval && corrupt)
|
||||
retval = EXT2_ET_DIR_CSUM_INVALID;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
|
||||
void *buf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
|
||||
void *buf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_read_dir_block3(fs, block, buf, flags);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
|
||||
void *buf)
|
||||
{
|
||||
return ext2fs_read_dir_block3(fs, block, buf, 0);
|
||||
}
|
||||
|
||||
|
||||
errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
|
||||
void *inbuf, int flags EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t ino)
|
||||
{
|
||||
errcode_t retval;
|
||||
char *buf = inbuf;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = ext2fs_get_mem(fs->blocksize, &buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
memcpy(buf, inbuf, fs->blocksize);
|
||||
retval = ext2fs_dirent_swab_out(fs, buf, flags);
|
||||
if (retval)
|
||||
return retval;
|
||||
#endif
|
||||
retval = ext2fs_dir_block_csum_set(fs, ino,
|
||||
(struct ext2_dir_entry *)buf);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, buf);
|
||||
|
||||
out:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ext2fs_free_mem(&buf);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
|
||||
void *inbuf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
|
||||
void *inbuf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_write_dir_block3(fs, block, inbuf, flags);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
|
||||
void *inbuf)
|
||||
{
|
||||
return ext2fs_write_dir_block3(fs, block, inbuf, 0);
|
||||
}
|
||||
|
||||
307
jni/e2fsprogs/lib/ext2fs/dirhash.c
Executable file
307
jni/e2fsprogs/lib/ext2fs/dirhash.c
Executable file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Keyed 32-bit hash function using TEA in a Davis-Meyer function
|
||||
* H0 = Key
|
||||
* Hi = E Mi(Hi-1) + Hi-1
|
||||
*
|
||||
* (see Applied Cryptography, 2nd edition, p448).
|
||||
*
|
||||
* Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
|
||||
*
|
||||
* This code is made available under the terms of the GPL
|
||||
*/
|
||||
#define DELTA 0x9E3779B9
|
||||
|
||||
static void TEA_transform(__u32 buf[4], __u32 const in[])
|
||||
{
|
||||
__u32 sum = 0;
|
||||
__u32 b0 = buf[0], b1 = buf[1];
|
||||
__u32 a = in[0], b = in[1], c = in[2], d = in[3];
|
||||
int n = 16;
|
||||
|
||||
do {
|
||||
sum += DELTA;
|
||||
b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
|
||||
b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
|
||||
} while(--n);
|
||||
|
||||
buf[0] += b0;
|
||||
buf[1] += b1;
|
||||
}
|
||||
|
||||
/* F, G and H are basic MD4 functions: selection, majority, parity */
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
|
||||
/*
|
||||
* The generic round function. The application is so specific that
|
||||
* we don't bother protecting all the arguments with parens, as is generally
|
||||
* good macro practice, in favor of extra legibility.
|
||||
* Rotation is separate from addition to prevent recomputation
|
||||
*/
|
||||
#define ROUND(f, a, b, c, d, x, s) \
|
||||
(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
|
||||
#define K1 0
|
||||
#define K2 013240474631UL
|
||||
#define K3 015666365641UL
|
||||
|
||||
/*
|
||||
* Basic cut-down MD4 transform. Returns only 32 bits of result.
|
||||
*/
|
||||
static void halfMD4Transform (__u32 buf[4], __u32 const in[])
|
||||
{
|
||||
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
|
||||
|
||||
/* Round 1 */
|
||||
ROUND(F, a, b, c, d, in[0] + K1, 3);
|
||||
ROUND(F, d, a, b, c, in[1] + K1, 7);
|
||||
ROUND(F, c, d, a, b, in[2] + K1, 11);
|
||||
ROUND(F, b, c, d, a, in[3] + K1, 19);
|
||||
ROUND(F, a, b, c, d, in[4] + K1, 3);
|
||||
ROUND(F, d, a, b, c, in[5] + K1, 7);
|
||||
ROUND(F, c, d, a, b, in[6] + K1, 11);
|
||||
ROUND(F, b, c, d, a, in[7] + K1, 19);
|
||||
|
||||
/* Round 2 */
|
||||
ROUND(G, a, b, c, d, in[1] + K2, 3);
|
||||
ROUND(G, d, a, b, c, in[3] + K2, 5);
|
||||
ROUND(G, c, d, a, b, in[5] + K2, 9);
|
||||
ROUND(G, b, c, d, a, in[7] + K2, 13);
|
||||
ROUND(G, a, b, c, d, in[0] + K2, 3);
|
||||
ROUND(G, d, a, b, c, in[2] + K2, 5);
|
||||
ROUND(G, c, d, a, b, in[4] + K2, 9);
|
||||
ROUND(G, b, c, d, a, in[6] + K2, 13);
|
||||
|
||||
/* Round 3 */
|
||||
ROUND(H, a, b, c, d, in[3] + K3, 3);
|
||||
ROUND(H, d, a, b, c, in[7] + K3, 9);
|
||||
ROUND(H, c, d, a, b, in[2] + K3, 11);
|
||||
ROUND(H, b, c, d, a, in[6] + K3, 15);
|
||||
ROUND(H, a, b, c, d, in[1] + K3, 3);
|
||||
ROUND(H, d, a, b, c, in[5] + K3, 9);
|
||||
ROUND(H, c, d, a, b, in[0] + K3, 11);
|
||||
ROUND(H, b, c, d, a, in[4] + K3, 15);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
#undef ROUND
|
||||
#undef F
|
||||
#undef G
|
||||
#undef H
|
||||
#undef K1
|
||||
#undef K2
|
||||
#undef K3
|
||||
|
||||
/* The old legacy hash */
|
||||
static ext2_dirhash_t dx_hack_hash (const char *name, int len,
|
||||
int unsigned_flag)
|
||||
{
|
||||
__u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
|
||||
const unsigned char *ucp = (const unsigned char *) name;
|
||||
const signed char *scp = (const signed char *) name;
|
||||
int c;
|
||||
|
||||
while (len--) {
|
||||
if (unsigned_flag)
|
||||
c = (int) *ucp++;
|
||||
else
|
||||
c = (int) *scp++;
|
||||
hash = hash1 + (hash0 ^ (c * 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,
|
||||
int unsigned_flag)
|
||||
{
|
||||
__u32 pad, val;
|
||||
int i, c;
|
||||
const unsigned char *ucp = (const unsigned char *) msg;
|
||||
const signed char *scp = (const signed char *) msg;
|
||||
|
||||
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 (unsigned_flag)
|
||||
c = (int) ucp[i];
|
||||
else
|
||||
c = (int) scp[i];
|
||||
|
||||
val = c + (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.
|
||||
*
|
||||
* This function doesn't do any normalization or casefolding of the
|
||||
* input string. To take charset encoding into account, use
|
||||
* ext2fs_dirhash2.
|
||||
*
|
||||
*/
|
||||
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];
|
||||
int unsigned_flag = 0;
|
||||
|
||||
/* 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_UNSIGNED:
|
||||
unsigned_flag++;
|
||||
/* fallthrough */
|
||||
case EXT2_HASH_LEGACY:
|
||||
hash = dx_hack_hash(name, len, unsigned_flag);
|
||||
break;
|
||||
case EXT2_HASH_HALF_MD4_UNSIGNED:
|
||||
unsigned_flag++;
|
||||
/* fallthrough */
|
||||
case EXT2_HASH_HALF_MD4:
|
||||
p = name;
|
||||
while (len > 0) {
|
||||
str2hashbuf(p, len, in, 8, unsigned_flag);
|
||||
halfMD4Transform(buf, in);
|
||||
len -= 32;
|
||||
p += 32;
|
||||
}
|
||||
minor_hash = buf[2];
|
||||
hash = buf[1];
|
||||
break;
|
||||
case EXT2_HASH_TEA_UNSIGNED:
|
||||
unsigned_flag++;
|
||||
/* fallthrough */
|
||||
case EXT2_HASH_TEA:
|
||||
p = name;
|
||||
while (len > 0) {
|
||||
str2hashbuf(p, len, in, 4, unsigned_flag);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the hash of a filename considering normalization and
|
||||
* casefolding. This is a wrapper around ext2fs_dirhash with string
|
||||
* encoding support based on the nls_table and the flags. Check
|
||||
* ext2fs_dirhash for documentation on the input and output parameters.
|
||||
*/
|
||||
errcode_t ext2fs_dirhash2(int version, const char *name, int len,
|
||||
const struct ext2fs_nls_table *charset,
|
||||
int hash_flags, const __u32 *seed,
|
||||
ext2_dirhash_t *ret_hash,
|
||||
ext2_dirhash_t *ret_minor_hash)
|
||||
{
|
||||
errcode_t r;
|
||||
int dlen;
|
||||
|
||||
if (len && charset && (hash_flags & EXT4_CASEFOLD_FL)) {
|
||||
char buff[PATH_MAX];
|
||||
|
||||
dlen = charset->ops->casefold(charset,
|
||||
(const unsigned char *) name, len,
|
||||
(unsigned char *) buff, sizeof(buff));
|
||||
if (dlen < 0) {
|
||||
if (dlen == -EINVAL)
|
||||
goto opaque_seq;
|
||||
|
||||
return dlen;
|
||||
}
|
||||
r = ext2fs_dirhash(version, buff, dlen, seed, ret_hash,
|
||||
ret_minor_hash);
|
||||
return r;
|
||||
}
|
||||
|
||||
opaque_seq:
|
||||
return ext2fs_dirhash(version, name, len, seed, ret_hash,
|
||||
ret_minor_hash);
|
||||
}
|
||||
459
jni/e2fsprogs/lib/ext2fs/dosio.c
Executable file
459
jni/e2fsprogs/lib/ext2fs/dosio.c
Executable file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* dosio.c -- Disk I/O module for the ext2fs/DOS library.
|
||||
*
|
||||
* Copyright (c) 1997 by Theodore Ts'o.
|
||||
*
|
||||
* Copyright (c) 1997 Mark Habersack
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <bios.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <io.h>
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <ext2fs/ext2_types.h>
|
||||
#include "utils.h"
|
||||
#include "dosio.h"
|
||||
#include "et/com_err.h"
|
||||
#include "ext2_err.h"
|
||||
#include "ext2fs/io.h"
|
||||
|
||||
/*
|
||||
* Some helper macros
|
||||
*/
|
||||
#define LINUX_EXT2FS 0x83
|
||||
#define LINUX_SWAP 0x82
|
||||
#define WRITE_ERR(_msg_) write(2, _msg_, strlen(_msg_))
|
||||
#define WRITE_ERR_S(_msg_) write(2, _msg_, sizeof(_msg_))
|
||||
|
||||
/*
|
||||
* Exported variables
|
||||
*/
|
||||
unsigned long _dio_error;
|
||||
unsigned long _dio_hw_error;
|
||||
|
||||
/*
|
||||
* Array of all opened partitions
|
||||
*/
|
||||
static PARTITION **partitions = NULL;
|
||||
static unsigned short npart = 0; /* Number of mapped partitions */
|
||||
static PARTITION *active = NULL;
|
||||
|
||||
/*
|
||||
* I/O Manager routine prototypes
|
||||
*/
|
||||
static errcode_t dos_open(const char *dev, int flags, io_channel *channel);
|
||||
static errcode_t dos_close(io_channel channel);
|
||||
static errcode_t dos_set_blksize(io_channel channel, int blksize);
|
||||
static errcode_t dos_read_blk(io_channel channel, unsigned long block,
|
||||
int count, void *buf);
|
||||
static errcode_t dos_write_blk(io_channel channel, unsigned long block,
|
||||
int count, const void *buf);
|
||||
static errcode_t dos_flush(io_channel channel);
|
||||
|
||||
static struct struct_io_manager struct_dos_manager = {
|
||||
.magic = EXT2_ET_MAGIC_IO_MANAGER,
|
||||
.name = "DOS I/O Manager",
|
||||
.open = dos_open,
|
||||
.close = dos_close,
|
||||
.set_blksize = dos_set_blksize,
|
||||
.read_blk = dos_read_blk,
|
||||
.write_blk = dos_write_blk,
|
||||
.flush = dos_flush
|
||||
};
|
||||
|
||||
io_manager dos_io_manager = &struct_dos_manager;
|
||||
|
||||
/*
|
||||
* Macro taken from unix_io.c
|
||||
*/
|
||||
/*
|
||||
* For checking structure magic numbers...
|
||||
*/
|
||||
|
||||
#define EXT2_CHECK_MAGIC(struct, code) \
|
||||
if ((struct)->magic != (code)) return (code)
|
||||
|
||||
/*
|
||||
* Calculates a CHS address of a sector from its LBA
|
||||
* offset for the given partition.
|
||||
*/
|
||||
static void lba2chs(unsigned long lba_addr, CHS *chs, PARTITION *part)
|
||||
{
|
||||
unsigned long abss;
|
||||
|
||||
chs->offset = lba_addr & 0x000001FF;
|
||||
abss = (lba_addr >> 9) + part->start;
|
||||
chs->cyl = abss / (part->sects * part->heads);
|
||||
chs->head = (abss / part->sects) % part->heads;
|
||||
chs->sector = (abss % part->sects) + 1;
|
||||
}
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
/*
|
||||
* Scans the passed partition table looking for *pno partition
|
||||
* that has LINUX_EXT2FS type.
|
||||
*
|
||||
* TODO:
|
||||
* For partition numbers >5 Linux uses DOS extended partitions -
|
||||
* dive into them an return an appropriate entry. Also dive into
|
||||
* extended partitions when scanning for a first Linux/ext2fs.
|
||||
*/
|
||||
static PTABLE_ENTRY *scan_partition_table(PTABLE_ENTRY *pentry,
|
||||
unsigned short phys,
|
||||
unsigned char *pno)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if(*pno != 0xFF && *pno >= 5)
|
||||
return NULL; /* We don't support extended partitions for now */
|
||||
|
||||
if(*pno != 0xFF)
|
||||
{
|
||||
if(pentry[*pno].type == LINUX_EXT2FS)
|
||||
return &pentry[*pno];
|
||||
else
|
||||
{
|
||||
if(!pentry[*pno].type)
|
||||
*pno = 0xFE;
|
||||
else if(pentry[*pno].type == LINUX_SWAP)
|
||||
*pno = 0xFD;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
if(pentry[i].type == LINUX_EXT2FS)
|
||||
{
|
||||
*pno = i;
|
||||
return &pentry[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate libext2fs structures associated with I/O manager
|
||||
*/
|
||||
static io_channel alloc_io_channel(PARTITION *part)
|
||||
{
|
||||
io_channel ioch;
|
||||
|
||||
ioch = (io_channel)malloc(sizeof(struct struct_io_channel));
|
||||
if (!ioch)
|
||||
return NULL;
|
||||
memset(ioch, 0, sizeof(struct struct_io_channel));
|
||||
ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
|
||||
ioch->manager = dos_io_manager;
|
||||
ioch->name = (char *)malloc(strlen(part->dev)+1);
|
||||
if (!ioch->name) {
|
||||
free(ioch);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(ioch->name, part->dev);
|
||||
ioch->private_data = part;
|
||||
ioch->block_size = 1024; /* The smallest ext2fs block size */
|
||||
ioch->read_error = 0;
|
||||
ioch->write_error = 0;
|
||||
|
||||
return ioch;
|
||||
}
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
/*
|
||||
* Open the 'name' partition, initialize all information structures
|
||||
* we need to keep and create libext2fs I/O manager.
|
||||
*/
|
||||
static errcode_t dos_open(const char *dev, int flags, io_channel *channel)
|
||||
{
|
||||
unsigned char *tmp, sec[512];
|
||||
PARTITION *part;
|
||||
PTABLE_ENTRY *pent;
|
||||
PARTITION **newparts;
|
||||
|
||||
if(!dev)
|
||||
{
|
||||
_dio_error = ERR_BADDEV;
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* First check whether the dev name is OK
|
||||
*/
|
||||
tmp = (unsigned char*)strrchr(dev, '/');
|
||||
if(!tmp)
|
||||
{
|
||||
_dio_error = ERR_BADDEV;
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
}
|
||||
*tmp = 0;
|
||||
if(strcmp(dev, "/dev"))
|
||||
{
|
||||
_dio_error = ERR_BADDEV;
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
}
|
||||
*tmp++ = '/';
|
||||
|
||||
/*
|
||||
* Check whether the partition data is already in cache
|
||||
*/
|
||||
|
||||
part = (PARTITION*)malloc(sizeof(PARTITION));
|
||||
if (!part)
|
||||
return ENOMEM;
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(;i < npart; i++)
|
||||
if(!strcmp(partitions[i]->dev, dev))
|
||||
{
|
||||
/* Found it! Make it the active one */
|
||||
active = partitions[i];
|
||||
*channel = alloc_io_channel(active);
|
||||
if (!*channel)
|
||||
return ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Drive number & optionally partn number
|
||||
*/
|
||||
switch(tmp[0])
|
||||
{
|
||||
case 'h':
|
||||
case 's':
|
||||
part->phys = 0x80;
|
||||
part->phys += toupper(tmp[2]) - 'A';
|
||||
/*
|
||||
* Do we have the partition number?
|
||||
*/
|
||||
if(tmp[3])
|
||||
part->pno = isdigit((int)tmp[3]) ? tmp[3] - '0' - 1: 0;
|
||||
else
|
||||
part->pno = 0xFF;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if(tmp[2])
|
||||
part->phys = isdigit((int)tmp[2]) ? tmp[2] - '0' : 0;
|
||||
else
|
||||
part->phys = 0x00; /* We'll assume /dev/fd0 */
|
||||
break;
|
||||
|
||||
default:
|
||||
_dio_error = ERR_BADDEV;
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
if(part->phys < 0x80)
|
||||
{
|
||||
/* We don't support floppies for now */
|
||||
_dio_error = ERR_NOTSUPP;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
part->dev = strdup(dev);
|
||||
|
||||
/*
|
||||
* Get drive's geometry
|
||||
*/
|
||||
_dio_hw_error = biosdisk(DISK_GET_GEOMETRY,
|
||||
part->phys,
|
||||
0, /* head */
|
||||
0, /* cylinder */
|
||||
1, /* sector */
|
||||
1, /* just one sector */
|
||||
sec);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
free(part->dev);
|
||||
free(part);
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the geometry
|
||||
*/
|
||||
part->cyls = (unsigned short)(((sec[0] >> 6) << 8) + sec[1] + 1);
|
||||
part->heads = sec[3] + 1;
|
||||
part->sects = sec[0] & 0x3F;
|
||||
|
||||
/*
|
||||
* Now that we know all we need, let's look for the partition
|
||||
*/
|
||||
_dio_hw_error = biosdisk(DISK_READ, part->phys, 0, 0, 1, 1, sec);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
free(part->dev);
|
||||
free(part);
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
pent = (PTABLE_ENTRY*)&sec[0x1BE];
|
||||
pent = scan_partition_table(pent, part->phys, &part->pno);
|
||||
|
||||
if(!pent)
|
||||
{
|
||||
_dio_error = part->pno == 0xFE ? ERR_EMPTYPART :
|
||||
part->pno == 0xFD ? ERR_LINUXSWAP : ERR_NOTEXT2FS;
|
||||
free(part->dev);
|
||||
free(part);
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the remaining figures
|
||||
*/
|
||||
{
|
||||
unsigned long fsec, fhead, fcyl;
|
||||
|
||||
fsec = (unsigned long)(pent->start_sec & 0x3F);
|
||||
fhead = (unsigned long)pent->start_head;
|
||||
fcyl = ((pent->start_sec >> 6) << 8) + pent->start_cyl;
|
||||
part->start = fsec + fhead * part->sects + fcyl *
|
||||
(part->heads * part->sects) - 1;
|
||||
part->len = pent->size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the partition to the table
|
||||
*/
|
||||
newparts = (PARTITION**)realloc(partitions, sizeof(PARTITION) * npart);
|
||||
if (!newparts) {
|
||||
free(part);
|
||||
return ENOMEM;
|
||||
}
|
||||
partitions = newparts;
|
||||
partitions[npart++] = active = part;
|
||||
|
||||
/*
|
||||
* Now alloc all libe2fs structures
|
||||
*/
|
||||
*channel = alloc_io_channel(active);
|
||||
if (!*channel)
|
||||
return ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_close(io_channel channel)
|
||||
{
|
||||
free(channel->name);
|
||||
free(channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_set_blksize(io_channel channel, int blksize)
|
||||
{
|
||||
channel->block_size = blksize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_read_blk(io_channel channel, unsigned long block,
|
||||
int count, void *buf)
|
||||
{
|
||||
PARTITION *part;
|
||||
size_t size;
|
||||
ext2_loff_t loc;
|
||||
CHS chs;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
part = (PARTITION*)channel->private_data;
|
||||
|
||||
size = (size_t)((count < 0) ? -count : count * channel->block_size);
|
||||
loc = (ext2_loff_t) block * channel->block_size;
|
||||
|
||||
lba2chs(loc, &chs, part);
|
||||
/*
|
||||
* Potential bug here:
|
||||
* If DJGPP is used then reads of >18 sectors will fail!
|
||||
* Have to rewrite biosdisk.
|
||||
*/
|
||||
_dio_hw_error = biosdisk(DISK_READ,
|
||||
part->phys,
|
||||
chs.head,
|
||||
chs.cyl,
|
||||
chs.sector,
|
||||
size < 512 ? 1 : size/512,
|
||||
buf);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_write_blk(io_channel channel, unsigned long block,
|
||||
int count, const void *buf)
|
||||
{
|
||||
PARTITION *part;
|
||||
size_t size;
|
||||
ext2_loff_t loc;
|
||||
CHS chs;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
part = (PARTITION*)channel->private_data;
|
||||
|
||||
if(count == 1)
|
||||
size = (size_t)channel->block_size;
|
||||
else
|
||||
{
|
||||
if (count < 0)
|
||||
size = (size_t)-count;
|
||||
else
|
||||
size = (size_t)(count * channel->block_size);
|
||||
}
|
||||
|
||||
loc = (ext2_loff_t)block * channel->block_size;
|
||||
lba2chs(loc, &chs, part);
|
||||
_dio_hw_error = biosdisk(DISK_WRITE,
|
||||
part->phys,
|
||||
chs.head,
|
||||
chs.cyl,
|
||||
chs.sector,
|
||||
size < 512 ? 1 : size/512,
|
||||
(void*)buf);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static errcode_t dos_flush(io_channel channel)
|
||||
{
|
||||
/*
|
||||
* No buffers, no flush...
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
122
jni/e2fsprogs/lib/ext2fs/dupfs.c
Executable file
122
jni/e2fsprogs/lib/ext2fs/dupfs.c
Executable file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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;
|
||||
fs->mmp_buf = 0;
|
||||
fs->mmp_cmp = 0;
|
||||
fs->mmp_fd = -1;
|
||||
|
||||
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_array(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;
|
||||
}
|
||||
if (src->mmp_buf) {
|
||||
retval = ext2fs_get_mem(src->blocksize, &fs->mmp_buf);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->mmp_buf, src->mmp_buf, src->blocksize);
|
||||
}
|
||||
if (src->mmp_fd >= 0) {
|
||||
fs->mmp_fd = dup(src->mmp_fd);
|
||||
if (fs->mmp_fd < 0) {
|
||||
retval = EXT2_ET_MMP_OPEN_DIRECT;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
if (src->mmp_cmp) {
|
||||
int align = ext2fs_get_dio_alignment(src->mmp_fd);
|
||||
|
||||
retval = ext2fs_get_memalign(src->blocksize, align,
|
||||
&fs->mmp_cmp);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->mmp_cmp, src->mmp_cmp, src->blocksize);
|
||||
}
|
||||
*dest = fs;
|
||||
return 0;
|
||||
errout:
|
||||
ext2fs_free(fs);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
143
jni/e2fsprogs/lib/ext2fs/expanddir.c
Executable file
143
jni/e2fsprogs/lib/ext2fs/expanddir.c
Executable file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct expand_dir_struct {
|
||||
int done;
|
||||
int newblocks;
|
||||
blk64_t goal;
|
||||
errcode_t err;
|
||||
ext2_ino_t dir;
|
||||
};
|
||||
|
||||
static int expand_dir_proc(ext2_filsys fs,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_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;
|
||||
blk64_t new_blk;
|
||||
char *block;
|
||||
errcode_t retval;
|
||||
|
||||
if (*blocknr) {
|
||||
if (blockcnt >= 0)
|
||||
es->goal = *blocknr;
|
||||
return 0;
|
||||
}
|
||||
if (blockcnt &&
|
||||
(EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1)))
|
||||
new_blk = es->goal+1;
|
||||
else {
|
||||
es->goal &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk);
|
||||
if (retval) {
|
||||
es->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
es->newblocks++;
|
||||
ext2fs_block_alloc_stats2(fs, new_blk, +1);
|
||||
}
|
||||
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_block4(fs, new_blk, block, 0,
|
||||
es->dir);
|
||||
ext2fs_free_mem(&block);
|
||||
} else
|
||||
retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL);
|
||||
if (blockcnt >= 0)
|
||||
es->goal = new_blk;
|
||||
if (retval) {
|
||||
es->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
*blocknr = new_blk;
|
||||
|
||||
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;
|
||||
|
||||
retval = ext2fs_read_inode(fs, dir, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
es.done = 0;
|
||||
es.err = 0;
|
||||
es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 0);
|
||||
es.newblocks = 0;
|
||||
es.dir = dir;
|
||||
|
||||
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
|
||||
0, expand_dir_proc, &es);
|
||||
if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE)
|
||||
return ext2fs_inline_data_expand(fs, dir);
|
||||
|
||||
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;
|
||||
|
||||
retval = ext2fs_inode_size_set(fs, &inode,
|
||||
EXT2_I_SIZE(&inode) + fs->blocksize);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
|
||||
|
||||
retval = ext2fs_write_inode(fs, dir, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
237
jni/e2fsprogs/lib/ext2fs/ext2_err.c
Executable file
237
jni/e2fsprogs/lib/ext2fs/ext2_err.c
Executable file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* ext2_err.c:
|
||||
* This file is automatically generated; please do not edit it.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N_(a) a
|
||||
|
||||
static const char * const text[] = {
|
||||
N_( "EXT2FS Library version android-t-qpr1-beta-2-gpl-369-g8ed4b2673"),
|
||||
N_( "Wrong magic number for ext2_filsys structure"),
|
||||
N_( "Wrong magic number for badblocks_list structure"),
|
||||
N_( "Wrong magic number for badblocks_iterate structure"),
|
||||
N_( "Wrong magic number for inode_scan structure"),
|
||||
N_( "Wrong magic number for io_channel structure"),
|
||||
N_( "Wrong magic number for unix io_channel structure"),
|
||||
N_( "Wrong magic number for io_manager structure"),
|
||||
N_( "Wrong magic number for block_bitmap structure"),
|
||||
N_( "Wrong magic number for inode_bitmap structure"),
|
||||
N_( "Wrong magic number for generic_bitmap structure"),
|
||||
N_( "Wrong magic number for test io_channel structure"),
|
||||
N_( "Wrong magic number for directory block list structure"),
|
||||
N_( "Wrong magic number for icount structure"),
|
||||
N_( "Wrong magic number for Powerquest io_channel structure"),
|
||||
N_( "Wrong magic number for ext2 file structure"),
|
||||
N_( "Wrong magic number for Ext2 Image Header"),
|
||||
N_( "Wrong magic number for inode io_channel structure"),
|
||||
N_( "Wrong magic number for ext4 extent handle"),
|
||||
N_( "Bad magic number in super-block"),
|
||||
N_( "Filesystem revision too high"),
|
||||
N_( "Attempt to write to filesystem opened read-only"),
|
||||
N_( "Can't read group descriptors"),
|
||||
N_( "Can't write group descriptors"),
|
||||
N_( "Corrupt group descriptor: bad block for block bitmap"),
|
||||
N_( "Corrupt group descriptor: bad block for inode bitmap"),
|
||||
N_( "Corrupt group descriptor: bad block for inode table"),
|
||||
N_( "Can't write an inode bitmap"),
|
||||
N_( "Can't read an inode bitmap"),
|
||||
N_( "Can't write a block bitmap"),
|
||||
N_( "Can't read a block bitmap"),
|
||||
N_( "Can't write an inode table"),
|
||||
N_( "Can't read an inode table"),
|
||||
N_( "Can't read next inode"),
|
||||
N_( "Filesystem has unexpected block size"),
|
||||
N_( "EXT2 directory corrupted"),
|
||||
N_( "Attempt to read block from filesystem resulted in short read"),
|
||||
N_( "Attempt to write block to filesystem resulted in short write"),
|
||||
N_( "No free space in the directory"),
|
||||
N_( "Inode bitmap not loaded"),
|
||||
N_( "Block bitmap not loaded"),
|
||||
N_( "Illegal inode number"),
|
||||
N_( "Illegal block number"),
|
||||
N_( "Internal error in ext2fs_expand_dir"),
|
||||
N_( "Not enough space to build proposed filesystem"),
|
||||
N_( "Illegal block number passed to ext2fs_mark_block_bitmap"),
|
||||
N_( "Illegal block number passed to ext2fs_unmark_block_bitmap"),
|
||||
N_( "Illegal block number passed to ext2fs_test_block_bitmap"),
|
||||
N_( "Illegal inode number passed to ext2fs_mark_inode_bitmap"),
|
||||
N_( "Illegal inode number passed to ext2fs_unmark_inode_bitmap"),
|
||||
N_( "Illegal inode number passed to ext2fs_test_inode_bitmap"),
|
||||
N_( "Attempt to fudge end of block bitmap past the real end"),
|
||||
N_( "Attempt to fudge end of inode bitmap past the real end"),
|
||||
N_( "Illegal indirect block found" ),
|
||||
N_( "Illegal doubly indirect block found" ),
|
||||
N_( "Illegal triply indirect block found" ),
|
||||
N_( "Block bitmaps are not the same"),
|
||||
N_( "Inode bitmaps are not the same"),
|
||||
N_( "Illegal or malformed device name"),
|
||||
N_( "A block group is missing an inode table"),
|
||||
N_( "The ext2 superblock is corrupt"),
|
||||
N_( "Illegal generic bit number passed to ext2fs_mark_generic_bitmap"),
|
||||
N_( "Illegal generic bit number passed to ext2fs_unmark_generic_bitmap"),
|
||||
N_( "Illegal generic bit number passed to ext2fs_test_generic_bitmap"),
|
||||
N_( "Too many symbolic links encountered."),
|
||||
N_( "The callback function will not handle this case"),
|
||||
N_( "The inode is from a bad block in the inode table"),
|
||||
N_( "Filesystem has unsupported feature(s)"),
|
||||
N_( "Filesystem has unsupported read-only feature(s)"),
|
||||
N_( "IO Channel failed to seek on read or write"),
|
||||
N_( "Memory allocation failed"),
|
||||
N_( "Invalid argument passed to ext2 library"),
|
||||
N_( "Could not allocate block in ext2 filesystem"),
|
||||
N_( "Could not allocate inode in ext2 filesystem"),
|
||||
N_( "Ext2 inode is not a directory"),
|
||||
N_( "Too many references in table"),
|
||||
N_( "File not found by ext2_lookup"),
|
||||
N_( "File open read-only"),
|
||||
N_( "Ext2 directory block not found"),
|
||||
N_( "Ext2 directory already exists"),
|
||||
N_( "Unimplemented ext2 library function"),
|
||||
N_( "User cancel requested"),
|
||||
N_( "Ext2 file too big"),
|
||||
N_( "Supplied journal device not a block device"),
|
||||
N_( "Journal superblock not found"),
|
||||
N_( "Journal must be at least 1024 blocks"),
|
||||
N_( "Unsupported journal version"),
|
||||
N_( "Error loading external journal"),
|
||||
N_( "Journal not found"),
|
||||
N_( "Directory hash unsupported"),
|
||||
N_( "Illegal extended attribute block number"),
|
||||
N_( "Cannot create filesystem with requested number of inodes"),
|
||||
N_( "E2image snapshot not in use"),
|
||||
N_( "Too many reserved group descriptor blocks"),
|
||||
N_( "Resize inode is corrupt"),
|
||||
N_( "Tried to set block bmap with missing indirect block"),
|
||||
N_( "TDB: Success"),
|
||||
N_( "TDB: Corrupt database"),
|
||||
N_( "TDB: IO Error"),
|
||||
N_( "TDB: Locking error"),
|
||||
N_( "TDB: Out of memory"),
|
||||
N_( "TDB: Record exists"),
|
||||
N_( "TDB: Lock exists on other keys"),
|
||||
N_( "TDB: Invalid parameter"),
|
||||
N_( "TDB: Record does not exist"),
|
||||
N_( "TDB: Write not permitted"),
|
||||
N_( "Ext2fs directory block list is empty"),
|
||||
N_( "Attempt to modify a block mapping via a read-only block iterator"),
|
||||
N_( "Wrong magic number for ext4 extent saved path"),
|
||||
N_( "Wrong magic number for 64-bit generic bitmap"),
|
||||
N_( "Wrong magic number for 64-bit block bitmap"),
|
||||
N_( "Wrong magic number for 64-bit inode bitmap"),
|
||||
N_( "Wrong magic number --- RESERVED_13"),
|
||||
N_( "Wrong magic number --- RESERVED_14"),
|
||||
N_( "Wrong magic number --- RESERVED_15"),
|
||||
N_( "Wrong magic number --- RESERVED_16"),
|
||||
N_( "Wrong magic number --- RESERVED_17"),
|
||||
N_( "Wrong magic number --- RESERVED_18"),
|
||||
N_( "Wrong magic number --- RESERVED_19"),
|
||||
N_( "Corrupt extent header"),
|
||||
N_( "Corrupt extent index"),
|
||||
N_( "Corrupt extent"),
|
||||
N_( "No free space in extent map"),
|
||||
N_( "Inode does not use extents"),
|
||||
N_( "No 'next' extent"),
|
||||
N_( "No 'previous' extent"),
|
||||
N_( "No 'up' extent"),
|
||||
N_( "No 'down' extent"),
|
||||
N_( "No current node"),
|
||||
N_( "Ext2fs operation not supported"),
|
||||
N_( "No room to insert extent in node"),
|
||||
N_( "Splitting would result in empty node"),
|
||||
N_( "Extent not found"),
|
||||
N_( "Operation not supported for inodes containing extents"),
|
||||
N_( "Extent length is invalid"),
|
||||
N_( "I/O Channel does not support 64-bit block numbers"),
|
||||
N_( "Can't check if filesystem is mounted due to missing mtab file"),
|
||||
N_( "Filesystem too large to use legacy bitmaps"),
|
||||
N_( "MMP: invalid magic number"),
|
||||
N_( "MMP: device currently active"),
|
||||
N_( "MMP: e2fsck being run"),
|
||||
N_( "MMP: block number beyond filesystem range"),
|
||||
N_( "MMP: undergoing an unknown operation"),
|
||||
N_( "MMP: filesystem still in use"),
|
||||
N_( "MMP: open with O_DIRECT failed"),
|
||||
N_( "Block group descriptor size incorrect"),
|
||||
N_( "Inode checksum does not match inode"),
|
||||
N_( "Inode bitmap checksum does not match bitmap"),
|
||||
N_( "Extent block checksum does not match extent block"),
|
||||
N_( "Directory block does not have space for checksum"),
|
||||
N_( "Directory block checksum does not match directory block"),
|
||||
N_( "Extended attribute block checksum does not match block"),
|
||||
N_( "Superblock checksum does not match superblock"),
|
||||
N_( "Unknown checksum algorithm"),
|
||||
N_( "MMP block checksum does not match"),
|
||||
N_( "Ext2 file already exists"),
|
||||
N_( "Block bitmap checksum does not match bitmap"),
|
||||
N_( "Cannot iterate data blocks of an inode containing inline data"),
|
||||
N_( "Extended attribute has an invalid name length"),
|
||||
N_( "Extended attribute has an invalid value length"),
|
||||
N_( "Extended attribute has an incorrect hash"),
|
||||
N_( "Extended attribute block has a bad header"),
|
||||
N_( "Extended attribute key not found"),
|
||||
N_( "Insufficient space to store extended attribute data"),
|
||||
N_( "Filesystem is missing ext_attr or inline_data feature"),
|
||||
N_( "Inode doesn't have inline data"),
|
||||
N_( "No block for an inode with inline data"),
|
||||
N_( "No free space in inline data"),
|
||||
N_( "Wrong magic number for extended attribute structure"),
|
||||
N_( "Inode seems to contain garbage"),
|
||||
N_( "Extended attribute has an invalid value offset"),
|
||||
N_( "Journal flags inconsistent"),
|
||||
N_( "Undo file corrupt"),
|
||||
N_( "Wrong undo file for this filesystem"),
|
||||
N_( "File system is corrupted"),
|
||||
N_( "Bad CRC detected in file system"),
|
||||
N_( "The journal superblock is corrupt"),
|
||||
N_( "Inode is corrupted"),
|
||||
N_( "Inode containing extended attribute value is corrupted"),
|
||||
N_( "Group descriptors not loaded"),
|
||||
N_( "The internal ext2_filsys data structure appears to be corrupted"),
|
||||
N_( "Found cyclic loop in extent tree"),
|
||||
N_( "Operation not supported on an external journal"),
|
||||
0
|
||||
};
|
||||
|
||||
struct error_table {
|
||||
char const * const * msgs;
|
||||
long base;
|
||||
int n_msgs;
|
||||
};
|
||||
struct et_list {
|
||||
struct et_list *next;
|
||||
const struct error_table * table;
|
||||
};
|
||||
extern struct et_list *_et_list;
|
||||
|
||||
const struct error_table et_ext2_error_table = { text, 2133571328L, 183 };
|
||||
|
||||
static struct et_list link = { 0, 0 };
|
||||
|
||||
void initialize_ext2_error_table_r(struct et_list **list);
|
||||
void initialize_ext2_error_table(void);
|
||||
|
||||
void initialize_ext2_error_table(void) {
|
||||
initialize_ext2_error_table_r(&_et_list);
|
||||
}
|
||||
|
||||
/* For Heimdal compatibility */
|
||||
void initialize_ext2_error_table_r(struct et_list **list)
|
||||
{
|
||||
struct et_list *et, **end;
|
||||
|
||||
for (end = list, et = *list; et; end = &et->next, et = et->next)
|
||||
if (et->table->msgs == text)
|
||||
return;
|
||||
et = malloc(sizeof(struct et_list));
|
||||
if (et == 0) {
|
||||
if (!link.table)
|
||||
et = &link;
|
||||
else
|
||||
return;
|
||||
}
|
||||
et->table = &et_ext2_error_table;
|
||||
et->next = 0;
|
||||
*end = et;
|
||||
}
|
||||
1777
jni/e2fsprogs/lib/ext2fs/ext_attr.c
Executable file
1777
jni/e2fsprogs/lib/ext2fs/ext_attr.c
Executable file
File diff suppressed because it is too large
Load Diff
1877
jni/e2fsprogs/lib/ext2fs/extent.c
Executable file
1877
jni/e2fsprogs/lib/ext2fs/extent.c
Executable file
File diff suppressed because it is too large
Load Diff
873
jni/e2fsprogs/lib/ext2fs/fallocate.c
Executable file
873
jni/e2fsprogs/lib/ext2fs/fallocate.c
Executable file
@@ -0,0 +1,873 @@
|
||||
/*
|
||||
* fallocate.c -- Allocate large chunks of file.
|
||||
*
|
||||
* Copyright (C) 2014 Oracle.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
|
||||
#else
|
||||
# define dbg_printf(f, a...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Extent-based fallocate code.
|
||||
*
|
||||
* Find runs of unmapped logical blocks by starting at start and walking the
|
||||
* extents until we reach the end of the range we want.
|
||||
*
|
||||
* For each run of unmapped blocks, try to find the extents on either side of
|
||||
* the range. If there's a left extent that can grow by at least a cluster and
|
||||
* there are lblocks between start and the next lcluster after start, see if
|
||||
* there's an implied cluster allocation; if so, zero the blocks (if the left
|
||||
* extent is initialized) and adjust the extent. Ditto for the blocks between
|
||||
* the end of the last full lcluster and end, if there's a right extent.
|
||||
*
|
||||
* Try to attach as much as we can to the left extent, then try to attach as
|
||||
* much as we can to the right extent. For the remainder, try to allocate the
|
||||
* whole range; map in whatever we get; and repeat until we're done.
|
||||
*
|
||||
* To attach to a left extent, figure out the maximum amount we can add to the
|
||||
* extent and try to allocate that much, and append if successful. To attach
|
||||
* to a right extent, figure out the max we can add to the extent, try to
|
||||
* allocate that much, and prepend if successful.
|
||||
*
|
||||
* We need an alloc_range function that tells us how much we can allocate given
|
||||
* a maximum length and one of a suggested start, a fixed start, or a fixed end
|
||||
* point.
|
||||
*
|
||||
* Every time we modify the extent tree we also need to update the block stats.
|
||||
*
|
||||
* At the end, update i_blocks and i_size appropriately.
|
||||
*/
|
||||
|
||||
static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)),
|
||||
const struct ext2fs_extent *extent EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (desc)
|
||||
printf("%s: ", desc);
|
||||
printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
|
||||
extent->e_lblk, extent->e_lblk + extent->e_len - 1,
|
||||
extent->e_len, extent->e_pblk);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
|
||||
fputs("LEAF ", stdout);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fputs("UNINIT ", stdout);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
|
||||
fputs("2ND_VISIT ", stdout);
|
||||
if (!extent->e_flags)
|
||||
fputs("(none)", stdout);
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t blk, blk64_t len)
|
||||
{
|
||||
blk64_t clusters;
|
||||
|
||||
clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) /
|
||||
EXT2FS_CLUSTER_RATIO(fs);
|
||||
ext2fs_block_alloc_stats_range(fs, blk,
|
||||
clusters * EXT2FS_CLUSTER_RATIO(fs), +1);
|
||||
return ext2fs_iblk_add_blocks(fs, inode, clusters);
|
||||
}
|
||||
|
||||
static errcode_t ext_falloc_helper(ext2_filsys fs,
|
||||
int flags,
|
||||
ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
struct ext2fs_extent *left_ext,
|
||||
struct ext2fs_extent *right_ext,
|
||||
blk64_t range_start, blk64_t range_len,
|
||||
blk64_t alloc_goal)
|
||||
{
|
||||
struct ext2fs_extent newex, ex;
|
||||
int op;
|
||||
blk64_t fillable, pblk, plen, x, y;
|
||||
blk64_t eof_blk = 0, cluster_fill = 0;
|
||||
errcode_t err;
|
||||
blk_t max_extent_len, max_uninit_len, max_init_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("%s: ", __func__);
|
||||
if (left_ext)
|
||||
printf("left_ext=%llu--%llu, ", left_ext->e_lblk,
|
||||
left_ext->e_lblk + left_ext->e_len - 1);
|
||||
if (right_ext)
|
||||
printf("right_ext=%llu--%llu, ", right_ext->e_lblk,
|
||||
right_ext->e_lblk + right_ext->e_len - 1);
|
||||
printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len,
|
||||
alloc_goal);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
/* Can't create initialized extents past EOF? */
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF))
|
||||
eof_blk = EXT2_I_SIZE(inode) / fs->blocksize;
|
||||
|
||||
/* The allocation goal must be as far into a cluster as range_start. */
|
||||
alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) |
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
|
||||
max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
|
||||
/* We must lengthen the left extent to the end of the cluster */
|
||||
if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
/* How many more blocks can be attached to left_ext? */
|
||||
if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - left_ext->e_len;
|
||||
else
|
||||
fillable = max_init_len - left_ext->e_len;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto expand_right;
|
||||
|
||||
/*
|
||||
* If range_start isn't on a cluster boundary, try an
|
||||
* implied cluster allocation for left_ext.
|
||||
*/
|
||||
cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill == 0)
|
||||
goto expand_right;
|
||||
|
||||
if (cluster_fill > fillable)
|
||||
cluster_fill = fillable;
|
||||
|
||||
/* Don't expand an initialized left_ext beyond EOF */
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
|
||||
x = left_ext->e_lblk + left_ext->e_len - 1;
|
||||
dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
|
||||
__func__, x, x + cluster_fill, eof_blk);
|
||||
if (eof_blk >= x && eof_blk <= x + cluster_fill)
|
||||
cluster_fill = eof_blk - x;
|
||||
if (cluster_fill == 0)
|
||||
goto expand_right;
|
||||
}
|
||||
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto expand_right;
|
||||
left_ext->e_len += cluster_fill;
|
||||
range_start += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
alloc_goal += cluster_fill;
|
||||
|
||||
dbg_print_extent("ext_falloc clus left+", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
|
||||
err = ext2fs_zero_blocks2(fs, left_ext->e_pblk +
|
||||
left_ext->e_len -
|
||||
cluster_fill, cluster_fill,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
expand_right:
|
||||
/* We must lengthen the right extent to the beginning of the cluster */
|
||||
if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
/* How much can we attach to right_ext? */
|
||||
if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - right_ext->e_len;
|
||||
else
|
||||
fillable = max_init_len - right_ext->e_len;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto try_merge;
|
||||
|
||||
/*
|
||||
* If range_end isn't on a cluster boundary, try an implied
|
||||
* cluster allocation for right_ext.
|
||||
*/
|
||||
cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill == 0)
|
||||
goto try_merge;
|
||||
|
||||
err = ext2fs_extent_goto(handle, right_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (cluster_fill > fillable)
|
||||
cluster_fill = fillable;
|
||||
right_ext->e_lblk -= cluster_fill;
|
||||
right_ext->e_pblk -= cluster_fill;
|
||||
right_ext->e_len += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
|
||||
dbg_print_extent("ext_falloc clus right+", right_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, right_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
|
||||
err = ext2fs_zero_blocks2(fs, right_ext->e_pblk,
|
||||
cluster_fill, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_merge:
|
||||
/* Merge both extents together, perhaps? */
|
||||
if (left_ext && right_ext) {
|
||||
/* Are the two extents mergeable? */
|
||||
if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) !=
|
||||
(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))
|
||||
goto try_left;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_left;
|
||||
|
||||
/*
|
||||
* Skip initialized extent unless user wants to zero blocks
|
||||
* or requires init extent.
|
||||
*/
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) ||
|
||||
!(flags & EXT2_FALLOCATE_FORCE_INIT)))
|
||||
goto try_left;
|
||||
|
||||
/* Will it even fit? */
|
||||
x = left_ext->e_len + range_len + right_ext->e_len;
|
||||
if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
|
||||
max_uninit_len : max_init_len))
|
||||
goto try_left;
|
||||
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto try_left;
|
||||
|
||||
/* Allocate blocks */
|
||||
y = left_ext->e_pblk + left_ext->e_len;
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH, y,
|
||||
right_ext->e_pblk - y + 1, NULL,
|
||||
&pblk, &plen);
|
||||
if (err)
|
||||
goto try_left;
|
||||
if (pblk + plen != right_ext->e_pblk)
|
||||
goto try_left;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify extents */
|
||||
left_ext->e_len = x;
|
||||
dbg_print_extent("ext_falloc merge", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_delete(handle, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
*right_ext = *left_ext;
|
||||
|
||||
/* Zero blocks */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, range_start, range_len,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try_left:
|
||||
/* Extend the left extent */
|
||||
if (left_ext) {
|
||||
/* How many more blocks can be attached to left_ext? */
|
||||
if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - left_ext->e_len;
|
||||
else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
|
||||
fillable = max_init_len - left_ext->e_len;
|
||||
else
|
||||
fillable = 0;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_right;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
|
||||
/* Don't expand an initialized left_ext beyond EOF */
|
||||
x = left_ext->e_lblk + left_ext->e_len - 1;
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
|
||||
dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
|
||||
__func__, x, x + fillable, eof_blk);
|
||||
if (eof_blk >= x && eof_blk <= x + fillable)
|
||||
fillable = eof_blk - x;
|
||||
}
|
||||
|
||||
if (fillable == 0)
|
||||
goto try_right;
|
||||
|
||||
/* Test if the right edge of the range is already mapped? */
|
||||
if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode,
|
||||
x + fillable, &pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk)
|
||||
fillable -= 1 + ((x + fillable)
|
||||
& EXT2FS_CLUSTER_MASK(fs));
|
||||
if (fillable == 0)
|
||||
goto try_right;
|
||||
}
|
||||
|
||||
/* Allocate range of blocks */
|
||||
x = left_ext->e_pblk + left_ext->e_len;
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH,
|
||||
x, fillable, NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto try_right;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify left_ext */
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
range_start += plen;
|
||||
range_len -= plen;
|
||||
left_ext->e_len += plen;
|
||||
dbg_print_extent("ext_falloc left+", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_right:
|
||||
/* Extend the right extent */
|
||||
if (right_ext) {
|
||||
/* How much can we attach to right_ext? */
|
||||
if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - right_ext->e_len;
|
||||
else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
|
||||
fillable = max_init_len - right_ext->e_len;
|
||||
else
|
||||
fillable = 0;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_anywhere;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto try_anywhere;
|
||||
|
||||
/* Test if the left edge of the range is already mapped? */
|
||||
if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode,
|
||||
right_ext->e_lblk - fillable, &pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk)
|
||||
fillable -= EXT2FS_CLUSTER_RATIO(fs) -
|
||||
((right_ext->e_lblk - fillable)
|
||||
& EXT2FS_CLUSTER_MASK(fs));
|
||||
if (fillable == 0)
|
||||
goto try_anywhere;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: It would be nice if we could handle allocating a
|
||||
* variable range from a fixed end point instead of just
|
||||
* skipping to the general allocator if the whole range is
|
||||
* unavailable.
|
||||
*/
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH,
|
||||
right_ext->e_pblk - fillable,
|
||||
fillable, NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto try_anywhere;
|
||||
err = claim_range(fs, inode,
|
||||
pblk & ~EXT2FS_CLUSTER_MASK(fs),
|
||||
plen + (pblk & EXT2FS_CLUSTER_MASK(fs)));
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify right_ext */
|
||||
err = ext2fs_extent_goto(handle, right_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
range_len -= plen;
|
||||
right_ext->e_lblk -= plen;
|
||||
right_ext->e_pblk -= plen;
|
||||
right_ext->e_len += plen;
|
||||
dbg_print_extent("ext_falloc right+", right_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, right_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk,
|
||||
plen + cluster_fill, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_anywhere:
|
||||
/* Try implied cluster alloc on the left and right ends */
|
||||
if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) {
|
||||
cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill > range_len)
|
||||
cluster_fill = range_len;
|
||||
newex.e_lblk = range_start;
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
|
||||
&pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk == 0)
|
||||
goto try_right_implied;
|
||||
newex.e_pblk = pblk;
|
||||
newex.e_len = cluster_fill;
|
||||
newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
|
||||
EXT2_EXTENT_FLAGS_UNINIT);
|
||||
dbg_print_extent("ext_falloc iclus left+", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, newex.e_pblk,
|
||||
newex.e_len, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
range_start += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
}
|
||||
|
||||
try_right_implied:
|
||||
y = range_start + range_len;
|
||||
if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) {
|
||||
cluster_fill = y & EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill > range_len)
|
||||
cluster_fill = range_len;
|
||||
newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
|
||||
&pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk == 0)
|
||||
goto no_implied;
|
||||
newex.e_pblk = pblk;
|
||||
newex.e_len = cluster_fill;
|
||||
newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
|
||||
EXT2_EXTENT_FLAGS_UNINIT);
|
||||
dbg_print_extent("ext_falloc iclus right+", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, newex.e_pblk,
|
||||
newex.e_len, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
range_len -= cluster_fill;
|
||||
}
|
||||
|
||||
no_implied:
|
||||
if (range_len == 0)
|
||||
return 0;
|
||||
|
||||
newex.e_lblk = range_start;
|
||||
if (flags & EXT2_FALLOCATE_FORCE_INIT) {
|
||||
max_extent_len = max_init_len;
|
||||
newex.e_flags = 0;
|
||||
} else {
|
||||
max_extent_len = max_uninit_len;
|
||||
newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT;
|
||||
}
|
||||
pblk = alloc_goal;
|
||||
y = range_len;
|
||||
for (x = 0; x < y;) {
|
||||
cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs);
|
||||
fillable = min(range_len + cluster_fill, max_extent_len);
|
||||
err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs),
|
||||
fillable,
|
||||
NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto out;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Create extent */
|
||||
newex.e_pblk = pblk + cluster_fill;
|
||||
newex.e_len = plen - cluster_fill;
|
||||
dbg_print_extent("ext_falloc create", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Update variables at end of loop */
|
||||
x += plen - cluster_fill;
|
||||
range_len -= plen - cluster_fill;
|
||||
newex.e_lblk += plen - cluster_fill;
|
||||
pblk += plen - cluster_fill;
|
||||
if (pblk >= ext2fs_blocks_count(fs->super))
|
||||
pblk = fs->super->s_first_data_block;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t goal,
|
||||
blk64_t start, blk64_t len)
|
||||
{
|
||||
ext2_extent_handle_t handle;
|
||||
struct ext2fs_extent left_extent, right_extent;
|
||||
struct ext2fs_extent *left_adjacent, *right_adjacent;
|
||||
errcode_t err;
|
||||
blk64_t range_start, range_end = 0, end, next;
|
||||
blk64_t count, goal_distance;
|
||||
|
||||
end = start + len - 1;
|
||||
err = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Find the extent closest to the start of the alloc range. We don't
|
||||
* check the return value because _goto() sets the current node to the
|
||||
* next-lowest extent if 'start' is in a hole; or the next-highest
|
||||
* extent if there aren't any lower ones; or doesn't set a current node
|
||||
* if there was a real error reading the extent tree. In that case,
|
||||
* _get() will error out.
|
||||
*/
|
||||
start_again:
|
||||
ext2fs_extent_goto(handle, start);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE) {
|
||||
blk64_t max_blocks = ext2fs_blocks_count(fs->super);
|
||||
|
||||
if (goal == ~0ULL)
|
||||
goal = ext2fs_find_inode_goal(fs, ino, inode, start);
|
||||
err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
|
||||
goal, max_blocks - 1, &goal);
|
||||
goal += start;
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
|
||||
NULL, start, len, goal);
|
||||
goto errout;
|
||||
} else if (err)
|
||||
goto errout;
|
||||
|
||||
dbg_print_extent("ext_falloc initial", &left_extent);
|
||||
next = left_extent.e_lblk + left_extent.e_len;
|
||||
if (left_extent.e_lblk > start) {
|
||||
/* The nearest extent we found was beyond start??? */
|
||||
goal = left_extent.e_pblk - (left_extent.e_lblk - start);
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
|
||||
&left_extent, start,
|
||||
left_extent.e_lblk - start, goal);
|
||||
if (err)
|
||||
goto errout;
|
||||
|
||||
goto start_again;
|
||||
} else if (next >= start) {
|
||||
range_start = next;
|
||||
left_adjacent = &left_extent;
|
||||
} else {
|
||||
range_start = start;
|
||||
left_adjacent = NULL;
|
||||
}
|
||||
goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
|
||||
|
||||
do {
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF,
|
||||
&right_extent);
|
||||
dbg_printf("%s: ino=%d get next =%d\n", __func__, ino,
|
||||
(int)err);
|
||||
dbg_print_extent("ext_falloc next", &right_extent);
|
||||
/* Stop if we've seen this extent before */
|
||||
if (!err && right_extent.e_lblk <= left_extent.e_lblk)
|
||||
err = EXT2_ET_EXTENT_NO_NEXT;
|
||||
|
||||
if (err && err != EXT2_ET_EXTENT_NO_NEXT)
|
||||
goto errout;
|
||||
if (err == EXT2_ET_EXTENT_NO_NEXT ||
|
||||
right_extent.e_lblk > end + 1) {
|
||||
range_end = end;
|
||||
right_adjacent = NULL;
|
||||
} else {
|
||||
/* Handle right_extent.e_lblk <= end */
|
||||
range_end = right_extent.e_lblk - 1;
|
||||
right_adjacent = &right_extent;
|
||||
}
|
||||
goal_distance = range_start - next;
|
||||
if (err != EXT2_ET_EXTENT_NO_NEXT &&
|
||||
goal_distance > (range_end - right_extent.e_lblk))
|
||||
goal = right_extent.e_pblk -
|
||||
(right_extent.e_lblk - range_start);
|
||||
|
||||
dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino,
|
||||
range_start, range_end);
|
||||
err = 0;
|
||||
if (range_start <= range_end) {
|
||||
count = range_end - range_start + 1;
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle,
|
||||
left_adjacent, right_adjacent,
|
||||
range_start, count, goal);
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (range_end == end)
|
||||
break;
|
||||
|
||||
err = ext2fs_extent_goto(handle, right_extent.e_lblk);
|
||||
if (err)
|
||||
goto errout;
|
||||
next = right_extent.e_lblk + right_extent.e_len;
|
||||
left_extent = right_extent;
|
||||
left_adjacent = &left_extent;
|
||||
range_start = next;
|
||||
goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
|
||||
} while (range_end < end);
|
||||
|
||||
errout:
|
||||
ext2fs_extent_free(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map physical blocks to a range of logical blocks within a file. The range
|
||||
* of logical blocks are (start, start + len). If there are already extents,
|
||||
* the mappings will try to extend the mappings; otherwise, it will try to map
|
||||
* start as if logical block 0 points to goal. If goal is ~0ULL, then the goal
|
||||
* is calculated based on the inode group.
|
||||
*
|
||||
* Flags:
|
||||
* - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated.
|
||||
* - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents.
|
||||
* - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents.
|
||||
* - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF.
|
||||
*
|
||||
* If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will
|
||||
* try to expand any extents it finds, zeroing blocks as necessary.
|
||||
*/
|
||||
errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t goal,
|
||||
blk64_t start, blk64_t len)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
blk64_t blk, x, zero_blk, last = 0;
|
||||
int zero_len = 0;
|
||||
errcode_t err;
|
||||
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(flags & EXT2_FALLOCATE_FORCE_UNINIT)) ||
|
||||
(flags & ~EXT2_FALLOCATE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (len > ext2fs_blocks_count(fs->super))
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
else if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Read inode structure if necessary */
|
||||
if (!inode) {
|
||||
err = ext2fs_read_inode(fs, ino, &inode_buf);
|
||||
if (err)
|
||||
return err;
|
||||
inode = &inode_buf;
|
||||
}
|
||||
dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino,
|
||||
start, len, goal);
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
err = extent_fallocate(fs, flags, ino, inode, goal, start, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX: Allocate a bunch of blocks the slow way */
|
||||
for (blk = start; blk < start + len; blk++) {
|
||||
err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x);
|
||||
if (err)
|
||||
return err;
|
||||
if (x)
|
||||
continue;
|
||||
|
||||
err = ext2fs_bmap2(fs, ino, inode, NULL, BMAP_ALLOC,
|
||||
blk, 0, &x);
|
||||
if (err)
|
||||
goto errout;
|
||||
if ((zero_len && (x != last+1)) ||
|
||||
(zero_len >= 65536)) {
|
||||
err = ext2fs_zero_blocks2(fs, zero_blk, zero_len,
|
||||
NULL, NULL);
|
||||
zero_len = 0;
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
if (zero_len == 0) {
|
||||
zero_blk = x;
|
||||
zero_len = 1;
|
||||
} else {
|
||||
zero_len++;
|
||||
}
|
||||
last = x;
|
||||
}
|
||||
|
||||
out:
|
||||
if (inode == &inode_buf)
|
||||
ext2fs_write_inode(fs, ino, inode);
|
||||
errout:
|
||||
if (zero_len)
|
||||
ext2fs_zero_blocks2(fs, zero_blk, zero_len, NULL, NULL);
|
||||
return err;
|
||||
}
|
||||
666
jni/e2fsprogs/lib/ext2fs/fileio.c
Executable file
666
jni/e2fsprogs/lib/ext2fs/fileio.c
Executable file
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct ext2_file {
|
||||
errcode_t magic;
|
||||
ext2_filsys fs;
|
||||
ext2_ino_t ino;
|
||||
struct ext2_inode inode;
|
||||
int flags;
|
||||
__u64 pos;
|
||||
blk64_t blockno;
|
||||
blk64_t physblock;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
struct block_entry {
|
||||
blk64_t physblock;
|
||||
unsigned char sha[EXT2FS_SHA512_LENGTH];
|
||||
};
|
||||
typedef struct block_entry *block_entry_t;
|
||||
|
||||
#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_array(3, fs->blocksize, &file->buf);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
*ret = file;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (file->buf)
|
||||
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 returns the pointer to the inode of a file from the structure
|
||||
*/
|
||||
struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file)
|
||||
{
|
||||
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
|
||||
return NULL;
|
||||
return &file->inode;
|
||||
}
|
||||
|
||||
/* This function returns the inode number from the structure */
|
||||
ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file)
|
||||
{
|
||||
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
|
||||
return 0;
|
||||
return file->ino;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
int ret_flags;
|
||||
blk64_t dontcare;
|
||||
|
||||
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;
|
||||
|
||||
/* Is this an uninit block? */
|
||||
if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER,
|
||||
0, file->blockno, &ret_flags, &dontcare);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (ret_flags & BMAP_RET_UNINIT) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER, BMAP_SET,
|
||||
file->blockno, 0,
|
||||
&file->physblock);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, the physical block hasn't been allocated yet.
|
||||
* Allocate it.
|
||||
*/
|
||||
if (!file->physblock) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
|
||||
file->blockno, 0, &file->physblock);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = io_channel_write_blk64(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)
|
||||
{
|
||||
blk64_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;
|
||||
int ret_flags;
|
||||
|
||||
if (!(file->flags & EXT2_FILE_BUF_VALID)) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER, 0, file->blockno, &ret_flags,
|
||||
&file->physblock);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (!dontfill) {
|
||||
if (file->physblock &&
|
||||
!(ret_flags & BMAP_RET_UNINIT)) {
|
||||
retval = io_channel_read_blk64(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);
|
||||
|
||||
if (file->buf)
|
||||
ext2fs_free_mem(&file->buf);
|
||||
ext2fs_free_mem(&file);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static errcode_t
|
||||
ext2fs_file_read_inline_data(ext2_file_t file, void *buf,
|
||||
unsigned int wanted, unsigned int *got)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval;
|
||||
unsigned int count = 0;
|
||||
size_t size;
|
||||
|
||||
fs = file->fs;
|
||||
retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
|
||||
file->buf, &size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (file->pos >= size)
|
||||
goto out;
|
||||
|
||||
count = size - file->pos;
|
||||
if (count > wanted)
|
||||
count = wanted;
|
||||
memcpy(buf, file->buf + file->pos, count);
|
||||
file->pos += count;
|
||||
buf = (char *) buf + count;
|
||||
|
||||
out:
|
||||
if (got)
|
||||
*got = count;
|
||||
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;
|
||||
|
||||
/* If an inode has inline data, things get complicated. */
|
||||
if (file->inode.i_flags & EXT4_INLINE_DATA_FL)
|
||||
return ext2fs_file_read_inline_data(file, buf, wanted, got);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static errcode_t
|
||||
ext2fs_file_write_inline_data(ext2_file_t file, const void *buf,
|
||||
unsigned int nbytes, unsigned int *written)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval;
|
||||
unsigned int count = 0;
|
||||
size_t size;
|
||||
|
||||
fs = file->fs;
|
||||
retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
|
||||
file->buf, &size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (file->pos < size) {
|
||||
count = nbytes - file->pos;
|
||||
memcpy(file->buf + file->pos, buf, count);
|
||||
|
||||
retval = ext2fs_inline_data_set(fs, file->ino, &file->inode,
|
||||
file->buf, count);
|
||||
if (retval == EXT2_ET_INLINE_DATA_NO_SPACE)
|
||||
goto expand;
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
file->pos += count;
|
||||
|
||||
/* Update inode size */
|
||||
if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
|
||||
errcode_t rc;
|
||||
|
||||
rc = ext2fs_file_set_size2(file, file->pos);
|
||||
if (retval == 0)
|
||||
retval = rc;
|
||||
}
|
||||
|
||||
if (written)
|
||||
*written = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
expand:
|
||||
retval = ext2fs_inline_data_expand(fs, file->ino);
|
||||
if (retval)
|
||||
return retval;
|
||||
/*
|
||||
* reload inode and return no space error
|
||||
*
|
||||
* XXX: file->inode could be copied from the outside
|
||||
* in ext2fs_file_open2(). We have no way to modify
|
||||
* the outside inode.
|
||||
*/
|
||||
retval = ext2fs_read_inode(fs, file->ino, &file->inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
return EXT2_ET_INLINE_DATA_NO_SPACE;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
block_entry_t new_block = NULL, old_block = NULL;
|
||||
int bmap_flags = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
fs = file->fs;
|
||||
|
||||
if (!(file->flags & EXT2_FILE_WRITE))
|
||||
return EXT2_ET_FILE_RO;
|
||||
|
||||
/* If an inode has inline data, things get complicated. */
|
||||
if (file->inode.i_flags & EXT4_INLINE_DATA_FL) {
|
||||
retval = ext2fs_file_write_inline_data(file, buf, nbytes,
|
||||
written);
|
||||
if (retval != EXT2_ET_INLINE_DATA_NO_SPACE)
|
||||
return retval;
|
||||
/* fall through to read data from the block */
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* OK, the physical block hasn't been allocated yet.
|
||||
* Allocate it.
|
||||
*/
|
||||
if (!file->physblock) {
|
||||
bmap_flags = (file->ino ? BMAP_ALLOC : 0);
|
||||
if (fs->flags & EXT2_FLAG_SHARE_DUP) {
|
||||
new_block = calloc(1, sizeof(*new_block));
|
||||
if (!new_block) {
|
||||
retval = EXT2_ET_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
ext2fs_sha512((const unsigned char*)file->buf,
|
||||
fs->blocksize, new_block->sha);
|
||||
old_block = ext2fs_hashmap_lookup(
|
||||
fs->block_sha_map,
|
||||
new_block->sha,
|
||||
sizeof(new_block->sha));
|
||||
}
|
||||
|
||||
if (old_block) {
|
||||
file->physblock = old_block->physblock;
|
||||
bmap_flags |= BMAP_SET;
|
||||
free(new_block);
|
||||
new_block = NULL;
|
||||
}
|
||||
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER,
|
||||
bmap_flags,
|
||||
file->blockno, 0,
|
||||
&file->physblock);
|
||||
if (retval) {
|
||||
free(new_block);
|
||||
new_block = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (new_block) {
|
||||
new_block->physblock = file->physblock;
|
||||
int ret = ext2fs_hashmap_add(fs->block_sha_map,
|
||||
new_block, new_block->sha,
|
||||
sizeof(new_block->sha));
|
||||
if (ret) {
|
||||
retval = EXT2_ET_NO_MEMORY;
|
||||
free(new_block);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (bmap_flags & BMAP_SET) {
|
||||
ext2fs_iblk_add_blocks(fs, &file->inode, 1);
|
||||
ext2fs_write_inode(fs, file->ino, &file->inode);
|
||||
}
|
||||
}
|
||||
|
||||
file->pos += c;
|
||||
ptr += c;
|
||||
count += c;
|
||||
nbytes -= c;
|
||||
}
|
||||
|
||||
fail:
|
||||
/* Update inode size */
|
||||
if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
|
||||
errcode_t rc;
|
||||
|
||||
rc = ext2fs_file_set_size2(file, file->pos);
|
||||
if (retval == 0)
|
||||
retval = rc;
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Zero the parts of the last block that are past EOF. */
|
||||
static errcode_t ext2fs_file_zero_past_offset(ext2_file_t file,
|
||||
ext2_off64_t offset)
|
||||
{
|
||||
ext2_filsys fs = file->fs;
|
||||
char *b = NULL;
|
||||
ext2_off64_t off = offset % fs->blocksize;
|
||||
blk64_t blk;
|
||||
int ret_flags;
|
||||
errcode_t retval;
|
||||
|
||||
if (off == 0)
|
||||
return 0;
|
||||
|
||||
retval = sync_buffer_position(file);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Is there an initialized block at the end? */
|
||||
retval = ext2fs_bmap2(fs, file->ino, NULL, NULL, 0,
|
||||
offset / fs->blocksize, &ret_flags, &blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
if ((blk == 0) || (ret_flags & BMAP_RET_UNINIT))
|
||||
return 0;
|
||||
|
||||
/* Zero to the end of the block */
|
||||
retval = ext2fs_get_mem(fs->blocksize, &b);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Read/zero/write block */
|
||||
retval = io_channel_read_blk64(fs->io, blk, 1, b);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
memset(b + off, 0, fs->blocksize - off);
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, blk, 1, b);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
ext2fs_free_mem(&b);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sets the size of the file, truncating it if necessary
|
||||
*
|
||||
*/
|
||||
errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size)
|
||||
{
|
||||
ext2_off64_t old_size;
|
||||
errcode_t retval;
|
||||
blk64_t old_truncate, truncate_block;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
|
||||
if (size && ext2fs_file_block_offset_too_big(file->fs, &file->inode,
|
||||
(size - 1) / file->fs->blocksize))
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
truncate_block = ((size + file->fs->blocksize - 1) >>
|
||||
EXT2_BLOCK_SIZE_BITS(file->fs->super));
|
||||
old_size = EXT2_I_SIZE(&file->inode);
|
||||
old_truncate = ((old_size + file->fs->blocksize - 1) >>
|
||||
EXT2_BLOCK_SIZE_BITS(file->fs->super));
|
||||
|
||||
retval = ext2fs_inode_size_set(file->fs, &file->inode, size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (file->ino) {
|
||||
retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_file_zero_past_offset(file, size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (truncate_block >= old_truncate)
|
||||
return 0;
|
||||
|
||||
return ext2fs_punch(file->fs, file->ino, &file->inode, 0,
|
||||
truncate_block, ~0ULL);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
|
||||
{
|
||||
return ext2fs_file_set_size2(file, size);
|
||||
}
|
||||
218
jni/e2fsprogs/lib/ext2fs/finddev.c
Executable file
218
jni/e2fsprogs/lib/ext2fs/finddev.c
Executable file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.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 = malloc(sizeof(struct dir_list));
|
||||
if (!dp)
|
||||
return;
|
||||
dp->name = malloc(strlen(name)+1);
|
||||
if (!dp->name) {
|
||||
free(dp);
|
||||
return;
|
||||
}
|
||||
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 *dirname, 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(dirname);
|
||||
if ((dir = opendir(dirname)) == 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", dirname, dp->d_name);
|
||||
if (stat(path, &st) < 0)
|
||||
goto skip_to_next;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
add_to_dirlist(path, list);
|
||||
if (ext2fsP_is_disk_device(st.st_mode) &&
|
||||
st.st_rdev == device) {
|
||||
cp = malloc(strlen(path)+1);
|
||||
if (!cp) {
|
||||
closedir(dir);
|
||||
return ENOMEM;
|
||||
}
|
||||
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 = 0, *new_list = 0;
|
||||
struct dir_list *current;
|
||||
char *ret_path = 0;
|
||||
int level = 0;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/* Avoid infinite loop */
|
||||
if (++level >= EXT2FS_MAX_NESTED_LINKS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 = "Couldn't 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("Couldn't find device.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
88
jni/e2fsprogs/lib/ext2fs/flushb.c
Executable file
88
jni/e2fsprogs/lib/ext2fs/flushb.c
Executable file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 defined(HAVE_FSYNC)
|
||||
if (fsync (fd) == -1)
|
||||
return errno;
|
||||
#endif
|
||||
|
||||
if (flushb) {
|
||||
errcode_t retval = 0;
|
||||
|
||||
#ifdef BLKFLSBUF
|
||||
if (ioctl (fd, BLKFLSBUF, 0) == 0)
|
||||
return 0;
|
||||
retval = errno;
|
||||
#elif defined(__linux__)
|
||||
#warning BLKFLSBUF not defined
|
||||
#endif
|
||||
#ifdef FDFLUSH
|
||||
/* In case this is a floppy */
|
||||
if (ioctl(fd, FDFLUSH, 0) == 0)
|
||||
return 0;
|
||||
if (retval == 0)
|
||||
retval = errno;
|
||||
#elif defined(__linux__)
|
||||
#warning FDFLUSH not defined
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
108
jni/e2fsprogs/lib/ext2fs/freefs.c
Executable file
108
jni/e2fsprogs/lib/ext2fs/freefs.c
Executable file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
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);
|
||||
}
|
||||
if (fs->device_name)
|
||||
ext2fs_free_mem(&fs->device_name);
|
||||
if (fs->super)
|
||||
ext2fs_free_mem(&fs->super);
|
||||
if (fs->orig_super)
|
||||
ext2fs_free_mem(&fs->orig_super);
|
||||
if (fs->group_desc)
|
||||
ext2fs_free_mem(&fs->group_desc);
|
||||
if (fs->block_map)
|
||||
ext2fs_free_block_bitmap(fs->block_map);
|
||||
if (fs->inode_map)
|
||||
ext2fs_free_inode_bitmap(fs->inode_map);
|
||||
if (fs->image_header)
|
||||
ext2fs_free_mem(&fs->image_header);
|
||||
|
||||
if (fs->badblocks)
|
||||
ext2fs_badblocks_list_free(fs->badblocks);
|
||||
fs->badblocks = 0;
|
||||
|
||||
if (fs->dblist)
|
||||
ext2fs_free_dblist(fs->dblist);
|
||||
|
||||
if (fs->icache)
|
||||
ext2fs_free_inode_cache(fs->icache);
|
||||
|
||||
if (fs->mmp_buf)
|
||||
ext2fs_free_mem(&fs->mmp_buf);
|
||||
if (fs->mmp_cmp)
|
||||
ext2fs_free_mem(&fs->mmp_cmp);
|
||||
|
||||
if (fs->block_sha_map)
|
||||
ext2fs_hashmap_free(fs->block_sha_map);
|
||||
|
||||
fs->magic = 0;
|
||||
|
||||
ext2fs_zero_blocks2(NULL, 0, 0, NULL, NULL);
|
||||
ext2fs_free_mem(&fs);
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure frees a badblocks list.
|
||||
*/
|
||||
void ext2fs_u32_list_free(ext2_u32_list bb)
|
||||
{
|
||||
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
|
||||
return;
|
||||
|
||||
if (bb->list)
|
||||
ext2fs_free_mem(&bb->list);
|
||||
bb->list = 0;
|
||||
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;
|
||||
|
||||
if (dblist->list)
|
||||
ext2fs_free_mem(&dblist->list);
|
||||
dblist->list = 0;
|
||||
if (dblist->fs && dblist->fs->dblist == dblist)
|
||||
dblist->fs->dblist = 0;
|
||||
dblist->magic = 0;
|
||||
ext2fs_free_mem(&dblist);
|
||||
}
|
||||
|
||||
650
jni/e2fsprogs/lib/ext2fs/gen_bitmap.c
Executable file
650
jni/e2fsprogs/lib/ext2fs/gen_bitmap.c
Executable file
@@ -0,0 +1,650 @@
|
||||
/*
|
||||
* gen_bitmap.c --- Generic (32-bit) bitmap routines
|
||||
*
|
||||
* Copyright (C) 2001 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#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"
|
||||
|
||||
struct ext2fs_struct_generic_bitmap_32 {
|
||||
errcode_t magic;
|
||||
ext2_filsys fs;
|
||||
__u32 start, end;
|
||||
__u32 real_end;
|
||||
char * description;
|
||||
char * bitmap;
|
||||
errcode_t base_error_code;
|
||||
__u32 reserved[7];
|
||||
};
|
||||
|
||||
typedef struct ext2fs_struct_generic_bitmap_32 *ext2fs_generic_bitmap_32;
|
||||
|
||||
#define EXT2FS_IS_32_BITMAP(bmap) \
|
||||
(((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP))
|
||||
|
||||
#define EXT2FS_IS_64_BITMAP(bmap) \
|
||||
(((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP64) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64))
|
||||
|
||||
/*
|
||||
* Used by previously inlined function, so we have to export this and
|
||||
* not change the function signature
|
||||
*/
|
||||
void ext2fs_warn_bitmap2(ext2fs_generic_bitmap gen_bitmap,
|
||||
int code, unsigned long arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (bitmap->description)
|
||||
com_err(0, bitmap->base_error_code+code,
|
||||
"#%lu for %s", arg, bitmap->description);
|
||||
else
|
||||
com_err(0, bitmap->base_error_code + code, "#%lu", arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static errcode_t check_magic(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
if (!bitmap || !((bitmap->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) ||
|
||||
(bitmap->magic == EXT2_ET_MAGIC_INODE_BITMAP) ||
|
||||
(bitmap->magic == EXT2_ET_MAGIC_BLOCK_BITMAP)))
|
||||
return EXT2_ET_MAGIC_GENERIC_BITMAP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs,
|
||||
__u32 start, __u32 end, __u32 real_end,
|
||||
const char *descr, char *init_map,
|
||||
ext2fs_generic_bitmap *ret)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap_32),
|
||||
&bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bitmap->magic = magic;
|
||||
bitmap->fs = fs;
|
||||
bitmap->start = start;
|
||||
bitmap->end = end;
|
||||
bitmap->real_end = real_end;
|
||||
switch (magic) {
|
||||
case EXT2_ET_MAGIC_INODE_BITMAP:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
|
||||
break;
|
||||
case EXT2_ET_MAGIC_BLOCK_BITMAP:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
/* Round up to allow for the BT x86 instruction */
|
||||
size = (size + 7) & ~3;
|
||||
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 = (ext2fs_generic_bitmap) bitmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
|
||||
__u32 end,
|
||||
__u32 real_end,
|
||||
const char *descr,
|
||||
ext2fs_generic_bitmap *ret)
|
||||
{
|
||||
return ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_GENERIC_BITMAP, 0,
|
||||
start, end, real_end, descr, 0, ret);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap gen_src,
|
||||
ext2fs_generic_bitmap *dest)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 src = (ext2fs_generic_bitmap_32) gen_src;
|
||||
|
||||
return (ext2fs_make_generic_bitmap(src->magic, src->fs,
|
||||
src->start, src->end,
|
||||
src->real_end,
|
||||
src->description, src->bitmap,
|
||||
dest));
|
||||
}
|
||||
|
||||
void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
if (check_magic(gen_bitmap))
|
||||
return;
|
||||
|
||||
bitmap->magic = 0;
|
||||
if (bitmap->description) {
|
||||
ext2fs_free_mem(&bitmap->description);
|
||||
bitmap->description = 0;
|
||||
}
|
||||
if (bitmap->bitmap) {
|
||||
ext2fs_free_mem(&bitmap->bitmap);
|
||||
bitmap->bitmap = 0;
|
||||
}
|
||||
ext2fs_free_mem(&bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
|
||||
blk_t bitno)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_test_generic_bmap(bitmap, bitno);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"test_bitmap(%lu)", (unsigned long) bitno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_bit(bitno - bitmap32->start, bitmap32->bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
|
||||
__u32 bitno)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_mark_generic_bmap(bitmap, bitno);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"mark_bitmap(%lu)", (unsigned long) bitno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_set_bit(bitno - bitmap32->start, bitmap32->bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
|
||||
blk_t bitno)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_unmark_generic_bmap(bitmap, bitno);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"mark_bitmap(%lu)", (unsigned long) bitno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_clear_bit(bitno - bitmap32->start, bitmap32->bitmap);
|
||||
}
|
||||
|
||||
__u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_get_generic_bmap_start(bitmap);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"get_bitmap_start");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap32->start;
|
||||
}
|
||||
|
||||
__u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_get_generic_bmap_end(bitmap);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"get_bitmap_end");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return bitmap32->end;
|
||||
}
|
||||
|
||||
void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
ext2fs_clear_generic_bmap(bitmap);
|
||||
return;
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"clear_generic_bitmap");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
memset(bitmap32->bitmap, 0,
|
||||
(size_t) (((bitmap32->real_end - bitmap32->start) / 8) + 1));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap gen_bitmap,
|
||||
errcode_t magic, errcode_t neq,
|
||||
ext2_ino_t end, ext2_ino_t *oend)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
EXT2_CHECK_MAGIC(bitmap, magic);
|
||||
|
||||
if (end > bitmap->real_end)
|
||||
return neq;
|
||||
if (oend)
|
||||
*oend = bitmap->end;
|
||||
bitmap->end = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_generic_bitmap(errcode_t magic,
|
||||
__u32 new_end, __u32 new_real_end,
|
||||
ext2fs_generic_bitmap gen_bmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
|
||||
errcode_t retval;
|
||||
size_t size, new_size;
|
||||
__u32 bitno;
|
||||
|
||||
if (!bmap || (bmap->magic != magic))
|
||||
return magic;
|
||||
|
||||
/*
|
||||
* 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_compare_generic_bitmap(errcode_t magic, errcode_t neq,
|
||||
ext2fs_generic_bitmap gen_bm1,
|
||||
ext2fs_generic_bitmap gen_bm2)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bm1 = (ext2fs_generic_bitmap_32) gen_bm1;
|
||||
ext2fs_generic_bitmap_32 bm2 = (ext2fs_generic_bitmap_32) gen_bm2;
|
||||
blk_t i;
|
||||
|
||||
if (!bm1 || bm1->magic != magic)
|
||||
return magic;
|
||||
if (!bm2 || bm2->magic != magic)
|
||||
return magic;
|
||||
|
||||
if ((bm1->start != bm2->start) ||
|
||||
(bm1->end != bm2->end) ||
|
||||
(memcmp(bm1->bitmap, bm2->bitmap,
|
||||
(size_t) (bm1->end - bm1->start)/8)))
|
||||
return neq;
|
||||
|
||||
for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
|
||||
if (ext2fs_fast_test_block_bitmap(gen_bm1, i) !=
|
||||
ext2fs_fast_test_block_bitmap(gen_bm2, i))
|
||||
return neq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap gen_map)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 map = (ext2fs_generic_bitmap_32) gen_map;
|
||||
__u32 i, j;
|
||||
|
||||
/* Protect loop from wrap-around if map->real_end is maxed */
|
||||
for (i=map->end+1, j = i - map->start;
|
||||
i <= map->real_end && i > map->end;
|
||||
i++, j++)
|
||||
ext2fs_set_bit(j, map->bitmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
errcode_t magic,
|
||||
__u32 start, __u32 num,
|
||||
void *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
|
||||
|
||||
if (!bmap || (bmap->magic != magic))
|
||||
return magic;
|
||||
|
||||
if ((start < bmap->start) || (start+num-1 > bmap->real_end))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
memcpy(out, bmap->bitmap + ((start - bmap->start) >> 3), (num+7) >> 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
errcode_t magic,
|
||||
__u32 start, __u32 num,
|
||||
void *in)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
|
||||
|
||||
if (!bmap || (bmap->magic != magic))
|
||||
return magic;
|
||||
|
||||
if ((start < bmap->start) || (start+num-1 > bmap->real_end))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
memcpy(bmap->bitmap + ((start - bmap->start) >> 3), in, (num+7) >> 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare @mem to zero buffer by 256 bytes.
|
||||
* Return 1 if @mem is zeroed memory, otherwise return 0.
|
||||
*/
|
||||
int ext2fs_mem_is_zero(const char *mem, size_t len)
|
||||
{
|
||||
static const char zero_buf[256];
|
||||
|
||||
while (len >= sizeof(zero_buf)) {
|
||||
if (memcmp(mem, zero_buf, sizeof(zero_buf)))
|
||||
return 0;
|
||||
len -= sizeof(zero_buf);
|
||||
mem += sizeof(zero_buf);
|
||||
}
|
||||
/* Deal with leftover bytes. */
|
||||
if (len)
|
||||
return !memcmp(mem, zero_buf, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if all of the bits in a specified range are clear
|
||||
*/
|
||||
static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap gen_bitmap,
|
||||
unsigned int start,
|
||||
unsigned int len)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
size_t start_byte, len_byte = len >> 3;
|
||||
unsigned int start_bit, len_bit = len % 8;
|
||||
int first_bit = 0;
|
||||
int last_bit = 0;
|
||||
int mark_count = 0;
|
||||
int mark_bit = 0;
|
||||
int i;
|
||||
const char *ADDR = bitmap->bitmap;
|
||||
|
||||
start -= bitmap->start;
|
||||
start_byte = start >> 3;
|
||||
start_bit = start % 8;
|
||||
|
||||
if (start_bit != 0) {
|
||||
/*
|
||||
* The compared start block number or start inode number
|
||||
* is not the first bit in a byte.
|
||||
*/
|
||||
mark_count = 8 - start_bit;
|
||||
if (len < 8 - start_bit) {
|
||||
mark_count = (int)len;
|
||||
mark_bit = len + start_bit - 1;
|
||||
} else
|
||||
mark_bit = 7;
|
||||
|
||||
for (i = mark_count; i > 0; i--, mark_bit--)
|
||||
first_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the first byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (first_bit & ADDR[start_byte])
|
||||
return 0;
|
||||
else if (len <= 8 - start_bit)
|
||||
return 1;
|
||||
|
||||
start_byte++;
|
||||
len_bit = (len - mark_count) % 8;
|
||||
len_byte = (len - mark_count) >> 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* The compared start block number or start inode number is
|
||||
* the first bit in a byte.
|
||||
*/
|
||||
if (len_bit != 0) {
|
||||
/*
|
||||
* The compared end block number or end inode number is
|
||||
* not the last bit in a byte.
|
||||
*/
|
||||
for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--)
|
||||
last_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the last byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (last_bit & ADDR[start_byte + len_byte])
|
||||
return 0;
|
||||
else if (len_byte == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check whether all bytes are 0 */
|
||||
return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u32 start, __u32 end,
|
||||
__u32 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
blk_t b;
|
||||
|
||||
if (start < bitmap->start || end > bitmap->end || start > end) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
while (start <= end) {
|
||||
b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap);
|
||||
if (!b) {
|
||||
*out = start;
|
||||
return 0;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u32 start, __u32 end,
|
||||
__u32 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
blk_t b;
|
||||
|
||||
if (start < bitmap->start || end > bitmap->end || start > end) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
while (start <= end) {
|
||||
b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap);
|
||||
if (b) {
|
||||
*out = start;
|
||||
return 0;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
|
||||
blk_t block, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
|
||||
if ((block < bitmap->start) || (block > bitmap->real_end) ||
|
||||
(block+num-1 > bitmap->real_end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
|
||||
block, bitmap->description);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap)
|
||||
bitmap, block, num);
|
||||
}
|
||||
|
||||
int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap gen_bitmap,
|
||||
ext2_ino_t inode, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
|
||||
if ((inode < bitmap->start) || (inode > bitmap->real_end) ||
|
||||
(inode+num-1 > bitmap->real_end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
|
||||
inode, bitmap->description);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap)
|
||||
bitmap, inode, num);
|
||||
}
|
||||
|
||||
void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
|
||||
blk_t block, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
int i;
|
||||
|
||||
if ((block < bitmap->start) || (block > bitmap->end) ||
|
||||
(block+num-1 > bitmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
|
||||
bitmap->description);
|
||||
return;
|
||||
}
|
||||
for (i=0; i < num; i++)
|
||||
ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap);
|
||||
}
|
||||
|
||||
void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
|
||||
blk_t block, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
int i;
|
||||
|
||||
if ((block < bitmap->start) || (block > bitmap->end) ||
|
||||
(block+num-1 > bitmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
|
||||
bitmap->description);
|
||||
return;
|
||||
}
|
||||
for (i=0; i < num; i++)
|
||||
ext2fs_fast_clear_bit(block + i - bitmap->start,
|
||||
bitmap->bitmap);
|
||||
}
|
||||
|
||||
981
jni/e2fsprogs/lib/ext2fs/gen_bitmap64.c
Executable file
981
jni/e2fsprogs/lib/ext2fs/gen_bitmap64.c
Executable file
@@ -0,0 +1,981 @@
|
||||
/*
|
||||
* gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and
|
||||
* block bitmaps.
|
||||
*
|
||||
* Copyright (C) 2007, 2008 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
|
||||
/*
|
||||
* Design of 64-bit bitmaps
|
||||
*
|
||||
* In order maintain ABI compatibility with programs that don't
|
||||
* understand about 64-bit blocks/inodes,
|
||||
* ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap()
|
||||
* will create old-style bitmaps unless the application passes the
|
||||
* flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is
|
||||
* passed, then we know the application has been recompiled, so we can
|
||||
* use the new-style bitmaps. If it is not passed, we have to return
|
||||
* an error if trying to open a filesystem which needs 64-bit bitmaps.
|
||||
*
|
||||
* The new bitmaps use a new set of structure magic numbers, so that
|
||||
* both the old-style and new-style interfaces can identify which
|
||||
* version of the data structure was used. Both the old-style and
|
||||
* new-style interfaces will support either type of bitmap, although
|
||||
* of course 64-bit operation will only be possible when both the
|
||||
* new-style interface and the new-style bitmap are used.
|
||||
*
|
||||
* For example, the new bitmap interfaces will check the structure
|
||||
* magic numbers and so will be able to detect old-stype bitmap. If
|
||||
* they see an old-style bitmap, they will pass it to the gen_bitmap.c
|
||||
* functions for handling. The same will be true for the old
|
||||
* interfaces as well.
|
||||
*
|
||||
* The new-style interfaces will have several different back-end
|
||||
* implementations, so we can support different encodings that are
|
||||
* appropriate for different applications. In general the default
|
||||
* should be whatever makes sense, and what the application/library
|
||||
* will use. However, e2fsck may need specialized implementations for
|
||||
* its own uses. For example, when doing parent directory pointer
|
||||
* loop detections in pass 3, the bitmap will *always* be sparse, so
|
||||
* e2fsck can request an encoding which is optimized for that.
|
||||
*/
|
||||
|
||||
static void warn_bitmap(ext2fs_generic_bitmap_64 bitmap,
|
||||
int code, __u64 arg)
|
||||
{
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (bitmap->description)
|
||||
com_err(0, bitmap->base_error_code+code,
|
||||
"#%llu for %s", (unsigned long long) arg,
|
||||
bitmap->description);
|
||||
else
|
||||
com_err(0, bitmap->base_error_code + code, "#%llu",
|
||||
(unsigned long long) arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
#define INC_STAT(map, name) map->stats.name
|
||||
#else
|
||||
#define INC_STAT(map, name) ;;
|
||||
#endif
|
||||
|
||||
|
||||
errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
|
||||
int type, __u64 start, __u64 end,
|
||||
__u64 real_end,
|
||||
const char *descr,
|
||||
ext2fs_generic_bitmap *ret)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap;
|
||||
struct ext2_bitmap_ops *ops;
|
||||
ext2_ino_t num_dirs;
|
||||
errcode_t retval;
|
||||
|
||||
if (!type)
|
||||
type = EXT2FS_BMAP64_BITARRAY;
|
||||
|
||||
switch (type) {
|
||||
case EXT2FS_BMAP64_BITARRAY:
|
||||
ops = &ext2fs_blkmap64_bitarray;
|
||||
break;
|
||||
case EXT2FS_BMAP64_RBTREE:
|
||||
ops = &ext2fs_blkmap64_rbtree;
|
||||
break;
|
||||
case EXT2FS_BMAP64_AUTODIR:
|
||||
retval = ext2fs_get_num_dirs(fs, &num_dirs);
|
||||
if (retval || num_dirs > (fs->super->s_inodes_count / 320))
|
||||
ops = &ext2fs_blkmap64_bitarray;
|
||||
else
|
||||
ops = &ext2fs_blkmap64_rbtree;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
|
||||
&bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
if (gettimeofday(&bitmap->stats.created,
|
||||
(struct timezone *) NULL) == -1) {
|
||||
perror("gettimeofday");
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return 1;
|
||||
}
|
||||
bitmap->stats.type = type;
|
||||
#endif
|
||||
|
||||
/* XXX factor out, repeated in copy_bmap */
|
||||
bitmap->magic = magic;
|
||||
bitmap->fs = fs;
|
||||
bitmap->start = start;
|
||||
bitmap->end = end;
|
||||
bitmap->real_end = real_end;
|
||||
bitmap->bitmap_ops = ops;
|
||||
bitmap->cluster_bits = 0;
|
||||
switch (magic) {
|
||||
case EXT2_ET_MAGIC_INODE_BITMAP64:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
|
||||
break;
|
||||
case EXT2_ET_MAGIC_BLOCK_BITMAP64:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
|
||||
bitmap->cluster_bits = fs->cluster_ratio_bits;
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
|
||||
retval = bitmap->bitmap_ops->new_bmap(fs, bitmap);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bitmap->description);
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*ret = (ext2fs_generic_bitmap) bitmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2_bmap_statistics *stats = &bitmap->stats;
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
float mark_seq_perc = 0.0, test_seq_perc = 0.0;
|
||||
float mark_back_perc = 0.0, test_back_perc = 0.0;
|
||||
struct timeval now;
|
||||
double inuse;
|
||||
|
||||
if (stats->test_count) {
|
||||
test_seq_perc = ((float)stats->test_seq /
|
||||
stats->test_count) * 100;
|
||||
test_back_perc = ((float)stats->test_back /
|
||||
stats->test_count) * 100;
|
||||
}
|
||||
|
||||
if (stats->mark_count) {
|
||||
mark_seq_perc = ((float)stats->mark_seq /
|
||||
stats->mark_count) * 100;
|
||||
mark_back_perc = ((float)stats->mark_back /
|
||||
stats->mark_count) * 100;
|
||||
}
|
||||
|
||||
if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
|
||||
perror("gettimeofday");
|
||||
return;
|
||||
}
|
||||
|
||||
inuse = (double) now.tv_sec + \
|
||||
(((double) now.tv_usec) * 0.000001);
|
||||
inuse -= (double) stats->created.tv_sec + \
|
||||
(((double) stats->created.tv_usec) * 0.000001);
|
||||
#endif /* ENABLE_BMAP_STATS_OPS */
|
||||
|
||||
fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
|
||||
stats->type);
|
||||
fprintf(stderr, "=================================================\n");
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
fprintf(stderr, "%16llu bits long\n",
|
||||
bitmap->real_end - bitmap->start);
|
||||
fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
|
||||
stats->copy_count, stats->resize_count);
|
||||
fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n",
|
||||
stats->mark_count, stats->unmark_count);
|
||||
fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n",
|
||||
stats->test_count, stats->mark_ext_count);
|
||||
fprintf(stderr, "%16lu unmark_bmap_extent\n"
|
||||
"%16lu test_clear_bmap_extent\n",
|
||||
stats->unmark_ext_count, stats->test_ext_count);
|
||||
fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n",
|
||||
stats->set_range_count, stats->get_range_count);
|
||||
fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n",
|
||||
stats->clear_count, stats->test_seq, test_seq_perc);
|
||||
fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n"
|
||||
"%16llu bits tested backwards (%.2f%%)\n",
|
||||
stats->mark_seq, mark_seq_perc,
|
||||
stats->test_back, test_back_perc);
|
||||
fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
|
||||
"%16.2f seconds in use\n",
|
||||
stats->mark_back, mark_back_perc, inuse);
|
||||
#endif /* ENABLE_BMAP_STATS_OPS */
|
||||
}
|
||||
#endif
|
||||
|
||||
void ext2fs_free_generic_bmap(ext2fs_generic_bitmap gen_bmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
ext2fs_free_generic_bitmap(gen_bmap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
if (getenv("E2FSPROGS_BITMAP_STATS")) {
|
||||
ext2fs_print_bmap_statistics(bmap);
|
||||
bmap->bitmap_ops->print_stats(bmap);
|
||||
}
|
||||
#endif
|
||||
|
||||
bmap->bitmap_ops->free_bmap(bmap);
|
||||
|
||||
if (bmap->description) {
|
||||
ext2fs_free_mem(&bmap->description);
|
||||
bmap->description = 0;
|
||||
}
|
||||
bmap->magic = 0;
|
||||
ext2fs_free_mem(&bmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
|
||||
ext2fs_generic_bitmap *dest)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src;
|
||||
char *descr, *new_descr;
|
||||
ext2fs_generic_bitmap_64 new_bmap;
|
||||
errcode_t retval;
|
||||
|
||||
if (!src)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(src))
|
||||
return ext2fs_copy_generic_bitmap(gen_src, dest);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(src))
|
||||
return EINVAL;
|
||||
|
||||
/* Allocate a new bitmap struct */
|
||||
retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
|
||||
&new_bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
src->stats.copy_count++;
|
||||
#endif
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
if (gettimeofday(&new_bmap->stats.created,
|
||||
(struct timezone *) NULL) == -1) {
|
||||
perror("gettimeofday");
|
||||
ext2fs_free_mem(&new_bmap);
|
||||
return 1;
|
||||
}
|
||||
new_bmap->stats.type = src->stats.type;
|
||||
#endif
|
||||
|
||||
/* Copy all the high-level parts over */
|
||||
new_bmap->magic = src->magic;
|
||||
new_bmap->fs = src->fs;
|
||||
new_bmap->start = src->start;
|
||||
new_bmap->end = src->end;
|
||||
new_bmap->real_end = src->real_end;
|
||||
new_bmap->bitmap_ops = src->bitmap_ops;
|
||||
new_bmap->base_error_code = src->base_error_code;
|
||||
new_bmap->cluster_bits = src->cluster_bits;
|
||||
|
||||
descr = src->description;
|
||||
if (descr) {
|
||||
retval = ext2fs_get_mem(strlen(descr)+10, &new_descr);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&new_bmap);
|
||||
return retval;
|
||||
}
|
||||
strcpy(new_descr, "copy of ");
|
||||
strcat(new_descr, descr);
|
||||
new_bmap->description = new_descr;
|
||||
}
|
||||
|
||||
retval = src->bitmap_ops->copy_bmap(src, new_bmap);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&new_bmap->description);
|
||||
ext2fs_free_mem(&new_bmap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*dest = (ext2fs_generic_bitmap) new_bmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
|
||||
__u64 new_end,
|
||||
__u64 new_real_end)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap))
|
||||
return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end,
|
||||
new_real_end, gen_bmap);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, resize_count);
|
||||
|
||||
return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap,
|
||||
errcode_t neq,
|
||||
__u64 end, __u64 *oend)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
ext2_ino_t tmp_oend;
|
||||
int retval;
|
||||
|
||||
retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap,
|
||||
bitmap->magic,
|
||||
neq, end, &tmp_oend);
|
||||
if (oend)
|
||||
*oend = tmp_oend;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
if (end > bitmap->real_end)
|
||||
return neq;
|
||||
if (oend)
|
||||
*oend = bitmap->end;
|
||||
bitmap->end = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap))
|
||||
return ext2fs_get_generic_bitmap_start(gen_bitmap);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
return bitmap->start;
|
||||
}
|
||||
|
||||
__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap))
|
||||
return ext2fs_get_generic_bitmap_end(gen_bitmap);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
return bitmap->end;
|
||||
}
|
||||
|
||||
void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap))
|
||||
ext2fs_clear_generic_bitmap(gen_bitmap);
|
||||
else
|
||||
bitmap->bitmap_ops->clear_bmap(bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u64 arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (arg & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap,
|
||||
EXT2FS_MARK_ERROR, 0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_mark_generic_bitmap(gen_bitmap, arg);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return 0;
|
||||
|
||||
arg >>= bitmap->cluster_bits;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
if (arg == bitmap->stats.last_marked + 1)
|
||||
bitmap->stats.mark_seq++;
|
||||
if (arg < bitmap->stats.last_marked)
|
||||
bitmap->stats.mark_back++;
|
||||
bitmap->stats.last_marked = arg;
|
||||
bitmap->stats.mark_count++;
|
||||
#endif
|
||||
|
||||
if ((arg < bitmap->start) || (arg > bitmap->end)) {
|
||||
warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
|
||||
}
|
||||
|
||||
int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u64 arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (arg & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR,
|
||||
0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_unmark_generic_bitmap(gen_bitmap, arg);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return 0;
|
||||
|
||||
arg >>= bitmap->cluster_bits;
|
||||
|
||||
INC_STAT(bitmap, unmark_count);
|
||||
|
||||
if ((arg < bitmap->start) || (arg > bitmap->end)) {
|
||||
warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
|
||||
}
|
||||
|
||||
int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u64 arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (arg & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR,
|
||||
0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_generic_bitmap(gen_bitmap, arg);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return 0;
|
||||
|
||||
arg >>= bitmap->cluster_bits;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bitmap->stats.test_count++;
|
||||
if (arg == bitmap->stats.last_tested + 1)
|
||||
bitmap->stats.test_seq++;
|
||||
if (arg < bitmap->stats.last_tested)
|
||||
bitmap->stats.test_back++;
|
||||
bitmap->stats.last_tested = arg;
|
||||
#endif
|
||||
|
||||
if ((arg < bitmap->start) || (arg > bitmap->end)) {
|
||||
warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap->bitmap_ops->test_bmap(bitmap, arg);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
__u64 start, unsigned int num,
|
||||
void *in)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((start+num-1) & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR,
|
||||
0xffffffff);
|
||||
return EINVAL;
|
||||
}
|
||||
return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic,
|
||||
start, num, in);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, set_range_count);
|
||||
|
||||
return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
__u64 start, unsigned int num,
|
||||
void *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((start+num-1) & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return EINVAL;
|
||||
}
|
||||
return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic,
|
||||
start, num, out);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, get_range_count);
|
||||
|
||||
return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
|
||||
ext2fs_generic_bitmap gen_bm1,
|
||||
ext2fs_generic_bitmap gen_bm2)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1;
|
||||
ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2;
|
||||
blk64_t i;
|
||||
|
||||
if (!bm1 || !bm2)
|
||||
return EINVAL;
|
||||
if (bm1->magic != bm2->magic)
|
||||
return EINVAL;
|
||||
|
||||
/* Now we know both bitmaps have the same magic */
|
||||
if (EXT2FS_IS_32_BITMAP(bm1))
|
||||
return ext2fs_compare_generic_bitmap(bm1->magic, neq,
|
||||
gen_bm1, gen_bm2);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bm1))
|
||||
return EINVAL;
|
||||
|
||||
if ((bm1->start != bm2->start) ||
|
||||
(bm1->end != bm2->end))
|
||||
return neq;
|
||||
|
||||
for (i = bm1->start; i < bm1->end; i++) {
|
||||
int ret1, ret2;
|
||||
ret1 = !!ext2fs_test_generic_bmap(gen_bm1, i);
|
||||
ret2 = !!ext2fs_test_generic_bmap(gen_bm2, i);
|
||||
if (ret1 != ret2) {
|
||||
return neq;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 start, num;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
ext2fs_set_generic_bitmap_padding(gen_bmap);
|
||||
return;
|
||||
}
|
||||
|
||||
start = bmap->end + 1;
|
||||
num = bmap->real_end - bmap->end;
|
||||
bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
|
||||
/* XXX ought to warn on error */
|
||||
}
|
||||
|
||||
int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
|
||||
blk64_t block, unsigned int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 end = block + num;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (num == 1)
|
||||
return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
|
||||
bmap, block);
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((block & ~0xffffffffULL) ||
|
||||
((block+num-1) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return EINVAL;
|
||||
}
|
||||
return ext2fs_test_block_bitmap_range(
|
||||
(ext2fs_generic_bitmap) bmap, block, num);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, test_ext_count);
|
||||
|
||||
/* convert to clusters if necessary */
|
||||
block >>= bmap->cluster_bits;
|
||||
end += (1ULL << bmap->cluster_bits) - 1;
|
||||
end >>= bmap->cluster_bits;
|
||||
num = end - block;
|
||||
|
||||
if ((block < bmap->start) || (block > bmap->end) ||
|
||||
(block+num-1 > bmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
|
||||
bmap->description);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
|
||||
}
|
||||
|
||||
void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
|
||||
blk64_t block, unsigned int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 end = block + num;
|
||||
|
||||
if (!bmap)
|
||||
return;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((block & ~0xffffffffULL) ||
|
||||
((block+num-1) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return;
|
||||
}
|
||||
ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
|
||||
block, num);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return;
|
||||
|
||||
INC_STAT(bmap, mark_ext_count);
|
||||
|
||||
/* convert to clusters if necessary */
|
||||
block >>= bmap->cluster_bits;
|
||||
end += (1ULL << bmap->cluster_bits) - 1;
|
||||
end >>= bmap->cluster_bits;
|
||||
num = end - block;
|
||||
|
||||
if ((block < bmap->start) || (block > bmap->end) ||
|
||||
(block+num-1 > bmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
|
||||
bmap->description);
|
||||
return;
|
||||
}
|
||||
|
||||
bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
|
||||
}
|
||||
|
||||
void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
|
||||
blk64_t block, unsigned int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 end = block + num;
|
||||
|
||||
if (!bmap)
|
||||
return;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((block & ~0xffffffffULL) ||
|
||||
((block+num-1) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return;
|
||||
}
|
||||
ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
|
||||
block, num);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return;
|
||||
|
||||
INC_STAT(bmap, unmark_ext_count);
|
||||
|
||||
/* convert to clusters if necessary */
|
||||
block >>= bmap->cluster_bits;
|
||||
end += (1ULL << bmap->cluster_bits) - 1;
|
||||
end >>= bmap->cluster_bits;
|
||||
num = end - block;
|
||||
|
||||
if ((block < bmap->start) || (block > bmap->end) ||
|
||||
(block+num-1 > bmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
|
||||
bmap->description);
|
||||
return;
|
||||
}
|
||||
|
||||
bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
|
||||
}
|
||||
|
||||
void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (bitmap && bitmap->description)
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"called %s with 64-bit bitmap for %s", func,
|
||||
bitmap->description);
|
||||
else
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"called %s with 64-bit bitmap", func);
|
||||
#endif
|
||||
}
|
||||
|
||||
errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
|
||||
ext2fs_block_bitmap *bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap, cmap;
|
||||
ext2fs_block_bitmap gen_bmap = *bitmap, gen_cmap;
|
||||
errcode_t retval;
|
||||
blk64_t i, next, b_end, c_end;
|
||||
|
||||
bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap))
|
||||
return 0; /* Nothing to do */
|
||||
|
||||
retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
|
||||
&gen_cmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
cmap = (ext2fs_generic_bitmap_64) gen_cmap;
|
||||
i = bmap->start;
|
||||
b_end = bmap->end;
|
||||
bmap->end = bmap->real_end;
|
||||
c_end = cmap->end;
|
||||
cmap->end = cmap->real_end;
|
||||
while (i < bmap->real_end) {
|
||||
retval = ext2fs_find_first_set_block_bitmap2(gen_bmap,
|
||||
i, bmap->real_end, &next);
|
||||
if (retval)
|
||||
break;
|
||||
ext2fs_mark_block_bitmap2(gen_cmap, next);
|
||||
i = EXT2FS_C2B(fs, EXT2FS_B2C(fs, next) + 1);
|
||||
}
|
||||
bmap->end = b_end;
|
||||
cmap->end = c_end;
|
||||
ext2fs_free_block_bitmap(gen_bmap);
|
||||
*bitmap = (ext2fs_block_bitmap) cmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
|
||||
__u64 cstart, cend, cout;
|
||||
errcode_t retval;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
blk_t blk = 0;
|
||||
|
||||
if (((start) & ~0xffffffffULL) ||
|
||||
((end) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start,
|
||||
end, &blk);
|
||||
if (retval == 0)
|
||||
*out = blk;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
cstart = start >> bmap64->cluster_bits;
|
||||
cend = end >> bmap64->cluster_bits;
|
||||
|
||||
if (cstart < bmap64->start || cend > bmap64->end || start > end) {
|
||||
warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (bmap64->bitmap_ops->find_first_zero) {
|
||||
retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart,
|
||||
cend, &cout);
|
||||
if (retval)
|
||||
return retval;
|
||||
found:
|
||||
cout <<= bmap64->cluster_bits;
|
||||
*out = (cout >= start) ? cout : start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cout = cstart; cout <= cend; cout++)
|
||||
if (!bmap64->bitmap_ops->test_bmap(bmap64, cout))
|
||||
goto found;
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
|
||||
__u64 cstart, cend, cout;
|
||||
errcode_t retval;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
blk_t blk = 0;
|
||||
|
||||
if (((start) & ~0xffffffffULL) ||
|
||||
((end) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retval = ext2fs_find_first_set_generic_bitmap(bitmap, start,
|
||||
end, &blk);
|
||||
if (retval == 0)
|
||||
*out = blk;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
cstart = start >> bmap64->cluster_bits;
|
||||
cend = end >> bmap64->cluster_bits;
|
||||
|
||||
if (cstart < bmap64->start || cend > bmap64->end || start > end) {
|
||||
warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (bmap64->bitmap_ops->find_first_set) {
|
||||
retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart,
|
||||
cend, &cout);
|
||||
if (retval)
|
||||
return retval;
|
||||
found:
|
||||
cout <<= bmap64->cluster_bits;
|
||||
*out = (cout >= start) ? cout : start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cout = cstart; cout <= cend; cout++)
|
||||
if (bmap64->bitmap_ops->test_bmap(bmap64, cout))
|
||||
goto found;
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start,
|
||||
blk64_t end, blk64_t *out)
|
||||
{
|
||||
blk64_t next;
|
||||
blk64_t tot_set = 0;
|
||||
errcode_t retval = 0;
|
||||
|
||||
while (start < end) {
|
||||
retval = ext2fs_find_first_set_block_bitmap2(fs->block_map,
|
||||
start, end, &next);
|
||||
if (retval) {
|
||||
if (retval == ENOENT)
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
start = next;
|
||||
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
|
||||
start, end, &next);
|
||||
if (retval == 0) {
|
||||
tot_set += next - start;
|
||||
start = next + 1;
|
||||
} else if (retval == ENOENT) {
|
||||
retval = 0;
|
||||
tot_set += end - start + 1;
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (!retval)
|
||||
*out = EXT2FS_NUM_B2C(fs, tot_set);
|
||||
return retval;
|
||||
}
|
||||
117
jni/e2fsprogs/lib/ext2fs/gen_crc32ctable.c
Executable file
117
jni/e2fsprogs/lib/ext2fs/gen_crc32ctable.c
Executable file
@@ -0,0 +1,117 @@
|
||||
#include <stdio.h>
|
||||
#include "crc32c_defs.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#define ENTRIES_PER_LINE 4
|
||||
|
||||
#if CRC_LE_BITS > 8
|
||||
# define LE_TABLE_ROWS (CRC_LE_BITS/8)
|
||||
# define LE_TABLE_SIZE 256
|
||||
#else
|
||||
# define LE_TABLE_ROWS 1
|
||||
# define LE_TABLE_SIZE (1 << CRC_LE_BITS)
|
||||
#endif
|
||||
|
||||
#if CRC_BE_BITS > 8
|
||||
# define BE_TABLE_ROWS (CRC_BE_BITS/8)
|
||||
# define BE_TABLE_SIZE 256
|
||||
#else
|
||||
# define BE_TABLE_ROWS 1
|
||||
# define BE_TABLE_SIZE (1 << CRC_BE_BITS)
|
||||
#endif
|
||||
|
||||
static uint32_t crc32table_be[BE_TABLE_ROWS][256];
|
||||
static uint32_t crc32ctable_le[LE_TABLE_ROWS][256];
|
||||
|
||||
/**
|
||||
* crc32init_le() - allocate and initialize LE table data
|
||||
*
|
||||
* crc is the crc of the byte i; other entries are filled in based on the
|
||||
* fact that crctable[i^j] = crctable[i] ^ crctable[j].
|
||||
*
|
||||
*/
|
||||
static void crc32cinit_le(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
uint32_t crc = 1;
|
||||
|
||||
crc32ctable_le[0][0] = 0;
|
||||
|
||||
for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
|
||||
for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
|
||||
crc32ctable_le[0][i + j] = crc ^ crc32ctable_le[0][j];
|
||||
}
|
||||
for (i = 0; i < LE_TABLE_SIZE; i++) {
|
||||
crc = crc32ctable_le[0][i];
|
||||
for (j = 1; j < LE_TABLE_ROWS; j++) {
|
||||
crc = crc32ctable_le[0][crc & 0xff] ^ (crc >> 8);
|
||||
crc32ctable_le[j][i] = crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32init_be() - allocate and initialize BE table data
|
||||
*/
|
||||
static void crc32init_be(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
uint32_t crc = 0x80000000;
|
||||
|
||||
crc32table_be[0][0] = 0;
|
||||
|
||||
for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
|
||||
crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
|
||||
for (j = 0; j < i; j++)
|
||||
crc32table_be[0][i + j] = crc ^ crc32table_be[0][j];
|
||||
}
|
||||
for (i = 0; i < BE_TABLE_SIZE; i++) {
|
||||
crc = crc32table_be[0][i];
|
||||
for (j = 1; j < BE_TABLE_ROWS; j++) {
|
||||
crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
|
||||
crc32table_be[j][i] = crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void output_table(uint32_t (*table)[256], int rows, int len, char *trans)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0 ; j < rows; j++) {
|
||||
printf("{");
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
if (i % ENTRIES_PER_LINE == 0)
|
||||
printf("\n");
|
||||
printf("%s(0x%8.8xL), ", trans, table[j][i]);
|
||||
}
|
||||
printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("/* this file is generated - do not edit */\n\n");
|
||||
|
||||
if (CRC_BE_BITS > 1) {
|
||||
crc32init_be();
|
||||
printf("static const uint32_t "
|
||||
"crc32table_be[%d][%d] = {",
|
||||
BE_TABLE_ROWS, BE_TABLE_SIZE);
|
||||
output_table(crc32table_be, LE_TABLE_ROWS,
|
||||
BE_TABLE_SIZE, "tobe");
|
||||
printf("};\n");
|
||||
}
|
||||
if (CRC_LE_BITS > 1) {
|
||||
crc32cinit_le();
|
||||
printf("static const uint32_t "
|
||||
"crc32ctable_le[%d][%d] = {",
|
||||
LE_TABLE_ROWS, LE_TABLE_SIZE);
|
||||
output_table(crc32ctable_le, LE_TABLE_ROWS,
|
||||
LE_TABLE_SIZE, "tole");
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
50
jni/e2fsprogs/lib/ext2fs/get_num_dirs.c
Executable file
50
jni/e2fsprogs/lib/ext2fs/get_num_dirs.c
Executable file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* get_num_dirs.c -- calculate number of directories
|
||||
*
|
||||
* Copyright 1997 by Theodore Ts'o
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
/*
|
||||
* 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 (ext2fs_bg_used_dirs_count(fs, i) > max_dirs)
|
||||
num_dirs += max_dirs / 8;
|
||||
else
|
||||
num_dirs += ext2fs_bg_used_dirs_count(fs, i);
|
||||
}
|
||||
if (num_dirs > fs->super->s_inodes_count)
|
||||
num_dirs = fs->super->s_inodes_count;
|
||||
|
||||
*ret_num_dirs = num_dirs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
171
jni/e2fsprogs/lib/ext2fs/get_pathname.c
Executable file
171
jni/e2fsprogs/lib/ext2fs/get_pathname.c
Executable file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* get_pathname.c --- do directory/inode -> name translation
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %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 the directory <dir>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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;
|
||||
int name_len = ext2fs_dirent_name_len(dirent);
|
||||
|
||||
gp = (struct get_pathname_struct *) priv_data;
|
||||
|
||||
if ((name_len == 2) && !strncmp(dirent->name, "..", 2))
|
||||
gp->parent = dirent->inode;
|
||||
if (dirent->inode == gp->search_ino) {
|
||||
retval = ext2fs_get_mem(name_len + 1, &gp->name);
|
||||
if (retval) {
|
||||
gp->errcode = retval;
|
||||
return DIRENT_ABORT;
|
||||
}
|
||||
strncpy(gp->name, dirent->name, name_len);
|
||||
gp->name[name_len] = '\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 = 0, *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 == EXT2_ET_NO_DIRECTORY) {
|
||||
char tmp[32];
|
||||
|
||||
if (ino)
|
||||
snprintf(tmp, sizeof(tmp), "<%u>/<%u>", dir, ino);
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), "<%u>", dir);
|
||||
retval = ext2fs_get_mem(strlen(tmp)+1, name);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
strcpy(*name, tmp);
|
||||
return 0;
|
||||
} else 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;
|
||||
retval = 0;
|
||||
|
||||
cleanup:
|
||||
ext2fs_free_mem(&parent_name);
|
||||
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;
|
||||
|
||||
}
|
||||
151
jni/e2fsprogs/lib/ext2fs/getsectsize.c
Executable file
151
jni/e2fsprogs/lib/ext2fs/getsectsize.c
Executable file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#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_DISK_H
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(_IO)
|
||||
#if !defined(BLKSSZGET)
|
||||
#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
|
||||
#endif
|
||||
#if !defined(BLKPBSZGET)
|
||||
#define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* Returns the logical sector size of a device
|
||||
*/
|
||||
errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
*sectsize = 512; // just guessing
|
||||
return 0;
|
||||
#else // not _WIN32
|
||||
|
||||
int fd;
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
|
||||
#ifdef BLKSSZGET
|
||||
if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
if (ioctl(fd, DIOCGSECTORSIZE, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
*sectsize = 0;
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
#endif // ifdef _WIN32
|
||||
}
|
||||
|
||||
/*
|
||||
* Return desired alignment for direct I/O
|
||||
*/
|
||||
int ext2fs_get_dio_alignment(int fd)
|
||||
{
|
||||
int align = 0;
|
||||
|
||||
#ifdef BLKSSZGET
|
||||
if (ioctl(fd, BLKSSZGET, &align) < 0)
|
||||
align = 0;
|
||||
#endif
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
if (align <= 0 &&
|
||||
ioctl(fd, DIOCGSECTORSIZE, &align) < 0)
|
||||
align = 0;
|
||||
#endif
|
||||
|
||||
#ifdef _SC_PAGESIZE
|
||||
if (align <= 0)
|
||||
align = sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
#ifdef HAVE_GETPAGESIZE
|
||||
if (align <= 0)
|
||||
align = getpagesize();
|
||||
#endif
|
||||
if (align <= 0)
|
||||
align = 4096;
|
||||
|
||||
return align;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the physical sector size of a device
|
||||
*/
|
||||
errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
return ext2fs_get_device_sectsize(file, sectsize);
|
||||
|
||||
#else // not _WIN32
|
||||
|
||||
int fd;
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
|
||||
#ifdef BLKPBSZGET
|
||||
if (ioctl(fd, BLKPBSZGET, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
/* This isn't really the physical sector size, but FreeBSD
|
||||
* doesn't seem to have this concept. */
|
||||
if (ioctl(fd, DIOCGSECTORSIZE, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
*sectsize = 0;
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
#endif // ifdef _WIN32
|
||||
}
|
||||
315
jni/e2fsprogs/lib/ext2fs/getsize.c
Executable file
315
jni/e2fsprogs/lib/ext2fs/getsize.c
Executable file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#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
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#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_size2(const char *file, int blocksize,
|
||||
blk64_t *retblocks)
|
||||
{
|
||||
int fd;
|
||||
HANDLE h;
|
||||
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 */
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
h = (HANDLE)_get_osfhandle(fd);
|
||||
if (DeviceIoControl(h, IOCTL_DISK_GET_PARTITION_INFO,
|
||||
&pi, sizeof(PARTITION_INFORMATION),
|
||||
&pi, sizeof(PARTITION_INFORMATION),
|
||||
&retbytes, NULL)) {
|
||||
|
||||
*retblocks = pi.PartitionLength.QuadPart / blocksize;
|
||||
|
||||
} else if (DeviceIoControl(h, 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(h, &filesize)) {
|
||||
*retblocks = filesize.QuadPart / blocksize;
|
||||
}
|
||||
#else
|
||||
} else {
|
||||
filesize = GetFileSize(h, NULL);
|
||||
if (INVALID_FILE_SIZE != filesize) {
|
||||
*retblocks = filesize / blocksize;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_GET_FILE_SIZE_EX */
|
||||
|
||||
close(fd);
|
||||
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_size2(const char *file, int blocksize,
|
||||
blk64_t *retblocks)
|
||||
{
|
||||
int fd, rc = 0;
|
||||
unsigned long long size64;
|
||||
ext2_loff_t high, low;
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
|
||||
#if defined DKIOCGETBLOCKCOUNT && defined DKIOCGETBLOCKSIZE /* For Apple Darwin */
|
||||
unsigned int size;
|
||||
|
||||
if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0 &&
|
||||
ioctl(fd, DKIOCGETBLOCKSIZE, &size) >= 0) {
|
||||
*retblocks = size64 * size / blocksize;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BLKGETSIZE64
|
||||
{
|
||||
int valid_blkgetsize64 = 1;
|
||||
#ifdef __linux__
|
||||
struct utsname ut;
|
||||
|
||||
if ((uname(&ut) == 0) &&
|
||||
((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) {
|
||||
*retblocks = size64 / blocksize;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif /* BLKGETSIZE64 */
|
||||
|
||||
#ifdef BLKGETSIZE
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
|
||||
*retblocks = size / (blocksize / 512);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FDGETPRM
|
||||
{
|
||||
struct floppy_struct this_floppy;
|
||||
|
||||
if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
|
||||
*retblocks = this_floppy.size / (blocksize / 512);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_DISKLABEL_H
|
||||
{
|
||||
int part;
|
||||
struct disklabel lab;
|
||||
struct partition *pp;
|
||||
char ch;
|
||||
|
||||
#if defined(DIOCGMEDIASIZE)
|
||||
{
|
||||
off_t ms;
|
||||
u_int bs;
|
||||
if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
|
||||
*retblocks = ms / blocksize;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#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) {
|
||||
*retblocks = pp->p_size / (blocksize / 512);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif /* defined(DIOCG*) */
|
||||
}
|
||||
#endif /* HAVE_SYS_DISKLABEL_H */
|
||||
|
||||
{
|
||||
ext2fs_struct_stat st;
|
||||
|
||||
if (ext2fs_fstat(fd, &st) == 0)
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
*retblocks = st.st_size / blocksize;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
size64 = low + 1;
|
||||
*retblocks = size64 / blocksize;
|
||||
out:
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
errcode_t ext2fs_get_device_size(const char *file, int blocksize,
|
||||
blk_t *retblocks)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t blocks;
|
||||
|
||||
retval = ext2fs_get_device_size2(file, blocksize, &blocks);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (blocks >= (1ULL << 32))
|
||||
return EFBIG;
|
||||
*retblocks = (blk_t) blocks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blk64_t blocks;
|
||||
int retval;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s device\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
retval = ext2fs_get_device_size2(argv[1], 1024, &blocks);
|
||||
if (retval) {
|
||||
com_err(argv[0], retval,
|
||||
"while calling ext2fs_get_device_size");
|
||||
exit(1);
|
||||
}
|
||||
printf("Device %s has %llu 1k blocks.\n", argv[1],
|
||||
(unsigned long long) locks);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
109
jni/e2fsprogs/lib/ext2fs/hashmap.c
Executable file
109
jni/e2fsprogs/lib/ext2fs/hashmap.c
Executable file
@@ -0,0 +1,109 @@
|
||||
#include "hashmap.h"
|
||||
#include <string.h>
|
||||
|
||||
struct ext2fs_hashmap {
|
||||
uint32_t size;
|
||||
uint32_t(*hash)(const void *key, size_t len);
|
||||
void(*free)(void*);
|
||||
struct ext2fs_hashmap_entry *first;
|
||||
struct ext2fs_hashmap_entry *last;
|
||||
#if __GNUC_PREREQ (4, 8)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#endif
|
||||
struct ext2fs_hashmap_entry *entries[0];
|
||||
#if __GNUC_PREREQ (4, 8)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
};
|
||||
|
||||
uint32_t ext2fs_djb2_hash(const void *str, size_t size)
|
||||
{
|
||||
int c;
|
||||
const char *s = str;
|
||||
uint32_t hash = 5381;
|
||||
|
||||
while (size-- > 0) {
|
||||
c = *s++;
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
struct ext2fs_hashmap *ext2fs_hashmap_create(
|
||||
uint32_t(*hash_fct)(const void*, size_t),
|
||||
void(*free_fct)(void*), size_t size)
|
||||
{
|
||||
struct ext2fs_hashmap *h = calloc(sizeof(struct ext2fs_hashmap) +
|
||||
sizeof(struct ext2fs_hashmap_entry) * size, 1);
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
h->size = size;
|
||||
h->free = free_fct;
|
||||
h->hash = hash_fct;
|
||||
h->first = h->last = NULL;
|
||||
return h;
|
||||
}
|
||||
|
||||
int ext2fs_hashmap_add(struct ext2fs_hashmap *h,
|
||||
void *data, const void *key, size_t key_len)
|
||||
{
|
||||
uint32_t hash = h->hash(key, key_len) % h->size;
|
||||
struct ext2fs_hashmap_entry *e = malloc(sizeof(*e));
|
||||
|
||||
if (!e)
|
||||
return -1;
|
||||
|
||||
e->data = data;
|
||||
e->key = key;
|
||||
e->key_len = key_len;
|
||||
e->next = h->entries[hash];
|
||||
h->entries[hash] = e;
|
||||
|
||||
e->list_prev = NULL;
|
||||
e->list_next = h->first;
|
||||
if (h->first)
|
||||
h->first->list_prev = e;
|
||||
h->first = e;
|
||||
if (!h->last)
|
||||
h->last = e;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *ext2fs_hashmap_lookup(struct ext2fs_hashmap *h, const void *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct ext2fs_hashmap_entry *iter;
|
||||
uint32_t hash = h->hash(key, key_len) % h->size;
|
||||
|
||||
for (iter = h->entries[hash]; iter; iter = iter->next)
|
||||
if (iter->key_len == key_len && !memcmp(iter->key, key, key_len))
|
||||
return iter->data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ext2fs_hashmap_iter_in_order(struct ext2fs_hashmap *h,
|
||||
struct ext2fs_hashmap_entry **it)
|
||||
{
|
||||
*it = *it ? (*it)->list_next : h->first;
|
||||
return *it ? (*it)->data : NULL;
|
||||
}
|
||||
|
||||
void ext2fs_hashmap_free(struct ext2fs_hashmap *h)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < h->size; ++i) {
|
||||
struct ext2fs_hashmap_entry *it = h->entries[i];
|
||||
while (it) {
|
||||
struct ext2fs_hashmap_entry *tmp = it->next;
|
||||
if (h->free)
|
||||
h->free(it->data);
|
||||
free(it);
|
||||
it = tmp;
|
||||
}
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
90
jni/e2fsprogs/lib/ext2fs/i_block.c
Executable file
90
jni/e2fsprogs/lib/ext2fs/i_block.c
Executable file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* i_block.c --- Manage the i_block field for i_blocks
|
||||
*
|
||||
* Copyright (C) 2008 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 <errno.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t num_blocks)
|
||||
{
|
||||
unsigned long long b = inode->i_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
|
||||
|
||||
if (!ext2fs_has_feature_huge_file(fs->super) ||
|
||||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
|
||||
num_blocks *= fs->blocksize / 512;
|
||||
num_blocks *= EXT2FS_CLUSTER_RATIO(fs);
|
||||
|
||||
b += num_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
|
||||
else if (b > 0xFFFFFFFF)
|
||||
return EOVERFLOW;
|
||||
inode->i_blocks = b & 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t num_blocks)
|
||||
{
|
||||
unsigned long long b = inode->i_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
|
||||
|
||||
if (!ext2fs_has_feature_huge_file(fs->super) ||
|
||||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
|
||||
num_blocks *= fs->blocksize / 512;
|
||||
num_blocks *= EXT2FS_CLUSTER_RATIO(fs);
|
||||
|
||||
if (num_blocks > b)
|
||||
return EOVERFLOW;
|
||||
|
||||
b -= num_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
|
||||
inode->i_blocks = b & 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b)
|
||||
{
|
||||
if (!ext2fs_has_feature_huge_file(fs->super) ||
|
||||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
|
||||
b *= fs->blocksize / 512;
|
||||
b *= EXT2FS_CLUSTER_RATIO(fs);
|
||||
|
||||
inode->i_blocks = b & 0xFFFFFFFF;
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
|
||||
else if (b >> 32)
|
||||
return EOVERFLOW;
|
||||
return 0;
|
||||
}
|
||||
921
jni/e2fsprogs/lib/ext2fs/icount.c
Executable file
921
jni/e2fsprogs/lib/ext2fs/icount.c
Executable file
@@ -0,0 +1,921 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "tdb.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;
|
||||
__u32 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;
|
||||
struct ext2_icount_el *last_lookup;
|
||||
#ifdef CONFIG_TDB
|
||||
char *tdb_fn;
|
||||
TDB_CONTEXT *tdb;
|
||||
#endif
|
||||
__u16 *fullmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* We now use a 32-bit counter field because it doesn't cost us
|
||||
* anything extra for the in-memory data structure, due to alignment
|
||||
* padding. But there's no point changing the interface if most of
|
||||
* the time we only care if the number is bigger than 65,000 or not.
|
||||
* So use the following translation function to return a 16-bit count.
|
||||
*/
|
||||
#define icount_16_xlate(x) (((x) > 65500) ? 65500 : (x))
|
||||
|
||||
void ext2fs_free_icount(ext2_icount_t icount)
|
||||
{
|
||||
if (!icount)
|
||||
return;
|
||||
|
||||
icount->magic = 0;
|
||||
if (icount->list)
|
||||
ext2fs_free_mem(&icount->list);
|
||||
if (icount->single)
|
||||
ext2fs_free_inode_bitmap(icount->single);
|
||||
if (icount->multiple)
|
||||
ext2fs_free_inode_bitmap(icount->multiple);
|
||||
#ifdef CONFIG_TDB
|
||||
if (icount->tdb)
|
||||
tdb_close(icount->tdb);
|
||||
if (icount->tdb_fn) {
|
||||
(void) unlink(icount->tdb_fn);
|
||||
free(icount->tdb_fn);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (icount->fullmap)
|
||||
ext2fs_free_mem(&icount->fullmap);
|
||||
|
||||
ext2fs_free_mem(&icount);
|
||||
}
|
||||
|
||||
static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret)
|
||||
{
|
||||
ext2_icount_t icount;
|
||||
errcode_t retval;
|
||||
|
||||
*ret = 0;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
|
||||
if (retval)
|
||||
return retval;
|
||||
memset(icount, 0, sizeof(struct ext2_icount));
|
||||
icount->magic = EXT2_ET_MAGIC_ICOUNT;
|
||||
icount->num_inodes = fs->super->s_inodes_count;
|
||||
|
||||
if ((flags & EXT2_ICOUNT_OPT_FULLMAP) &&
|
||||
(flags & EXT2_ICOUNT_OPT_INCREMENT)) {
|
||||
unsigned sz = sizeof(*icount->fullmap) * icount->num_inodes;
|
||||
|
||||
retval = ext2fs_get_mem(sz, &icount->fullmap);
|
||||
/* If we can't allocate, fall back */
|
||||
if (!retval) {
|
||||
memset(icount->fullmap, 0, sz);
|
||||
*ret = icount;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ext2fs_allocate_inode_bitmap(fs, "icount", &icount->single);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
|
||||
retval = ext2fs_allocate_inode_bitmap(fs, "icount_inc",
|
||||
&icount->multiple);
|
||||
if (retval)
|
||||
goto errout;
|
||||
} else
|
||||
icount->multiple = 0;
|
||||
|
||||
*ret = icount;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
ext2fs_free_icount(icount);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TDB
|
||||
struct uuid {
|
||||
__u32 time_low;
|
||||
__u16 time_mid;
|
||||
__u16 time_hi_and_version;
|
||||
__u16 clock_seq;
|
||||
__u8 node[6];
|
||||
};
|
||||
|
||||
static void 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);
|
||||
}
|
||||
|
||||
static void uuid_unparse(void *uu, char *out)
|
||||
{
|
||||
struct uuid uuid;
|
||||
|
||||
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]);
|
||||
}
|
||||
#endif
|
||||
|
||||
errcode_t ext2fs_create_icount_tdb(ext2_filsys fs EXT2FS_NO_TDB_UNUSED,
|
||||
char *tdb_dir EXT2FS_NO_TDB_UNUSED,
|
||||
int flags EXT2FS_NO_TDB_UNUSED,
|
||||
ext2_icount_t *ret EXT2FS_NO_TDB_UNUSED)
|
||||
{
|
||||
#ifdef CONFIG_TDB
|
||||
ext2_icount_t icount;
|
||||
errcode_t retval;
|
||||
char *fn, uuid[40];
|
||||
ext2_ino_t num_inodes;
|
||||
mode_t save_umask;
|
||||
int fd;
|
||||
|
||||
retval = alloc_icount(fs, flags, &icount);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn);
|
||||
if (retval)
|
||||
goto errout;
|
||||
uuid_unparse(fs->super->s_uuid, uuid);
|
||||
sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid);
|
||||
save_umask = umask(077);
|
||||
fd = mkstemp(fn);
|
||||
if (fd < 0) {
|
||||
retval = errno;
|
||||
ext2fs_free_mem(&fn);
|
||||
goto errout;
|
||||
}
|
||||
icount->tdb_fn = fn;
|
||||
umask(save_umask);
|
||||
/*
|
||||
* This is an overestimate of the size that we will need; the
|
||||
* ideal value is the number of used inodes with a count
|
||||
* greater than 1. OTOH the times when we really need this is
|
||||
* with the backup programs that use lots of hard links, in
|
||||
* which case the number of inodes in use approaches the ideal
|
||||
* value.
|
||||
*/
|
||||
num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count;
|
||||
|
||||
icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC,
|
||||
O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
close(fd);
|
||||
if (icount->tdb == NULL) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
*ret = icount;
|
||||
return 0;
|
||||
errout:
|
||||
ext2fs_free_icount(icount);
|
||||
return(retval);
|
||||
#else
|
||||
return EXT2_ET_UNIMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
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 = alloc_icount(fs, flags, &icount);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (icount->fullmap)
|
||||
goto successout;
|
||||
|
||||
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));
|
||||
#if 0
|
||||
printf("Icount allocated %u entries, %d bytes.\n",
|
||||
icount->size, bytes);
|
||||
#endif
|
||||
retval = ext2fs_get_array(icount->size, sizeof(struct ext2_icount_el),
|
||||
&icount->list);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memset(icount->list, 0, bytes);
|
||||
|
||||
icount->count = 0;
|
||||
icount->cursor = 0;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
successout:
|
||||
*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->last_lookup && icount->last_lookup->ino == ino)
|
||||
return icount->last_lookup;
|
||||
|
||||
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;
|
||||
#if 0
|
||||
printf("Reallocating icount %u entries...\n", new_size);
|
||||
#endif
|
||||
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;
|
||||
icount->last_lookup = el;
|
||||
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)
|
||||
{
|
||||
int low, high, mid;
|
||||
|
||||
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++];
|
||||
#if 0
|
||||
printf("Non-cursor get_icount_el: %u\n", ino);
|
||||
#endif
|
||||
low = 0;
|
||||
high = (int) icount->count-1;
|
||||
while (low <= high) {
|
||||
mid = ((unsigned)low + (unsigned)high) >> 1;
|
||||
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;
|
||||
}
|
||||
|
||||
static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u32 count)
|
||||
{
|
||||
struct ext2_icount_el *el;
|
||||
#ifdef CONFIG_TDB
|
||||
TDB_DATA key, data;
|
||||
|
||||
if (icount->tdb) {
|
||||
key.dptr = (unsigned char *) &ino;
|
||||
key.dsize = sizeof(ext2_ino_t);
|
||||
data.dptr = (unsigned char *) &count;
|
||||
data.dsize = sizeof(__u32);
|
||||
if (count) {
|
||||
if (tdb_store(icount->tdb, key, data, TDB_REPLACE))
|
||||
return tdb_error(icount->tdb) +
|
||||
EXT2_ET_TDB_SUCCESS;
|
||||
} else {
|
||||
if (tdb_delete(icount->tdb, key))
|
||||
return tdb_error(icount->tdb) +
|
||||
EXT2_ET_TDB_SUCCESS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (icount->fullmap) {
|
||||
icount->fullmap[ino] = icount_16_xlate(count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el = get_icount_el(icount, ino, 1);
|
||||
if (!el)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
|
||||
el->count = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u32 *count)
|
||||
{
|
||||
struct ext2_icount_el *el;
|
||||
#ifdef CONFIG_TDB
|
||||
TDB_DATA key, data;
|
||||
|
||||
if (icount->tdb) {
|
||||
key.dptr = (unsigned char *) &ino;
|
||||
key.dsize = sizeof(ext2_ino_t);
|
||||
|
||||
data = tdb_fetch(icount->tdb, key);
|
||||
if (data.dptr == NULL) {
|
||||
*count = 0;
|
||||
return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS;
|
||||
}
|
||||
|
||||
*count = *((__u32 *) data.dptr);
|
||||
free(data.dptr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (icount->fullmap) {
|
||||
*count = icount->fullmap[ino];
|
||||
return 0;
|
||||
}
|
||||
|
||||
el = get_icount_el(icount, ino, 0);
|
||||
if (!el) {
|
||||
*count = 0;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
*count = el->count;
|
||||
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)
|
||||
{
|
||||
__u32 val;
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (!icount->fullmap) {
|
||||
if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
|
||||
*ret = 1;
|
||||
return 0;
|
||||
}
|
||||
if (icount->multiple &&
|
||||
!ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
get_inode_count(icount, ino, &val);
|
||||
*ret = icount_16_xlate(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u16 *ret)
|
||||
{
|
||||
__u32 curr_value;
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (icount->fullmap) {
|
||||
curr_value = icount_16_xlate(icount->fullmap[ino] + 1);
|
||||
icount->fullmap[ino] = curr_value;
|
||||
} else if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
|
||||
/*
|
||||
* If the existing count is 1, then we know there is
|
||||
* no entry in the list.
|
||||
*/
|
||||
if (set_inode_count(icount, ino, 2))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
curr_value = 2;
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
} 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 we need to fix it.
|
||||
*/
|
||||
if (ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
|
||||
get_inode_count(icount, ino, &curr_value);
|
||||
curr_value++;
|
||||
if (set_inode_count(icount, ino, curr_value))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
} else {
|
||||
/*
|
||||
* The count was zero; mark the single bitmap
|
||||
* and return.
|
||||
*/
|
||||
ext2fs_mark_inode_bitmap2(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.
|
||||
*/
|
||||
get_inode_count(icount, ino, &curr_value);
|
||||
curr_value++;
|
||||
if (set_inode_count(icount, ino, curr_value))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
}
|
||||
if (icount->multiple)
|
||||
ext2fs_mark_inode_bitmap2(icount->multiple, ino);
|
||||
if (ret)
|
||||
*ret = icount_16_xlate(curr_value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u16 *ret)
|
||||
{
|
||||
__u32 curr_value;
|
||||
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (icount->fullmap) {
|
||||
if (!icount->fullmap[ino])
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
curr_value = --icount->fullmap[ino];
|
||||
if (ret)
|
||||
*ret = icount_16_xlate(curr_value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple)
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
else {
|
||||
set_inode_count(icount, ino, 0);
|
||||
}
|
||||
if (ret)
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (icount->multiple &&
|
||||
!ext2fs_test_inode_bitmap2(icount->multiple, ino))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
get_inode_count(icount, ino, &curr_value);
|
||||
if (!curr_value)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
curr_value--;
|
||||
if (set_inode_count(icount, ino, curr_value))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
|
||||
if (curr_value == 1)
|
||||
ext2fs_mark_inode_bitmap2(icount->single, ino);
|
||||
if ((curr_value == 0) && icount->multiple)
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
|
||||
if (ret)
|
||||
*ret = icount_16_xlate(curr_value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u16 count)
|
||||
{
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (icount->fullmap)
|
||||
return set_inode_count(icount, ino, count);
|
||||
|
||||
if (count == 1) {
|
||||
ext2fs_mark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple)
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
return 0;
|
||||
}
|
||||
if (count == 0) {
|
||||
ext2fs_unmark_inode_bitmap2(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_bitmap2(icount->multiple, ino);
|
||||
} else
|
||||
set_inode_count(icount, ino, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (set_inode_count(icount, ino, count))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple)
|
||||
ext2fs_mark_inode_bitmap2(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;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
ext2_filsys test_fs;
|
||||
ext2_icount_t icount;
|
||||
|
||||
#define EXIT 0x00
|
||||
#define FETCH 0x01
|
||||
#define STORE 0x02
|
||||
#define INCREMENT 0x03
|
||||
#define DECREMENT 0x04
|
||||
|
||||
struct test_program {
|
||||
int cmd;
|
||||
ext2_ino_t ino;
|
||||
__u16 arg;
|
||||
__u16 expected;
|
||||
};
|
||||
|
||||
struct test_program prog[] = {
|
||||
{ STORE, 42, 42, 42 },
|
||||
{ STORE, 1, 1, 1 },
|
||||
{ STORE, 2, 2, 2 },
|
||||
{ STORE, 3, 3, 3 },
|
||||
{ STORE, 10, 1, 1 },
|
||||
{ STORE, 42, 0, 0 },
|
||||
{ INCREMENT, 5, 0, 1 },
|
||||
{ INCREMENT, 5, 0, 2 },
|
||||
{ INCREMENT, 5, 0, 3 },
|
||||
{ INCREMENT, 5, 0, 4 },
|
||||
{ DECREMENT, 5, 0, 3 },
|
||||
{ DECREMENT, 5, 0, 2 },
|
||||
{ DECREMENT, 5, 0, 1 },
|
||||
{ DECREMENT, 5, 0, 0 },
|
||||
{ FETCH, 10, 0, 1 },
|
||||
{ FETCH, 1, 0, 1 },
|
||||
{ FETCH, 2, 0, 2 },
|
||||
{ FETCH, 3, 0, 3 },
|
||||
{ INCREMENT, 1, 0, 2 },
|
||||
{ DECREMENT, 2, 0, 1 },
|
||||
{ DECREMENT, 2, 0, 0 },
|
||||
{ FETCH, 12, 0, 0 },
|
||||
{ EXIT, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct test_program extended[] = {
|
||||
{ STORE, 1, 1, 1 },
|
||||
{ STORE, 2, 2, 2 },
|
||||
{ STORE, 3, 3, 3 },
|
||||
{ STORE, 4, 4, 4 },
|
||||
{ STORE, 5, 5, 5 },
|
||||
{ STORE, 6, 1, 1 },
|
||||
{ STORE, 7, 2, 2 },
|
||||
{ STORE, 8, 3, 3 },
|
||||
{ STORE, 9, 4, 4 },
|
||||
{ STORE, 10, 5, 5 },
|
||||
{ STORE, 11, 1, 1 },
|
||||
{ STORE, 12, 2, 2 },
|
||||
{ STORE, 13, 3, 3 },
|
||||
{ STORE, 14, 4, 4 },
|
||||
{ STORE, 15, 5, 5 },
|
||||
{ STORE, 16, 1, 1 },
|
||||
{ STORE, 17, 2, 2 },
|
||||
{ STORE, 18, 3, 3 },
|
||||
{ STORE, 19, 4, 4 },
|
||||
{ STORE, 20, 5, 5 },
|
||||
{ STORE, 21, 1, 1 },
|
||||
{ STORE, 22, 2, 2 },
|
||||
{ STORE, 23, 3, 3 },
|
||||
{ STORE, 24, 4, 4 },
|
||||
{ STORE, 25, 5, 5 },
|
||||
{ STORE, 26, 1, 1 },
|
||||
{ STORE, 27, 2, 2 },
|
||||
{ STORE, 28, 3, 3 },
|
||||
{ STORE, 29, 4, 4 },
|
||||
{ STORE, 30, 5, 5 },
|
||||
{ EXIT, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Setup the variables for doing the inode scan test.
|
||||
*/
|
||||
static void setup(void)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct ext2_super_block param;
|
||||
|
||||
initialize_ext2_error_table();
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
ext2fs_blocks_count_set(¶m, 12000);
|
||||
|
||||
retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m,
|
||||
test_io_manager, &test_fs);
|
||||
if (retval) {
|
||||
com_err("setup", retval,
|
||||
"while initializing filesystem");
|
||||
exit(1);
|
||||
}
|
||||
retval = ext2fs_allocate_tables(test_fs);
|
||||
if (retval) {
|
||||
com_err("setup", retval,
|
||||
"while allocating tables for test filesystem");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int run_test(int flags, int size, char *dir, struct test_program *prog)
|
||||
{
|
||||
errcode_t retval;
|
||||
ext2_icount_t icount;
|
||||
struct test_program *pc;
|
||||
__u16 result;
|
||||
int problem = 0;
|
||||
|
||||
if (dir) {
|
||||
#ifdef CONFIG_TDB
|
||||
retval = ext2fs_create_icount_tdb(test_fs, dir,
|
||||
flags, &icount);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while creating icount using tdb");
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
printf("Skipped\n");
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
retval = ext2fs_create_icount2(test_fs, flags, size, 0,
|
||||
&icount);
|
||||
if (retval) {
|
||||
com_err("run_test", retval, "while creating icount");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for (pc = prog; pc->cmd != EXIT; pc++) {
|
||||
switch (pc->cmd) {
|
||||
case FETCH:
|
||||
printf("icount_fetch(%u) = ", pc->ino);
|
||||
break;
|
||||
case STORE:
|
||||
retval = ext2fs_icount_store(icount, pc->ino, pc->arg);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_store");
|
||||
exit(1);
|
||||
}
|
||||
printf("icount_store(%u, %u) = ", pc->ino, pc->arg);
|
||||
break;
|
||||
case INCREMENT:
|
||||
retval = ext2fs_icount_increment(icount, pc->ino, 0);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_increment");
|
||||
exit(1);
|
||||
}
|
||||
printf("icount_increment(%u) = ", pc->ino);
|
||||
break;
|
||||
case DECREMENT:
|
||||
retval = ext2fs_icount_decrement(icount, pc->ino, 0);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_decrement");
|
||||
exit(1);
|
||||
}
|
||||
printf("icount_decrement(%u) = ", pc->ino);
|
||||
break;
|
||||
}
|
||||
retval = ext2fs_icount_fetch(icount, pc->ino, &result);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_fetch");
|
||||
exit(1);
|
||||
}
|
||||
printf("%u (%s)\n", result, (result == pc->expected) ?
|
||||
"OK" : "NOT OK");
|
||||
if (result != pc->expected)
|
||||
problem++;
|
||||
}
|
||||
printf("icount size is %u\n", ext2fs_get_icount_size(icount));
|
||||
retval = ext2fs_icount_validate(icount, stdout);
|
||||
if (retval) {
|
||||
com_err("run_test", retval, "while calling icount_validate");
|
||||
exit(1);
|
||||
}
|
||||
ext2fs_free_icount(icount);
|
||||
return problem;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int failed = 0;
|
||||
|
||||
setup();
|
||||
printf("Standard icount run:\n");
|
||||
failed += run_test(0, 0, 0, prog);
|
||||
printf("\nMultiple bitmap test:\n");
|
||||
failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog);
|
||||
printf("\nResizing icount:\n");
|
||||
failed += run_test(0, 3, 0, extended);
|
||||
printf("\nStandard icount run with tdb:\n");
|
||||
failed += run_test(0, 0, ".", prog);
|
||||
printf("\nMultiple bitmap test with tdb:\n");
|
||||
failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog);
|
||||
if (failed)
|
||||
printf("FAILED!\n");
|
||||
return failed;
|
||||
}
|
||||
#endif
|
||||
470
jni/e2fsprogs/lib/ext2fs/imager.c
Executable file
470
jni/e2fsprogs/lib/ext2fs/imager.c
Executable file
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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)
|
||||
{
|
||||
dgrp_t group;
|
||||
ssize_t left, c, d;
|
||||
char *buf, *cp;
|
||||
blk64_t blk;
|
||||
ssize_t actual;
|
||||
errcode_t retval;
|
||||
ext2_loff_t r;
|
||||
|
||||
buf = malloc(fs->blocksize * BUF_BLOCKS);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
for (group = 0; group < fs->group_desc_count; group++) {
|
||||
blk = ext2fs_inode_table_loc(fs, group);
|
||||
if (!blk) {
|
||||
retval = EXT2_ET_MISSING_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
left = fs->inode_blocks_per_group;
|
||||
if ((blk < fs->super->s_first_data_block) ||
|
||||
(blk + left - 1 >= ext2fs_blocks_count(fs->super))) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
while (left) {
|
||||
c = BUF_BLOCKS;
|
||||
if (c > left)
|
||||
c = left;
|
||||
retval = io_channel_read_blk64(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;
|
||||
r = ext2fs_llseek(fd, fs->blocksize,
|
||||
SEEK_CUR);
|
||||
if (r < 0) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
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, d * fs->blocksize);
|
||||
if (actual == -1) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (actual != d * fs->blocksize) {
|
||||
retval = EXT2_ET_SHORT_WRITE;
|
||||
goto errout;
|
||||
}
|
||||
blk += d;
|
||||
left -= d;
|
||||
cp += d * fs->blocksize;
|
||||
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)))
|
||||
{
|
||||
dgrp_t group;
|
||||
ssize_t c, left;
|
||||
char *buf;
|
||||
blk64_t blk;
|
||||
ssize_t actual;
|
||||
errcode_t retval;
|
||||
|
||||
buf = malloc(fs->blocksize * BUF_BLOCKS);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
for (group = 0; group < fs->group_desc_count; group++) {
|
||||
blk = ext2fs_inode_table_loc(fs, group);
|
||||
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 != fs->blocksize * c) {
|
||||
retval = EXT2_ET_SHORT_READ;
|
||||
goto errout;
|
||||
}
|
||||
retval = io_channel_write_blk64(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;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
unsigned int groups_per_block;
|
||||
struct ext2_group_desc *gdp;
|
||||
int j;
|
||||
#endif
|
||||
|
||||
if (fs->group_desc == NULL)
|
||||
return EXT2_ET_NO_GDESC;
|
||||
|
||||
buf = malloc(fs->blocksize);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* Write out the superblock
|
||||
*/
|
||||
memset(buf, 0, fs->blocksize);
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
/*
|
||||
* We're writing out superblock so let's convert
|
||||
* it to little endian and then back if needed
|
||||
*/
|
||||
ext2fs_swap_super(fs->super);
|
||||
memcpy(buf, fs->super, SUPERBLOCK_SIZE);
|
||||
ext2fs_swap_super(fs->super);
|
||||
#else
|
||||
memcpy(buf, fs->super, SUPERBLOCK_SIZE);
|
||||
#endif
|
||||
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;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
/*
|
||||
* Convert group descriptors to little endian and back
|
||||
* if needed
|
||||
*/
|
||||
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
|
||||
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
|
||||
if (gdp)
|
||||
ext2fs_swap_group_desc2(fs, gdp);
|
||||
}
|
||||
#endif
|
||||
|
||||
actual = write(fd, cp, (ssize_t)fs->blocksize * fs->desc_blocks);
|
||||
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
|
||||
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
|
||||
if (gdp)
|
||||
ext2fs_swap_group_desc2(fs, gdp);
|
||||
}
|
||||
#endif
|
||||
|
||||
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 = (ssize_t)fs->blocksize * (fs->group_desc_count + 1);
|
||||
buf = malloc(size);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
(ssize_t)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)
|
||||
{
|
||||
ext2fs_generic_bitmap bmap;
|
||||
errcode_t retval;
|
||||
ssize_t actual;
|
||||
size_t c;
|
||||
__u64 itr, cnt, size, total_size;
|
||||
char buf[1024];
|
||||
|
||||
if (flags & IMAGER_FLAG_INODEMAP) {
|
||||
if (!fs->inode_map) {
|
||||
retval = ext2fs_read_inode_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->inode_map;
|
||||
itr = 1;
|
||||
cnt = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
|
||||
fs->group_desc_count;
|
||||
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
|
||||
} else {
|
||||
if (!fs->block_map) {
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->block_map;
|
||||
itr = fs->super->s_first_data_block;
|
||||
cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count);
|
||||
size = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
|
||||
}
|
||||
total_size = size * fs->group_desc_count;
|
||||
|
||||
while (cnt > 0) {
|
||||
size = sizeof(buf);
|
||||
if (size > (cnt >> 3))
|
||||
size = (cnt >> 3);
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
retval = ext2fs_get_generic_bmap_range(bmap, itr,
|
||||
size << 3, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
actual = write(fd, buf, size);
|
||||
if (actual == -1)
|
||||
return errno;
|
||||
if (actual != (int) size)
|
||||
return EXT2_ET_SHORT_READ;
|
||||
|
||||
itr += size << 3;
|
||||
cnt -= size << 3;
|
||||
}
|
||||
|
||||
size = total_size % fs->blocksize;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (size) {
|
||||
size = fs->blocksize - size;
|
||||
while (size) {
|
||||
c = size;
|
||||
if (c > (int) sizeof(buf))
|
||||
c = sizeof(buf);
|
||||
actual = write(fd, buf, c);
|
||||
if (actual < 0)
|
||||
return errno;
|
||||
if ((size_t) actual != c)
|
||||
return EXT2_ET_SHORT_WRITE;
|
||||
size -= c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the block/inode bitmaps.
|
||||
*/
|
||||
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
|
||||
{
|
||||
ext2fs_generic_bitmap bmap;
|
||||
errcode_t retval;
|
||||
__u64 itr, cnt;
|
||||
char buf[1024];
|
||||
unsigned int size;
|
||||
ssize_t actual;
|
||||
|
||||
if (flags & IMAGER_FLAG_INODEMAP) {
|
||||
if (!fs->inode_map) {
|
||||
retval = ext2fs_read_inode_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->inode_map;
|
||||
itr = 1;
|
||||
cnt = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
|
||||
fs->group_desc_count;
|
||||
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
|
||||
} else {
|
||||
if (!fs->block_map) {
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->block_map;
|
||||
itr = fs->super->s_first_data_block;
|
||||
cnt = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count);
|
||||
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
|
||||
}
|
||||
|
||||
while (cnt > 0) {
|
||||
size = sizeof(buf);
|
||||
if (size > (cnt >> 3))
|
||||
size = (cnt >> 3);
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
actual = read(fd, buf, size);
|
||||
if (actual == -1)
|
||||
return errno;
|
||||
if (actual != (int) size)
|
||||
return EXT2_ET_SHORT_READ;
|
||||
|
||||
retval = ext2fs_set_generic_bmap_range(bmap, itr,
|
||||
size << 3, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
itr += size << 3;
|
||||
cnt -= size << 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
67
jni/e2fsprogs/lib/ext2fs/ind_block.c
Executable file
67
jni/e2fsprogs/lib/ext2fs/ind_block.c
Executable file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
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;
|
||||
}
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
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)
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
blk_t *block_nr;
|
||||
int i;
|
||||
int limit = fs->blocksize >> 2;
|
||||
#endif
|
||||
|
||||
if (fs->flags & EXT2_FLAG_IMAGE_FILE)
|
||||
return 0;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
671
jni/e2fsprogs/lib/ext2fs/initialize.c
Executable file
671
jni/e2fsprogs/lib/ext2fs/initialize.c
Executable file
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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 O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#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) */
|
||||
|
||||
/*
|
||||
* 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 unsigned 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 = EXT2_DESC_PER_BLOCK(sb);
|
||||
unsigned long max_blocks = 0xffffffff;
|
||||
unsigned long rsv_groups;
|
||||
unsigned int rsv_gdb;
|
||||
|
||||
/* We set it at 1024x the current filesystem size, or
|
||||
* the upper block count limit (2^32), whichever is lower.
|
||||
*/
|
||||
if (ext2fs_blocks_count(sb) < max_blocks / 1024)
|
||||
max_blocks = ext2fs_blocks_count(sb) * 1024;
|
||||
/*
|
||||
* ext2fs_div64_ceil() is unnecessary because max_blocks is
|
||||
* max _GDT_ blocks, which is limited to 32 bits.
|
||||
*/
|
||||
rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg);
|
||||
rsv_gdb = ext2fs_div_ceil(rsv_groups, 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;
|
||||
unsigned int rem;
|
||||
unsigned int overhead = 0;
|
||||
unsigned int ipg;
|
||||
dgrp_t i;
|
||||
blk64_t free_blocks;
|
||||
blk_t numblocks;
|
||||
int rsv_gdt;
|
||||
int csum_flag;
|
||||
int bigalloc_flag;
|
||||
int io_flags;
|
||||
int has_bg;
|
||||
unsigned reserved_inos;
|
||||
char *buf = 0;
|
||||
char c;
|
||||
double reserved_ratio;
|
||||
char *time_env;
|
||||
|
||||
if (!param || !ext2fs_blocks_count(param))
|
||||
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;
|
||||
fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
fs->flags |= EXT2_FLAG_SWAP_BYTES;
|
||||
#endif
|
||||
|
||||
time_env = getenv("E2FSPROGS_FAKE_TIME");
|
||||
if (time_env)
|
||||
fs->now = strtoul(time_env, NULL, 0);
|
||||
|
||||
io_flags = IO_FLAG_RW;
|
||||
if (flags & EXT2_FLAG_EXCLUSIVE)
|
||||
io_flags |= IO_FLAG_EXCLUSIVE;
|
||||
if (flags & EXT2_FLAG_DIRECT_IO)
|
||||
io_flags |= IO_FLAG_DIRECT_IO;
|
||||
io_flags |= O_BINARY;
|
||||
retval = manager->open(name, io_flags, &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))
|
||||
#define assign_field(field) (super->field = param->field)
|
||||
|
||||
super->s_magic = EXT2_SUPER_MAGIC;
|
||||
super->s_state = EXT2_VALID_FS;
|
||||
|
||||
bigalloc_flag = ext2fs_has_feature_bigalloc(param);
|
||||
|
||||
assign_field(s_log_block_size);
|
||||
|
||||
if (bigalloc_flag) {
|
||||
set_field(s_log_cluster_size, super->s_log_block_size+4);
|
||||
if (super->s_log_block_size > super->s_log_cluster_size) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
} else
|
||||
super->s_log_cluster_size = super->s_log_block_size;
|
||||
|
||||
set_field(s_first_data_block, super->s_log_cluster_size ? 0 : 1);
|
||||
set_field(s_max_mnt_count, 0);
|
||||
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_default_mount_opts, 0);
|
||||
set_field(s_first_meta_bg, 0);
|
||||
set_field(s_raid_stride, 0); /* default stride size: 0 */
|
||||
set_field(s_raid_stripe_width, 0); /* default stripe width: 0 */
|
||||
set_field(s_log_groups_per_flex, 0);
|
||||
set_field(s_flags, 0);
|
||||
assign_field(s_backup_bgs[0]);
|
||||
assign_field(s_backup_bgs[1]);
|
||||
|
||||
assign_field(s_encoding);
|
||||
assign_field(s_encoding_flags);
|
||||
|
||||
if (ext2fs_has_feature_casefold(param))
|
||||
fs->encoding = ext2fs_load_nls_table(param->s_encoding);
|
||||
|
||||
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);
|
||||
if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
|
||||
int extra_isize = sizeof(struct ext2_inode_large) -
|
||||
EXT2_GOOD_OLD_INODE_SIZE;
|
||||
set_field(s_min_extra_isize, extra_isize);
|
||||
set_field(s_want_extra_isize, extra_isize);
|
||||
}
|
||||
} else {
|
||||
super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
|
||||
super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
|
||||
}
|
||||
|
||||
set_field(s_checkinterval, 0);
|
||||
super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL);
|
||||
|
||||
super->s_creator_os = CREATOR_OS;
|
||||
|
||||
fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(super);
|
||||
fs->cluster_ratio_bits = super->s_log_cluster_size -
|
||||
super->s_log_block_size;
|
||||
|
||||
if (bigalloc_flag) {
|
||||
unsigned long long bpg;
|
||||
|
||||
if (param->s_blocks_per_group &&
|
||||
param->s_clusters_per_group &&
|
||||
((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) !=
|
||||
param->s_blocks_per_group)) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
if (param->s_clusters_per_group)
|
||||
assign_field(s_clusters_per_group);
|
||||
else if (param->s_blocks_per_group)
|
||||
super->s_clusters_per_group =
|
||||
param->s_blocks_per_group /
|
||||
EXT2FS_CLUSTER_RATIO(fs);
|
||||
else if (super->s_log_cluster_size + 15 < 32)
|
||||
super->s_clusters_per_group = fs->blocksize * 8;
|
||||
else
|
||||
super->s_clusters_per_group = (fs->blocksize - 1) * 8;
|
||||
if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super))
|
||||
super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super);
|
||||
bpg = EXT2FS_C2B(fs,
|
||||
(unsigned long long) super->s_clusters_per_group);
|
||||
if (bpg >= (((unsigned long long) 1) << 32)) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
super->s_blocks_per_group = bpg;
|
||||
} else {
|
||||
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_clusters_per_group = super->s_blocks_per_group;
|
||||
}
|
||||
|
||||
ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) &
|
||||
~((blk64_t) EXT2FS_CLUSTER_MASK(fs)));
|
||||
ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param));
|
||||
if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
set_field(s_mmp_update_interval, 0);
|
||||
|
||||
/*
|
||||
* If we're creating an external journal device, we don't need
|
||||
* to bother with the rest.
|
||||
*/
|
||||
if (ext2fs_has_feature_journal_dev(super)) {
|
||||
fs->group_desc_count = 0;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
*ret_fs = fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
fs->group_desc_count = (dgrp_t) ext2fs_div64_ceil(
|
||||
ext2fs_blocks_count(super) - super->s_first_data_block,
|
||||
EXT2_BLOCKS_PER_GROUP(super));
|
||||
if (fs->group_desc_count == 0) {
|
||||
retval = EXT2_ET_TOOSMALL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
set_field(s_desc_size,
|
||||
ext2fs_has_feature_64bit(super) ?
|
||||
EXT2_MIN_DESC_SIZE_64BIT : 0);
|
||||
|
||||
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
|
||||
EXT2_DESC_PER_BLOCK(super));
|
||||
|
||||
i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
|
||||
|
||||
if (ext2fs_has_feature_64bit(super) &&
|
||||
(ext2fs_blocks_count(super) / i) >= (1ULL << 32))
|
||||
set_field(s_inodes_count, ~0U);
|
||||
else
|
||||
set_field(s_inodes_count, ext2fs_blocks_count(super) / 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 = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
|
||||
if (ipg > fs->blocksize * 8) {
|
||||
if (!bigalloc_flag && super->s_blocks_per_group >= 256) {
|
||||
/* Try again with slightly different parameters */
|
||||
super->s_blocks_per_group -= 8;
|
||||
ext2fs_blocks_count_set(super,
|
||||
ext2fs_blocks_count(param));
|
||||
super->s_clusters_per_group = super->s_blocks_per_group;
|
||||
goto retry;
|
||||
} else {
|
||||
retval = EXT2_ET_TOO_MANY_INODES;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
|
||||
ipg = EXT2_MAX_INODES_PER_GROUP(super);
|
||||
|
||||
ipg_retry:
|
||||
super->s_inodes_per_group = ipg;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (super->s_inodes_per_group < 8)
|
||||
super->s_inodes_per_group = 8;
|
||||
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
|
||||
*/
|
||||
if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) {
|
||||
ipg--;
|
||||
goto ipg_retry;
|
||||
}
|
||||
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 (ext2fs_has_feature_resize_inode(super))
|
||||
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;
|
||||
}
|
||||
/* Enable meta_bg if we'd lose more than 3/4 of a BG to GDT blocks. */
|
||||
if (super->s_reserved_gdt_blocks + fs->desc_blocks >
|
||||
super->s_blocks_per_group * 3 / 4) {
|
||||
ext2fs_set_feature_meta_bg(fs->super);
|
||||
ext2fs_clear_feature_resize_inode(fs->super);
|
||||
set_field(s_reserved_gdt_blocks, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the maximum number of bookkeeping blocks per
|
||||
* group. It includes the superblock, the block group
|
||||
* descriptors, the block bitmap, the inode bitmap, the inode
|
||||
* table, and the reserved gdt blocks.
|
||||
*/
|
||||
overhead = (int) (3 + fs->inode_blocks_per_group +
|
||||
super->s_reserved_gdt_blocks);
|
||||
|
||||
if (ext2fs_has_feature_meta_bg(fs->super))
|
||||
overhead++;
|
||||
else
|
||||
overhead += fs->desc_blocks;
|
||||
|
||||
/* This can only happen if the user requested too many inodes */
|
||||
if (overhead > super->s_blocks_per_group) {
|
||||
retval = EXT2_ET_TOO_MANY_INODES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the last group is big enough to support the
|
||||
* necessary data structures. If not, we need to get rid of
|
||||
* it. We need to recalculate the overhead for the last block
|
||||
* group, since it might or might not have a superblock
|
||||
* backup.
|
||||
*/
|
||||
overhead = (int) (2 + fs->inode_blocks_per_group);
|
||||
has_bg = 0;
|
||||
if (ext2fs_has_feature_sparse_super2(super)) {
|
||||
/*
|
||||
* We have to do this manually since
|
||||
* super->s_backup_bgs hasn't been set up yet.
|
||||
*/
|
||||
if (fs->group_desc_count == 2)
|
||||
has_bg = param->s_backup_bgs[0] != 0;
|
||||
else
|
||||
has_bg = param->s_backup_bgs[1] != 0;
|
||||
} else
|
||||
has_bg = ext2fs_bg_has_super(fs, fs->group_desc_count - 1);
|
||||
if (has_bg)
|
||||
overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
|
||||
rem = ((ext2fs_blocks_count(super) - super->s_first_data_block) %
|
||||
super->s_blocks_per_group);
|
||||
if ((fs->group_desc_count == 1) && rem && (rem < overhead)) {
|
||||
retval = EXT2_ET_TOOSMALL;
|
||||
goto cleanup;
|
||||
}
|
||||
if (rem && (rem < overhead+50)) {
|
||||
ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) -
|
||||
rem);
|
||||
/*
|
||||
* If blocks count is changed, we need to recalculate
|
||||
* reserved blocks count not to exceed 50%.
|
||||
*/
|
||||
reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) /
|
||||
ext2fs_blocks_count(param);
|
||||
ext2fs_r_blocks_count_set(super, reserved_ratio *
|
||||
ext2fs_blocks_count(super) / 100.0);
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* Set up the locations of the backup superblocks */
|
||||
if (ext2fs_has_feature_sparse_super2(super)) {
|
||||
if (super->s_backup_bgs[0] >= fs->group_desc_count)
|
||||
super->s_backup_bgs[0] = fs->group_desc_count - 1;
|
||||
if (super->s_backup_bgs[1] >= fs->group_desc_count)
|
||||
super->s_backup_bgs[1] = fs->group_desc_count - 1;
|
||||
if (super->s_backup_bgs[0] == super->s_backup_bgs[1])
|
||||
super->s_backup_bgs[1] = 0;
|
||||
if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) {
|
||||
__u32 t = super->s_backup_bgs[0];
|
||||
super->s_backup_bgs[0] = super->s_backup_bgs[1];
|
||||
super->s_backup_bgs[1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
strcpy(buf, "block bitmap for ");
|
||||
strcat(buf, fs->device_name);
|
||||
retval = ext2fs_allocate_subcluster_bitmap(fs, buf, &fs->block_map);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
strcpy(buf, "inode bitmap for ");
|
||||
strcat(buf, fs->device_name);
|
||||
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
ext2fs_free_mem(&buf);
|
||||
|
||||
retval = ext2fs_get_array(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.
|
||||
*
|
||||
* If FLEX_BG meta-data grouping is used, only account for the
|
||||
* superblock and group descriptors (the inode tables and
|
||||
* bitmaps will be accounted for when allocated).
|
||||
*/
|
||||
free_blocks = 0;
|
||||
csum_flag = ext2fs_has_group_desc_csum(fs);
|
||||
reserved_inos = super->s_first_ino;
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
/*
|
||||
* Don't set the BLOCK_UNINIT group for the last group
|
||||
* because the block bitmap needs to be padded.
|
||||
*/
|
||||
if (csum_flag) {
|
||||
if (i != fs->group_desc_count - 1)
|
||||
ext2fs_bg_flags_set(fs, i,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
|
||||
numblocks = super->s_inodes_per_group;
|
||||
if (reserved_inos) {
|
||||
if (numblocks > reserved_inos) {
|
||||
numblocks -= reserved_inos;
|
||||
reserved_inos = 0;
|
||||
} else {
|
||||
reserved_inos -= numblocks;
|
||||
numblocks = 0;
|
||||
}
|
||||
}
|
||||
ext2fs_bg_itable_unused_set(fs, i, numblocks);
|
||||
}
|
||||
numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
|
||||
if (fs->super->s_log_groups_per_flex)
|
||||
numblocks += 2 + fs->inode_blocks_per_group;
|
||||
|
||||
free_blocks += numblocks;
|
||||
ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
|
||||
ext2fs_bg_free_inodes_count_set(fs, i, fs->super->s_inodes_per_group);
|
||||
ext2fs_bg_used_dirs_count_set(fs, i, 0);
|
||||
ext2fs_group_desc_csum_set(fs, i);
|
||||
}
|
||||
free_blocks &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
ext2fs_free_blocks_count_set(super, free_blocks);
|
||||
|
||||
c = (char) 255;
|
||||
if (((int) c) == -1) {
|
||||
super->s_flags |= EXT2_FLAGS_SIGNED_HASH;
|
||||
} else {
|
||||
super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
|
||||
}
|
||||
|
||||
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:
|
||||
free(buf);
|
||||
ext2fs_free(fs);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs, int super_only)
|
||||
{
|
||||
blk64_t blk;
|
||||
ext2_ino_t ino;
|
||||
unsigned int group = 0;
|
||||
unsigned int count = 0;
|
||||
int total_free = 0;
|
||||
int group_free = 0;
|
||||
int last_allocated = 0;
|
||||
int uninit;
|
||||
|
||||
/*
|
||||
* First calculate the block statistics
|
||||
*/
|
||||
uninit = 1;
|
||||
for (blk = fs->super->s_first_data_block;
|
||||
blk < ext2fs_blocks_count(fs->super); blk++) {
|
||||
if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
|
||||
group_free++;
|
||||
total_free++;
|
||||
} else {
|
||||
uninit = 0;
|
||||
}
|
||||
count++;
|
||||
if ((count == fs->super->s_blocks_per_group) ||
|
||||
(blk == ext2fs_blocks_count(fs->super)-1)) {
|
||||
ext2fs_bg_free_blocks_count_set(fs, group,
|
||||
group_free);
|
||||
if (!super_only) {
|
||||
if (uninit && blk !=
|
||||
ext2fs_blocks_count(fs->super) - 1)
|
||||
ext2fs_bg_flags_set(fs, group,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
else
|
||||
ext2fs_bg_flags_clear(fs, group,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
}
|
||||
count = 0;
|
||||
group_free = 0;
|
||||
uninit = 1;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
total_free = EXT2FS_C2B(fs, total_free);
|
||||
ext2fs_free_blocks_count_set(fs->super, total_free);
|
||||
|
||||
/*
|
||||
* Next, calculate the inode statistics
|
||||
*/
|
||||
group_free = 0;
|
||||
total_free = 0;
|
||||
last_allocated = 0;
|
||||
count = 0;
|
||||
group = 0;
|
||||
|
||||
/* Protect loop from wrap-around if s_inodes_count maxed */
|
||||
for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
|
||||
if (!ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
|
||||
group_free++;
|
||||
total_free++;
|
||||
} else {
|
||||
last_allocated = ino;
|
||||
}
|
||||
count++;
|
||||
if ((count == fs->super->s_inodes_per_group) ||
|
||||
(ino == fs->super->s_inodes_count)) {
|
||||
if (!super_only) {
|
||||
if (last_allocated) {
|
||||
ext2fs_bg_flags_clear(fs, group,
|
||||
EXT2_BG_INODE_UNINIT);
|
||||
ext2fs_bg_itable_unused_set(fs, group,
|
||||
fs->super->s_inodes_per_group -
|
||||
(last_allocated %
|
||||
fs->super->s_inodes_per_group));
|
||||
} else {
|
||||
ext2fs_bg_flags_set(fs, group,
|
||||
EXT2_BG_INODE_UNINIT);
|
||||
ext2fs_bg_itable_unused_set(fs, group,
|
||||
0);
|
||||
}
|
||||
ext2fs_bg_free_inodes_count_set(fs, group,
|
||||
group_free);
|
||||
}
|
||||
group++;
|
||||
count = 0;
|
||||
group_free = 0;
|
||||
last_allocated = 0;
|
||||
}
|
||||
}
|
||||
fs->super->s_free_inodes_count = total_free;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
return 0;
|
||||
}
|
||||
118
jni/e2fsprogs/lib/ext2fs/inline.c
Executable file
118
jni/e2fsprogs/lib/ext2fs/inline.c
Executable file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600 /* for posix_memalign() */
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#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
|
||||
#if HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#define INCLUDE_INLINE_FUNCS
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* We used to define this as an inline, but since we are now using
|
||||
* autoconf-defined #ifdef's, we need to export this as a
|
||||
* library-provided function exclusively.
|
||||
*/
|
||||
errcode_t ext2fs_get_memalign(unsigned long size,
|
||||
unsigned long align, void *ptr)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
void **p = ptr;
|
||||
|
||||
if (align < 8)
|
||||
align = 8;
|
||||
#ifdef HAVE_POSIX_MEMALIGN
|
||||
retval = posix_memalign(p, align, size);
|
||||
if (retval == ENOMEM)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
#else /* !HAVE_POSIX_MEMALIGN */
|
||||
#ifdef HAVE_MEMALIGN
|
||||
*p = memalign(align, size);
|
||||
if (*p == NULL) {
|
||||
if (errno)
|
||||
return errno;
|
||||
else
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
}
|
||||
#else /* !HAVE_MEMALIGN */
|
||||
#ifdef HAVE_VALLOC
|
||||
if (align > sizeof(long long))
|
||||
*p = valloc(size);
|
||||
else
|
||||
#endif
|
||||
*p = malloc(size);
|
||||
if ((uintptr_t) *p & (align - 1)) {
|
||||
free(*p);
|
||||
*p = 0;
|
||||
}
|
||||
if (*p == 0)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
#endif /* HAVE_MEMALIGN */
|
||||
#endif /* HAVE_POSIX_MEMALIGN */
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int isaligned(void *ptr, unsigned long align)
|
||||
{
|
||||
return (((unsigned long) ptr & (align - 1)) == 0);
|
||||
}
|
||||
|
||||
static errcode_t test_memalign(unsigned long align)
|
||||
{
|
||||
void *ptr = 0;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_get_memalign(32, align, &ptr);
|
||||
if (!retval && !isaligned(ptr, align))
|
||||
retval = EINVAL;
|
||||
free(ptr);
|
||||
printf("tst_memalign(%lu) is %s\n", align,
|
||||
retval ? error_message(retval) : "OK");
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (test_memalign(4))
|
||||
err++;
|
||||
if (test_memalign(32))
|
||||
err++;
|
||||
if (test_memalign(1024))
|
||||
err++;
|
||||
if (test_memalign(4096))
|
||||
err++;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
842
jni/e2fsprogs/lib/ext2fs/inline_data.c
Executable file
842
jni/e2fsprogs/lib/ext2fs/inline_data.c
Executable file
@@ -0,0 +1,842 @@
|
||||
/*
|
||||
* inline_data.c --- data in inode
|
||||
*
|
||||
* Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h> /* for PATH_MAX */
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2_ext_attr.h"
|
||||
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct ext2_inline_data {
|
||||
ext2_filsys fs;
|
||||
ext2_ino_t ino;
|
||||
size_t ea_size; /* the size of inline data in ea area */
|
||||
void *ea_data;
|
||||
};
|
||||
|
||||
static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data)
|
||||
{
|
||||
struct ext2_xattr_handle *handle;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_xattrs_read(handle);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
retval = ext2fs_xattr_set(handle, "system.data",
|
||||
data->ea_data, data->ea_size);
|
||||
err:
|
||||
(void) ext2fs_xattrs_close(&handle);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data)
|
||||
{
|
||||
struct ext2_xattr_handle *handle;
|
||||
errcode_t retval;
|
||||
|
||||
data->ea_size = 0;
|
||||
data->ea_data = 0;
|
||||
|
||||
retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_xattrs_read(handle);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
retval = ext2fs_xattr_get(handle, "system.data",
|
||||
(void **)&data->ea_data, &data->ea_size);
|
||||
if (retval == EXT2_ET_EA_KEY_NOT_FOUND) {
|
||||
data->ea_size = 0;
|
||||
data->ea_data = NULL;
|
||||
retval = 0;
|
||||
} else if (retval)
|
||||
goto err;
|
||||
|
||||
err:
|
||||
(void) ext2fs_xattrs_close(&handle);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino)
|
||||
{
|
||||
struct ext2_inline_data data;
|
||||
char empty[1] = { '\0' };
|
||||
|
||||
data.fs = fs;
|
||||
data.ino = ino;
|
||||
data.ea_size = 0;
|
||||
data.ea_data = empty;
|
||||
return ext2fs_inline_data_ea_set(&data);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, size_t *size)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
struct ext2_inline_data data;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!(inode.i_flags & EXT4_INLINE_DATA_FL))
|
||||
return EXT2_ET_NO_INLINE_DATA;
|
||||
|
||||
data.fs = fs;
|
||||
data.ino = ino;
|
||||
retval = ext2fs_inline_data_ea_get(&data);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
*size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size;
|
||||
return ext2fs_free_mem(&data.ea_data);
|
||||
}
|
||||
|
||||
int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
|
||||
void *priv_data)
|
||||
{
|
||||
struct dir_context *ctx;
|
||||
struct ext2_inode inode;
|
||||
struct ext2_dir_entry dirent;
|
||||
struct ext2_inline_data data;
|
||||
int ret = BLOCK_ABORT;
|
||||
e2_blkcnt_t blockcnt = 0;
|
||||
char *old_buf;
|
||||
unsigned int old_buflen;
|
||||
int old_flags;
|
||||
|
||||
ctx = (struct dir_context *)priv_data;
|
||||
old_buf = ctx->buf;
|
||||
old_buflen = ctx->buflen;
|
||||
old_flags = ctx->flags;
|
||||
ctx->flags |= DIRENT_FLAG_INCLUDE_INLINE_DATA;
|
||||
|
||||
ctx->errcode = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (ctx->errcode)
|
||||
goto out;
|
||||
|
||||
if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) {
|
||||
ctx->errcode = EXT2_ET_NO_INLINE_DATA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!LINUX_S_ISDIR(inode.i_mode)) {
|
||||
ctx->errcode = EXT2_ET_NO_DIRECTORY;
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
/* we first check '.' and '..' dir */
|
||||
dirent.inode = ino;
|
||||
dirent.name_len = 1;
|
||||
ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
|
||||
dirent.name[0] = '.';
|
||||
dirent.name[1] = '\0';
|
||||
ctx->buf = (char *)&dirent;
|
||||
ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
|
||||
ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto out;
|
||||
|
||||
dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
|
||||
dirent.name_len = 2;
|
||||
ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
|
||||
dirent.name[0] = '.';
|
||||
dirent.name[1] = '.';
|
||||
dirent.name[2] = '\0';
|
||||
ctx->buf = (char *)&dirent;
|
||||
ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
|
||||
ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
|
||||
if (ret & BLOCK_INLINE_DATA_CHANGED) {
|
||||
errcode_t err;
|
||||
|
||||
inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode);
|
||||
err = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (err)
|
||||
goto out;
|
||||
ret &= ~BLOCK_INLINE_DATA_CHANGED;
|
||||
}
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto out;
|
||||
|
||||
ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
|
||||
ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ABORT;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
|
||||
if (ret & BLOCK_INLINE_DATA_CHANGED) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
|
||||
ctx->buflen, 0);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ABORT;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
ctx->errcode = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (ctx->errcode)
|
||||
ret |= BLOCK_ABORT;
|
||||
ret &= ~BLOCK_INLINE_DATA_CHANGED;
|
||||
}
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto out;
|
||||
|
||||
data.fs = fs;
|
||||
data.ino = ino;
|
||||
ctx->errcode = ext2fs_inline_data_ea_get(&data);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ABORT;
|
||||
goto out;
|
||||
}
|
||||
if (data.ea_size <= 0)
|
||||
goto out1;
|
||||
|
||||
ctx->buf = data.ea_data;
|
||||
ctx->buflen = data.ea_size;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ABORT;
|
||||
goto out1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
|
||||
if (ret & BLOCK_INLINE_DATA_CHANGED) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
|
||||
ctx->buflen, 0);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ABORT;
|
||||
goto out1;
|
||||
}
|
||||
#endif
|
||||
ctx->errcode = ext2fs_inline_data_ea_set(&data);
|
||||
if (ctx->errcode)
|
||||
ret |= BLOCK_ABORT;
|
||||
}
|
||||
|
||||
out1:
|
||||
ext2fs_free_mem(&data.ea_data);
|
||||
out:
|
||||
ctx->buf = old_buf;
|
||||
ctx->buflen = old_buflen;
|
||||
ctx->flags = old_flags;
|
||||
ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino)
|
||||
{
|
||||
struct ext2_xattr_handle *handle;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_xattrs_open(fs, ino, &handle);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_xattrs_read(handle);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
retval = ext2fs_xattr_remove(handle, "system.data");
|
||||
err:
|
||||
(void) ext2fs_xattrs_close(&handle);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
|
||||
char *bbuf, char *ibuf, int size)
|
||||
{
|
||||
struct ext2_dir_entry *dir, *dir2;
|
||||
struct ext2_dir_entry_tail *t;
|
||||
errcode_t retval;
|
||||
int offset;
|
||||
unsigned int rec_len;
|
||||
int csum_size = 0;
|
||||
int filetype = 0;
|
||||
|
||||
if (ext2fs_has_feature_metadata_csum(fs->super))
|
||||
csum_size = sizeof(struct ext2_dir_entry_tail);
|
||||
|
||||
/* Create '.' and '..' */
|
||||
if (ext2fs_has_feature_filetype(fs->super))
|
||||
filetype = EXT2_FT_DIR;
|
||||
|
||||
/*
|
||||
* Set up entry for '.'
|
||||
*/
|
||||
dir = (struct ext2_dir_entry *) bbuf;
|
||||
dir->inode = ino;
|
||||
ext2fs_dirent_set_name_len(dir, 1);
|
||||
ext2fs_dirent_set_file_type(dir, filetype);
|
||||
dir->name[0] = '.';
|
||||
rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
|
||||
dir->rec_len = EXT2_DIR_REC_LEN(1);
|
||||
|
||||
/*
|
||||
* Set up entry for '..'
|
||||
*/
|
||||
dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
|
||||
dir->rec_len = EXT2_DIR_REC_LEN(2);
|
||||
dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
|
||||
ext2fs_dirent_set_name_len(dir, 2);
|
||||
ext2fs_dirent_set_file_type(dir, filetype);
|
||||
dir->name[0] = '.';
|
||||
dir->name[1] = '.';
|
||||
|
||||
/*
|
||||
* Adjust the last rec_len
|
||||
*/
|
||||
offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
|
||||
dir = (struct ext2_dir_entry *) (bbuf + offset);
|
||||
memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
size - EXT4_INLINE_DATA_DOTDOT_SIZE);
|
||||
size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
|
||||
EXT4_INLINE_DATA_DOTDOT_SIZE;
|
||||
|
||||
do {
|
||||
dir2 = dir;
|
||||
retval = ext2fs_get_rec_len(fs, dir, &rec_len);
|
||||
if (retval)
|
||||
goto err;
|
||||
offset += rec_len;
|
||||
dir = (struct ext2_dir_entry *) (bbuf + offset);
|
||||
} while (offset < size);
|
||||
rec_len += fs->blocksize - csum_size - offset;
|
||||
retval = ext2fs_set_rec_len(fs, rec_len, dir2);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
if (csum_size) {
|
||||
t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize);
|
||||
ext2fs_initialize_dirent_tail(fs, t);
|
||||
}
|
||||
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t
|
||||
ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, char *buf, size_t size)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t blk;
|
||||
char *blk_buf;
|
||||
|
||||
retval = ext2fs_get_memzero(fs->blocksize, &blk_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
size, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
#endif
|
||||
|
||||
/* Adjust the rec_len */
|
||||
retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
/* Allocate a new block */
|
||||
retval = ext2fs_new_block2(fs, 0, 0, &blk);
|
||||
if (retval)
|
||||
goto errout;
|
||||
retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
/* Update inode */
|
||||
if (ext2fs_has_feature_extents(fs->super))
|
||||
inode->i_flags |= EXT4_EXTENTS_FL;
|
||||
inode->i_flags &= ~EXT4_INLINE_DATA_FL;
|
||||
retval = ext2fs_iblk_add_blocks(fs, inode, 1);
|
||||
if (retval)
|
||||
goto errout;
|
||||
inode->i_size = fs->blocksize;
|
||||
retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk);
|
||||
if (retval)
|
||||
goto errout;
|
||||
retval = ext2fs_write_inode(fs, ino, inode);
|
||||
if (retval)
|
||||
goto errout;
|
||||
ext2fs_block_alloc_stats(fs, blk, +1);
|
||||
|
||||
errout:
|
||||
ext2fs_free_mem(&blk_buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t
|
||||
ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, char *buf, size_t size)
|
||||
{
|
||||
ext2_file_t e2_file;
|
||||
errcode_t retval;
|
||||
|
||||
/* Update inode */
|
||||
memset(inode->i_block, 0, sizeof(inode->i_block));
|
||||
if (ext2fs_has_feature_extents(fs->super)) {
|
||||
ext2_extent_handle_t handle;
|
||||
|
||||
inode->i_flags &= ~EXT4_EXTENTS_FL;
|
||||
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_extent_free(handle);
|
||||
}
|
||||
inode->i_flags &= ~EXT4_INLINE_DATA_FL;
|
||||
inode->i_size = 0;
|
||||
retval = ext2fs_write_inode(fs, ino, inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Write out the block buffer */
|
||||
retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ext2fs_file_write(e2_file, buf, size, 0);
|
||||
ext2fs_file_close(e2_file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
struct ext2_inline_data data;
|
||||
errcode_t retval;
|
||||
size_t inline_size;
|
||||
char *inline_buf = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!(inode.i_flags & EXT4_INLINE_DATA_FL))
|
||||
return EXT2_ET_NO_INLINE_DATA;
|
||||
|
||||
data.fs = fs;
|
||||
data.ino = ino;
|
||||
retval = ext2fs_inline_data_ea_get(&data);
|
||||
if (retval)
|
||||
return retval;
|
||||
inline_size = data.ea_size + EXT4_MIN_INLINE_DATA_SIZE;
|
||||
retval = ext2fs_get_mem(inline_size, &inline_buf);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
memcpy(inline_buf, (void *)inode.i_block, EXT4_MIN_INLINE_DATA_SIZE);
|
||||
if (data.ea_size > 0) {
|
||||
memcpy(inline_buf + EXT4_MIN_INLINE_DATA_SIZE,
|
||||
data.ea_data, data.ea_size);
|
||||
}
|
||||
|
||||
memset((void *)inode.i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
|
||||
/*
|
||||
* NOTE: We must do this write -> ea_remove -> read cycle here because
|
||||
* removing the inline data EA can free the EA block, which is a change
|
||||
* that our stack copy of the inode will never see. If that happens,
|
||||
* we can end up with the EA block and lblk 0 pointing to the same
|
||||
* pblk, which is bad news.
|
||||
*/
|
||||
retval = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (retval)
|
||||
goto errout;
|
||||
retval = ext2fs_inline_data_ea_remove(fs, ino);
|
||||
if (retval)
|
||||
goto errout;
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
if (LINUX_S_ISDIR(inode.i_mode)) {
|
||||
retval = ext2fs_inline_data_dir_expand(fs, ino, &inode,
|
||||
inline_buf, inline_size);
|
||||
} else {
|
||||
retval = ext2fs_inline_data_file_expand(fs, ino, &inode,
|
||||
inline_buf, inline_size);
|
||||
}
|
||||
|
||||
errout:
|
||||
if (inline_buf)
|
||||
ext2fs_free_mem(&inline_buf);
|
||||
ext2fs_free_mem(&data.ea_data);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* When caller uses this function to retrieve the inline data, it must
|
||||
* allocate a buffer which has the size of inline data. The size of
|
||||
* inline data can be know by ext2fs_inline_data_get_size().
|
||||
*/
|
||||
errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
void *buf, size_t *size)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
struct ext2_inline_data data;
|
||||
errcode_t retval;
|
||||
|
||||
if (!inode) {
|
||||
retval = ext2fs_read_inode(fs, ino, &inode_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
inode = &inode_buf;
|
||||
}
|
||||
|
||||
data.fs = fs;
|
||||
data.ino = ino;
|
||||
retval = ext2fs_inline_data_ea_get(&data);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
|
||||
if (data.ea_size > 0)
|
||||
memcpy((char *) buf + EXT4_MIN_INLINE_DATA_SIZE,
|
||||
data.ea_data, data.ea_size);
|
||||
|
||||
if (size)
|
||||
*size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size;
|
||||
ext2fs_free_mem(&data.ea_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
void *buf, size_t size)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
struct ext2_inline_data data = {
|
||||
.fs = fs,
|
||||
.ino = ino,
|
||||
};
|
||||
errcode_t retval;
|
||||
size_t free_ea_size, existing_size, free_inode_size;
|
||||
|
||||
if (!inode) {
|
||||
retval = ext2fs_read_inode(fs, ino, &inode_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
inode = &inode_buf;
|
||||
}
|
||||
|
||||
if (size <= EXT4_MIN_INLINE_DATA_SIZE) {
|
||||
memcpy((void *)inode->i_block, buf, size);
|
||||
} else {
|
||||
retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_inline_data_size(fs, ino, &existing_size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (existing_size < EXT4_MIN_INLINE_DATA_SIZE) {
|
||||
free_inode_size = EXT4_MIN_INLINE_DATA_SIZE -
|
||||
existing_size;
|
||||
} else {
|
||||
free_inode_size = 0;
|
||||
}
|
||||
|
||||
if (size != existing_size &&
|
||||
size > existing_size + free_ea_size + free_inode_size)
|
||||
return EXT2_ET_INLINE_DATA_NO_SPACE;
|
||||
|
||||
memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
|
||||
if (size > EXT4_MIN_INLINE_DATA_SIZE)
|
||||
data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE;
|
||||
data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE;
|
||||
}
|
||||
retval = ext2fs_write_inode(fs, ino, inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
return ext2fs_inline_data_ea_set(&data);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "e2p/e2p.h"
|
||||
|
||||
/*
|
||||
* The length of buffer is set to 64 because in inode's i_block member it only
|
||||
* can save 60 bytes. Thus this value can let the data being saved in extra
|
||||
* space.
|
||||
*/
|
||||
#define BUFF_SIZE (64)
|
||||
|
||||
static errcode_t file_test(ext2_filsys fs)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
ext2_ino_t newfile;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
char *buf = 0, *cmpbuf = 0;
|
||||
|
||||
/* create a new file */
|
||||
retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile);
|
||||
if (retval) {
|
||||
com_err("file_test", retval, "while allocating a new inode");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&inode, 0, sizeof(inode));
|
||||
inode.i_flags |= EXT4_INLINE_DATA_FL;
|
||||
inode.i_size = EXT4_MIN_INLINE_DATA_SIZE;
|
||||
inode.i_mode = LINUX_S_IFREG;
|
||||
retval = ext2fs_write_new_inode(fs, newfile, &inode);
|
||||
if (retval) {
|
||||
com_err("file_test", retval, "while writing a new inode");
|
||||
return 1;
|
||||
}
|
||||
|
||||
retval = ext2fs_inline_data_init(fs, newfile);
|
||||
if (retval) {
|
||||
com_err("file_test", retval, "while init 'system.data'");
|
||||
return 1;
|
||||
}
|
||||
|
||||
retval = ext2fs_inline_data_size(fs, newfile, &size);
|
||||
if (retval) {
|
||||
com_err("file_test", retval, "while getting size");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (size != EXT4_MIN_INLINE_DATA_SIZE) {
|
||||
fprintf(stderr,
|
||||
"tst_inline_data: size of inline data is wrong\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ext2fs_get_mem(BUFF_SIZE, &buf);
|
||||
memset(buf, 'a', BUFF_SIZE);
|
||||
retval = ext2fs_inline_data_set(fs, newfile, 0, buf, BUFF_SIZE);
|
||||
if (retval) {
|
||||
com_err("file_test", retval,
|
||||
"while setting inline data %s", buf);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ext2fs_get_mem(BUFF_SIZE, &cmpbuf);
|
||||
retval = ext2fs_inline_data_get(fs, newfile, 0, cmpbuf, &size);
|
||||
if (retval) {
|
||||
com_err("file_test", retval, "while getting inline data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (size != BUFF_SIZE) {
|
||||
fprintf(stderr,
|
||||
"tst_inline_data: size %zu != buflen %u\n",
|
||||
size, BUFF_SIZE);
|
||||
retval = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcmp(buf, cmpbuf, BUFF_SIZE)) {
|
||||
fprintf(stderr, "tst_inline_data: buf != cmpbuf\n");
|
||||
retval = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0ULL);
|
||||
if (retval) {
|
||||
com_err("file_test", retval, "while truncating inode");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* reload inode and check isize */
|
||||
ext2fs_read_inode(fs, newfile, &inode);
|
||||
if (inode.i_size != 0) {
|
||||
fprintf(stderr, "tst_inline_data: i_size should be 0\n");
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
err:
|
||||
if (cmpbuf)
|
||||
ext2fs_free_mem(&cmpbuf);
|
||||
if (buf)
|
||||
ext2fs_free_mem(&buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t dir_test(ext2_filsys fs)
|
||||
{
|
||||
const char *dot_name = ".";
|
||||
const char *stub_name = "stub";
|
||||
const char *parent_name = "test";
|
||||
ext2_ino_t parent, dir, tmp;
|
||||
errcode_t retval;
|
||||
char dirname[32];
|
||||
int i;
|
||||
|
||||
retval = ext2fs_mkdir(fs, 11, 11, stub_name);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval, "while creating %s dir", stub_name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_mkdir(fs, 11, 0, parent_name);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval,
|
||||
"while creating %s dir", parent_name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_lookup(fs, 11, parent_name, strlen(parent_name),
|
||||
0, &parent);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval,
|
||||
"while looking up %s dir", parent_name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_lookup(fs, parent, dot_name, strlen(dot_name),
|
||||
0, &tmp);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval,
|
||||
"while looking up %s dir", parent_name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (parent != tmp) {
|
||||
fprintf(stderr, "tst_inline_data: parent (%u) != tmp (%u)\n",
|
||||
parent, tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0, dir = 13; i < 4; i++, dir++) {
|
||||
tmp = 0;
|
||||
snprintf(dirname, sizeof(dirname), "%d", i);
|
||||
retval = ext2fs_mkdir(fs, parent, 0, dirname);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval,
|
||||
"while creating %s dir", dirname);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_lookup(fs, parent, dirname, strlen(dirname),
|
||||
0, &tmp);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval,
|
||||
"while looking up %s dir", parent_name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (dir != tmp) {
|
||||
fprintf(stderr,
|
||||
"tst_inline_data: dir (%u) != tmp (%u)\n",
|
||||
dir, tmp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(dirname, sizeof(dirname), "%d", i);
|
||||
retval = ext2fs_mkdir(fs, parent, 0, dirname);
|
||||
if (retval && retval != EXT2_ET_DIR_NO_SPACE) {
|
||||
com_err("dir_test", retval, "while creating %s dir", dirname);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_expand_dir(fs, parent);
|
||||
if (retval) {
|
||||
com_err("dir_test", retval, "while expanding %s dir", parent_name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
ext2_filsys fs;
|
||||
struct ext2_super_block param;
|
||||
errcode_t retval;
|
||||
|
||||
/* setup */
|
||||
initialize_ext2_error_table();
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
ext2fs_blocks_count_set(¶m, 32768);
|
||||
param.s_inodes_count = 100;
|
||||
|
||||
param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA;
|
||||
param.s_rev_level = EXT2_DYNAMIC_REV;
|
||||
param.s_inode_size = 256;
|
||||
|
||||
retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m,
|
||||
test_io_manager, &fs);
|
||||
if (retval) {
|
||||
com_err("setup", retval,
|
||||
"while initializing filesystem");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
retval = ext2fs_allocate_tables(fs);
|
||||
if (retval) {
|
||||
com_err("setup", retval,
|
||||
"while allocating tables for test filesystem");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialize inode cache */
|
||||
if (!fs->icache) {
|
||||
ext2_ino_t first_ino = EXT2_FIRST_INO(fs->super);
|
||||
int i;
|
||||
|
||||
/* we just want to init inode cache. So ignore error */
|
||||
ext2fs_create_inode_cache(fs, 16);
|
||||
if (!fs->icache) {
|
||||
fprintf(stderr,
|
||||
"tst_inline_data: init inode cache failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* setup inode cache */
|
||||
for (i = 0; i < fs->icache->cache_size; i++)
|
||||
fs->icache->cache[i].ino = first_ino++;
|
||||
}
|
||||
|
||||
/* test */
|
||||
if (file_test(fs)) {
|
||||
fprintf(stderr, "tst_inline_data(FILE): FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("tst_inline_data(FILE): OK\n");
|
||||
|
||||
if (dir_test(fs)) {
|
||||
fprintf(stderr, "tst_inline_data(DIR): FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("tst_inline_data(DIR): OK\n");
|
||||
ext2fs_free(fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
1122
jni/e2fsprogs/lib/ext2fs/inode.c
Executable file
1122
jni/e2fsprogs/lib/ext2fs/inode.c
Executable file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user