Compare commits
268 Commits
v0.6.2
...
release-0.
Author | SHA1 | Date | |
---|---|---|---|
1d44d931d0 | |||
5d5a0cbfd4 | |||
4353a35c59 | |||
2f48297d25 | |||
dfcb815480 | |||
f370829717 | |||
ef96f3588c | |||
e8fc149423 | |||
e12d409b80 | |||
b34fd35e62 | |||
714ee67472 | |||
8c4682ae92 | |||
5b073a2f29 | |||
c6f1101e9d | |||
f8d3bca20a | |||
46a947b602 | |||
56796ff55f | |||
1cbae01f12 | |||
da4634a593 | |||
f18d5157dc | |||
1195614881 | |||
1218e6e32d | |||
95381ce258 | |||
19fd87ef7b | |||
d20da80767 | |||
5009d1038d | |||
1ae2a39d1d | |||
70af4872c9 | |||
71d491ed37 | |||
cad3b000cf | |||
ece42746ec | |||
3f90111052 | |||
d87e5721db | |||
00802a1934 | |||
c2f502b9a8 | |||
1f2fd259ae | |||
9a873ed693 | |||
ec672ab903 | |||
99ddd5c116 | |||
63ddfc1c94 | |||
6886777ea0 | |||
77591e4546 | |||
540df15ec9 | |||
ce7a5c810f | |||
a809a87eef | |||
5732726a27 | |||
aae169aeeb | |||
1b5328d619 | |||
d565ae87f4 | |||
98a6db7f7f | |||
8a0be8ca19 | |||
dd1cde0379 | |||
d8d2709de9 | |||
854a3b8088 | |||
e8f8876ee6 | |||
f709a95fda | |||
d98081f173 | |||
6389bbbf58 | |||
b27bcc7022 | |||
f2b7872fc6 | |||
da125e8f6b | |||
198f6536bc | |||
437713cd8e | |||
0a265d9d4f | |||
806ea7b82e | |||
e7853df2f4 | |||
ece52dc070 | |||
21de3e2087 | |||
d28351c5a4 | |||
2534be5b5d | |||
681d092118 | |||
8b0920df53 | |||
e759bd5240 | |||
1a307cb790 | |||
41f75ea21f | |||
6cf484442c | |||
691887fd2c | |||
6f9db3d8c1 | |||
8eff065b5f | |||
5f2bde776b | |||
0402325ec2 | |||
da2619c42a | |||
183ed6cc5a | |||
cd427b269a | |||
50edfbea51 | |||
a6090a6273 | |||
a87c28da95 | |||
4d0063f7e2 | |||
4f468171ad | |||
32dc6dd041 | |||
8d8dcb9c93 | |||
e1460aa9a6 | |||
4daf626493 | |||
356b73eda8 | |||
f52c1aeb77 | |||
97d885fc9a | |||
0e0ecc1d00 | |||
c1ba7d93d9 | |||
a097793caf | |||
e17a8c718f | |||
fb2309ea16 | |||
e45f41fb44 | |||
0ada61b15e | |||
c789c23119 | |||
49821f6962 | |||
22e45ed489 | |||
1b3f5186e7 | |||
620547ac0a | |||
699866f984 | |||
2633aab967 | |||
b09dcd5246 | |||
b1f8161006 | |||
d7f691d6df | |||
b5fd981482 | |||
c974365b16 | |||
f66e3b8e2f | |||
64a9b79224 | |||
e8267b71d1 | |||
1add3e32c5 | |||
4c13522783 | |||
8d459c7f77 | |||
1eb8029e60 | |||
4950f869cb | |||
c226491f18 | |||
84c100c2f5 | |||
b600757649 | |||
313c4ff20f | |||
b824db94dc | |||
9f60c75f08 | |||
6dee6e4c20 | |||
b53ef57ac6 | |||
0b4792bc0c | |||
2cc74562fb | |||
d9f3244037 | |||
4ed2269570 | |||
7dfec561d9 | |||
dc26d8eefc | |||
bd9b49714f | |||
aae339fe49 | |||
c801fa60f7 | |||
c8495481ca | |||
65e5b00171 | |||
bb69e14b08 | |||
a5aedd51a4 | |||
1150ee32a4 | |||
d4ce4a7f88 | |||
6659ec1566 | |||
6ad6d3c219 | |||
24fadd7649 | |||
723d23321a | |||
ece6eca9a5 | |||
20adf50275 | |||
c6f4370e71 | |||
d01b3cc6cc | |||
9dc56426c0 | |||
de99f93640 | |||
3c91c2f333 | |||
3294dd5e94 | |||
e8f1dfb8e5 | |||
19661b0c05 | |||
1267052c03 | |||
f7a47baa22 | |||
cc9de1507f | |||
6b273ef79a | |||
a8c7d1b0e6 | |||
7990e01a57 | |||
23e2647920 | |||
412ad2fcdb | |||
14dd988f0f | |||
698fdec290 | |||
28e8936b4f | |||
0026c93cd4 | |||
fcf22cffe7 | |||
ed1041a069 | |||
eccaac09cc | |||
88ef351e74 | |||
cb3a879baf | |||
7e97a45b20 | |||
7db39f99b6 | |||
186c2f2ff7 | |||
1a4c5ba679 | |||
62315dfc44 | |||
56287470b0 | |||
89b0e9da68 | |||
65252934de | |||
60ab97b5f4 | |||
b959b150e9 | |||
68419703d7 | |||
e79ee64a2f | |||
33e058a66a | |||
75c44a1474 | |||
e91f12972b | |||
c1a7702f52 | |||
37e6752375 | |||
1ccc532808 | |||
2de74d04a7 | |||
7a87f47542 | |||
690e02a461 | |||
882073f145 | |||
fb3c3e1a6d | |||
ff480b35e9 | |||
643dbef05c | |||
f9e15054db | |||
ce0949a585 | |||
126e60741e | |||
2e99e1aac9 | |||
3a503a3e85 | |||
87f08d27ac | |||
3f6da75e9c | |||
6ff7699c47 | |||
68bd636bd8 | |||
35a623c7ec | |||
fc46f4ec84 | |||
2cc8a6d978 | |||
ab14c030bc | |||
86a3f4de22 | |||
558bdde116 | |||
1756cf4c92 | |||
927fb62ac4 | |||
f8938bd37b | |||
2e0688dee6 | |||
e318d48cb9 | |||
84771aa83b | |||
7e617733b1 | |||
ccc7b0b58f | |||
b94d993239 | |||
7b0da1ecd6 | |||
2374976b6d | |||
8b10d3107a | |||
987fa4b323 | |||
166f1d83bd | |||
648941cb15 | |||
d455f9b540 | |||
bad03a9a2b | |||
69fe1d6074 | |||
0c69463c5a | |||
ae43626f0b | |||
620c7a08e1 | |||
edc5ccf90a | |||
d534a96c83 | |||
085f6b64a3 | |||
d2a92bd0f6 | |||
6b583aa31f | |||
cb47296913 | |||
dd02d1d976 | |||
c75f1a430e | |||
d894d3719b | |||
6d633caadb | |||
955f2f9c24 | |||
061dce1ec2 | |||
31a92bd8bd | |||
b3ef67feb6 | |||
241a7295ba | |||
b9331ba5c1 | |||
0dad87f035 | |||
37f69d5360 | |||
811743a147 | |||
3c97b494b6 | |||
7b7fc4ddc1 | |||
d835235a93 | |||
e5f1cfca40 | |||
353ed64d77 | |||
e80ae930ea | |||
5a2ab22b81 | |||
25ab8631e4 | |||
3fa3292564 | |||
9c73b108f7 | |||
a98b4eda40 |
@ -38,3 +38,4 @@ demo/isogrow
|
||||
doc/html
|
||||
doc/doxygen.conf
|
||||
libisofs-1.pc
|
||||
demo/find
|
||||
|
@ -1,4 +1,4 @@
|
||||
#Fri Dec 28 21:07:56 CET 2007
|
||||
#Sat Sep 06 00:52:28 CEST 2008
|
||||
eclipse.preferences.version=1
|
||||
indexer/filesToParseUpFront=
|
||||
indexer/indexAllFiles=true
|
||||
|
@ -5,9 +5,8 @@ Copyright (C) 2007-2008 Vreixo Formoso, Mario Danic, Thomas Schmitt
|
||||
|
||||
|
||||
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.
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
137
Makefile.am
137
Makefile.am
@ -1,4 +1,8 @@
|
||||
pkgconfigdir=$(libdir)/pkgconfig
|
||||
|
||||
# ts A90315 : LIBBURNIA_PKGCONFDIR is defined OS specific in acinclude.m4
|
||||
# was: pkgconfigdir=$(libdir)/pkgconfig
|
||||
pkgconfigdir=$(LIBBURNIA_PKGCONFDIR)
|
||||
|
||||
libincludedir=$(includedir)/libisofs
|
||||
|
||||
lib_LTLIBRARIES = libisofs/libisofs.la
|
||||
@ -9,6 +13,13 @@ lib_LTLIBRARIES = libisofs/libisofs.la
|
||||
|
||||
libisofs_libisofs_la_LDFLAGS = \
|
||||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||
|
||||
# Eventually enabling system adapters for ACL and EA.
|
||||
# ts A90409: Eventually enabling use of zlib.
|
||||
libisofs_libisofs_la_CFLAGS = $(LIBACL_DEF) $(XATTR_DEF) $(ZLIB_DEF)
|
||||
|
||||
# ts A90114 : added aaip_0_2.*
|
||||
|
||||
libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/builder.h \
|
||||
libisofs/builder.c \
|
||||
@ -16,6 +27,7 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/node.c \
|
||||
libisofs/tree.h \
|
||||
libisofs/tree.c \
|
||||
libisofs/find.c \
|
||||
libisofs/image.h \
|
||||
libisofs/image.c \
|
||||
libisofs/fsource.h \
|
||||
@ -28,6 +40,12 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/libiso_msgs.c \
|
||||
libisofs/stream.h \
|
||||
libisofs/stream.c \
|
||||
libisofs/filter.h \
|
||||
libisofs/filter.c \
|
||||
libisofs/filters/xor_encrypt.c \
|
||||
libisofs/filters/external.c \
|
||||
libisofs/filters/zisofs.c \
|
||||
libisofs/filters/gzip.c \
|
||||
libisofs/util.h \
|
||||
libisofs/util.c \
|
||||
libisofs/util_rbtree.c \
|
||||
@ -39,6 +57,7 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/ecma119_tree.h \
|
||||
libisofs/ecma119_tree.c \
|
||||
libisofs/writer.h \
|
||||
libisofs/buffer.h \
|
||||
libisofs/buffer.c \
|
||||
libisofs/rockridge.h \
|
||||
libisofs/rockridge.c \
|
||||
@ -47,9 +66,16 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/joliet.c \
|
||||
libisofs/eltorito.h \
|
||||
libisofs/eltorito.c \
|
||||
libisofs/system_area.h \
|
||||
libisofs/system_area.c \
|
||||
libisofs/make_isohybrid_mbr.c \
|
||||
libisofs/iso1999.h \
|
||||
libisofs/iso1999.c \
|
||||
libisofs/data_source.c
|
||||
libisofs/data_source.c \
|
||||
libisofs/aaip_0_2.h \
|
||||
libisofs/aaip_0_2.c
|
||||
libisofs_libisofs_la_LIBADD= \
|
||||
$(THREAD_LIBS)
|
||||
libinclude_HEADERS = \
|
||||
libisofs/libisofs.h
|
||||
|
||||
@ -61,79 +87,100 @@ noinst_PROGRAMS = \
|
||||
demo/cat \
|
||||
demo/catbuffer \
|
||||
demo/tree \
|
||||
demo/find \
|
||||
demo/ecma119tree \
|
||||
demo/iso \
|
||||
demo/isoread \
|
||||
demo/isocat \
|
||||
demo/isomodify \
|
||||
demo/isoms \
|
||||
demo/isogrow
|
||||
demo/isoms
|
||||
|
||||
# demo/isogrow
|
||||
|
||||
demo_lsl_CPPFLAGS = -Ilibisofs
|
||||
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
demo_lsl_SOURCES = demo/lsl.c
|
||||
|
||||
demo_cat_CPPFLAGS = -Ilibisofs
|
||||
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
demo_cat_SOURCES = demo/cat.c
|
||||
|
||||
demo_catbuffer_CPPFLAGS = -Ilibisofs
|
||||
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_catbuffer_SOURCES = demo/cat_buffer.c
|
||||
|
||||
demo_tree_CPPFLAGS = -Ilibisofs
|
||||
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_tree_SOURCES = demo/tree.c
|
||||
|
||||
demo_find_CPPFLAGS = -Ilibisofs
|
||||
demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_find_SOURCES = demo/find.c
|
||||
|
||||
demo_ecma119tree_CPPFLAGS = -Ilibisofs
|
||||
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_ecma119tree_SOURCES = demo/ecma119_tree.c
|
||||
|
||||
demo_iso_CPPFLAGS = -Ilibisofs
|
||||
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
demo_iso_SOURCES = demo/iso.c
|
||||
|
||||
demo_isoread_CPPFLAGS = -Ilibisofs
|
||||
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_isoread_SOURCES = demo/iso_read.c
|
||||
|
||||
demo_isocat_CPPFLAGS = -Ilibisofs
|
||||
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_isocat_SOURCES = demo/iso_cat.c
|
||||
|
||||
demo_isomodify_CPPFLAGS = -Ilibisofs
|
||||
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_isomodify_SOURCES = demo/iso_modify.c
|
||||
|
||||
demo_isoms_CPPFLAGS = -Ilibisofs
|
||||
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
$(libisofs_libisofs_la_LIBADD)
|
||||
demo_isoms_SOURCES = demo/iso_ms.c
|
||||
|
||||
demo_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
|
||||
demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn
|
||||
demo_isogrow_SOURCES = demo/iso_grow.c
|
||||
# demo_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
|
||||
# demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD) \
|
||||
# -lburn
|
||||
# demo_isogrow_SOURCES = demo/iso_grow.c
|
||||
|
||||
|
||||
## Build unit test
|
||||
## ts A90428 , ticket 147, The test code does not use the API and is totally
|
||||
## outdated in its creation of mocked objects.
|
||||
## A volunteer is needed to rewrite it using the API.
|
||||
|
||||
# ## Build unit test
|
||||
|
||||
check_PROGRAMS = \
|
||||
test/test
|
||||
|
||||
test_test_CPPFLAGS = -Ilibisofs
|
||||
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
|
||||
test_test_LDFLAGS = -L.. -lm
|
||||
|
||||
test_test_SOURCES = \
|
||||
test/test.h \
|
||||
test/test.c \
|
||||
test/test_node.c \
|
||||
test/test_image.c \
|
||||
test/test_tree.c \
|
||||
test/test_util.c \
|
||||
test/test_rockridge.c \
|
||||
test/test_stream.c \
|
||||
test/mocked_fsrc.h \
|
||||
test/mocked_fsrc.c
|
||||
# check_PROGRAMS = \
|
||||
# test/test
|
||||
#
|
||||
# test_test_CPPFLAGS = -Ilibisofs
|
||||
# test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD) -lcunit
|
||||
# test_test_LDFLAGS = -L.. -lm
|
||||
#
|
||||
# test_test_SOURCES = \
|
||||
# test/test.h \
|
||||
# test/test.c \
|
||||
# test/test_node.c \
|
||||
# test/test_image.c \
|
||||
# test/test_tree.c \
|
||||
# test/test_util.c \
|
||||
# test/test_rockridge.c \
|
||||
# test/test_stream.c \
|
||||
# test/mocked_fsrc.h \
|
||||
# test/mocked_fsrc.c
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
@ -162,6 +209,8 @@ uninstall-local:
|
||||
nodist_pkgconfig_DATA = \
|
||||
libisofs-1.pc
|
||||
|
||||
# ts A80114 : added aaip-os*
|
||||
|
||||
EXTRA_DIST = \
|
||||
libisofs-1.pc.in \
|
||||
version.h.in \
|
||||
@ -171,9 +220,15 @@ EXTRA_DIST = \
|
||||
AUTHORS \
|
||||
COPYRIGHT \
|
||||
COPYING \
|
||||
NEWS \
|
||||
INSTALL \
|
||||
TODO \
|
||||
ChangeLog \
|
||||
Roadmap
|
||||
NEWS \
|
||||
INSTALL \
|
||||
TODO \
|
||||
ChangeLog \
|
||||
Roadmap \
|
||||
doc/susp_aaip_2_0.txt \
|
||||
doc/susp_aaip_isofs_names.txt \
|
||||
doc/zisofs_format.txt \
|
||||
libisofs/aaip-os-dummy.c \
|
||||
libisofs/aaip-os-linux.c \
|
||||
libisofs/aaip-os-freebsd.c
|
||||
|
||||
|
20
NEWS
20
NEWS
@ -1,3 +1,23 @@
|
||||
== Sun Apr 27 2008 ==
|
||||
|
||||
Libisofs v0.6.4
|
||||
===============
|
||||
|
||||
- Extended information: iso_node_add_xinfo()
|
||||
- New node iteration: iso_dir_find_children()
|
||||
- Custom image file content via iso_tree_add_new_file()
|
||||
- Missing feature added to map a disk file to an
|
||||
arbitrary image file path via iso_tree_add_new_node()
|
||||
- Obtain image path of a node object via iso_tree_get_node_path()
|
||||
- Various bugfixes
|
||||
|
||||
== Fri Feb 22 2008 ==
|
||||
|
||||
Libisofs v0.6.2.1
|
||||
=================
|
||||
|
||||
- FIX: missing buffer.h in tarball
|
||||
|
||||
== Thu Feb 14 2008 ==
|
||||
|
||||
Libisofs v0.6.2
|
||||
|
1
TODO
1
TODO
@ -9,7 +9,6 @@ TODO
|
||||
#00004 (libisofs.h) -> Add a get_mime_type() function.
|
||||
#00005 (node.c) -> optimize iso_dir_iter_take.
|
||||
#00006 (libisofs.h) -> define more replace values when adding a node to a dir
|
||||
#00007 (libisofs.h) -> expose iso_tree_add_new_file
|
||||
#00008 (data_dource.c) -> guard against partial reads
|
||||
#00009 (ecma119_tree.c/h) -> add true support for harlinks and inode numbers
|
||||
#00010 (buffer.c) -> optimize ring buffer
|
||||
|
@ -1,6 +1,7 @@
|
||||
AC_DEFUN([TARGET_SHIZZLE],
|
||||
[
|
||||
ARCH=""
|
||||
LIBBURNIA_PKGCONFDIR="$libdir"/pkgconfig
|
||||
|
||||
AC_MSG_CHECKING([target operating system])
|
||||
|
||||
@ -12,9 +13,12 @@ AC_DEFUN([TARGET_SHIZZLE],
|
||||
*-*-freebsd*)
|
||||
ARCH=freebsd
|
||||
LIBBURN_ARCH_LIBS=-lcam
|
||||
LIBBURNIA_PKGCONFDIR=$(echo "$libdir" | sed 's/\/lib$/\/libdata/')/pkgconfig
|
||||
;;
|
||||
*)
|
||||
AC_ERROR([You are attempting to compile for an unsupported platform])
|
||||
ARCH=
|
||||
LIBBURN_ARCH_LIBS=
|
||||
# AC_ERROR([You are attempting to compile for an unsupported platform])
|
||||
;;
|
||||
esac
|
||||
|
||||
|
63
configure.ac
63
configure.ac
@ -1,4 +1,4 @@
|
||||
AC_INIT([libisofs], [0.6.2], [http://libburnia-project.org])
|
||||
AC_INIT([libisofs], [0.6.20], [http://libburnia-project.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
@ -44,7 +44,7 @@ dnl If LIBISOFS_*_VERSION changes, be sure to change AC_INIT above to match.
|
||||
dnl
|
||||
LIBISOFS_MAJOR_VERSION=0
|
||||
LIBISOFS_MINOR_VERSION=6
|
||||
LIBISOFS_MICRO_VERSION=2
|
||||
LIBISOFS_MICRO_VERSION=20
|
||||
LIBISOFS_VERSION=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION.$LIBISOFS_MICRO_VERSION
|
||||
|
||||
AC_SUBST(LIBISOFS_MAJOR_VERSION)
|
||||
@ -54,10 +54,11 @@ AC_SUBST(LIBISOFS_VERSION)
|
||||
|
||||
dnl Libtool versioning
|
||||
LT_RELEASE=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION
|
||||
# SONAME = 6 - 0 = 6 . Library name = libisofs.6.0.0
|
||||
LT_CURRENT=6
|
||||
# 2009.05.30 development jump has not yet happened
|
||||
# SONAME = 22 - 16 = 6 . Library name = libisofs.6.16.0
|
||||
LT_CURRENT=22
|
||||
LT_REVISION=0
|
||||
LT_AGE=0
|
||||
LT_AGE=16
|
||||
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
|
||||
|
||||
AC_SUBST(LT_RELEASE)
|
||||
@ -84,6 +85,10 @@ if test ! $ac_cv_func_fseeko; then
|
||||
AC_MSG_ERROR([Libisofs requires largefile support.])
|
||||
fi
|
||||
|
||||
dnl If iconv(3) is in an extra lib, then it gets added to variable LIBS.
|
||||
dnl If not, then no -liconv will be added.
|
||||
AC_CHECK_LIB(iconv, iconv, , )
|
||||
|
||||
AC_PROG_LIBTOOL
|
||||
AC_SUBST(LIBTOOL_DEPS)
|
||||
LIBTOOL="$LIBTOOL --silent"
|
||||
@ -119,6 +124,7 @@ AC_SUBST(THREAD_LIBS)
|
||||
|
||||
TARGET_SHIZZLE
|
||||
AC_SUBST(ARCH)
|
||||
AC_SUBST(LIBBURNIA_PKGCONFDIR)
|
||||
AC_SUBST(LIBBURN_ARCH_LIBS)
|
||||
|
||||
dnl Add compiler-specific flags
|
||||
@ -146,6 +152,53 @@ AC_ARG_ENABLE(verbose-debug,
|
||||
AC_DEFINE(LIBISOFS_VERBOSE_DEBUG, 1))
|
||||
|
||||
|
||||
dnl ts A90123
|
||||
AC_ARG_ENABLE(libacl,
|
||||
[ --enable-libacl Enable use of libacl by libisofs, default=yes],
|
||||
, enable_libacl=yes)
|
||||
if test x$enable_libacl = xyes; then
|
||||
dnl Check whether there is libacl-devel and libacl-runtime.
|
||||
dnl If not, erase this macro which would enable use of acl_to_text and others
|
||||
LIBACL_DEF="-DLibisofs_with_aaip_acL"
|
||||
dnl The empty yes case obviously causes -lacl to be linked
|
||||
AC_CHECK_HEADER(sys/acl.h, AC_CHECK_LIB(acl, acl_to_text, , LIBACL_DEF= ), LIBACL_DEF= )
|
||||
else
|
||||
LIBACL_DEF=
|
||||
fi
|
||||
AC_SUBST(LIBACL_DEF)
|
||||
|
||||
|
||||
dnl ts A90123
|
||||
AC_ARG_ENABLE(xattr,
|
||||
[ --enable-xattr Enable use of xattr by libisofs, default=yes],
|
||||
, enable_xattr=yes)
|
||||
if test x$enable_xattr = xyes; then
|
||||
dnl Check whether there is the header for Linux xattr.
|
||||
dnl If not, erase this macro which would enable use of listxattr and others
|
||||
XATTR_DEF="-DLibisofs_with_aaip_xattR"
|
||||
AC_CHECK_HEADER(attr/xattr.h, AC_CHECK_LIB(c, listxattr, X= , XATTR_DEF= ), XATTR_DEF= )
|
||||
else
|
||||
XATTR_DEF=
|
||||
fi
|
||||
AC_SUBST(XATTR_DEF)
|
||||
|
||||
|
||||
dnl ts A90409
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[ --enable-zlib Enable use of zlib by libisofs, default=yes],
|
||||
, enable_zlib=yes)
|
||||
if test x$enable_zlib = xyes; then
|
||||
dnl Check whether there is the header for zlib.
|
||||
dnl If not, erase this macro which would enable use of compress2() and others.
|
||||
dnl The empty parameter after "compress2" causes -lz.
|
||||
ZLIB_DEF="-DLibisofs_with_zliB"
|
||||
AC_CHECK_HEADER(zlib.h, AC_CHECK_LIB(z, compress2, , ZLIB_DEF= ), ZLIB_DEF= )
|
||||
else
|
||||
ZLIB_DEF=
|
||||
fi
|
||||
AC_SUBST(ZLIB_DEF)
|
||||
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
doc/doxygen.conf
|
||||
|
63
demo/find.c
Normal file
63
demo/find.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Little program that import a directory, find matching nodes and prints the
|
||||
* resulting iso tree.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void
|
||||
print_dir(IsoDir *dir)
|
||||
{
|
||||
IsoDirIter *iter;
|
||||
IsoNode *node;
|
||||
IsoFindCondition *cond, *c1, *c2;
|
||||
|
||||
c1 = iso_new_find_conditions_name("*a*");
|
||||
c2 = iso_new_find_conditions_mode(S_IFREG);
|
||||
cond = iso_new_find_conditions_and(c1, c2);
|
||||
iso_dir_find_children(dir, cond, &iter);
|
||||
while (iso_dir_iter_next(iter, &node) == 1) {
|
||||
char *path = iso_tree_get_node_path(node);
|
||||
printf(" %s\n", path);
|
||||
free(path);
|
||||
}
|
||||
iso_dir_iter_free(iter);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImage *image;
|
||||
|
||||
if (argc != 2) {
|
||||
printf ("You need to specify a valid path\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
iso_init();
|
||||
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||
|
||||
result = iso_image_new("volume_id", &image);
|
||||
if (result < 0) {
|
||||
printf ("Error creating image\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
|
||||
if (result < 0) {
|
||||
printf ("Error adding directory %d\n", result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_dir(iso_image_get_root(image));
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
}
|
20
demo/iso.c
20
demo/iso.c
@ -3,8 +3,8 @@
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#define LIBISOFS_WITHOUT_LIBBURN yes
|
||||
#include "libisofs.h"
|
||||
#include "libburn/libburn.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
@ -91,7 +91,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
printf ("Please pass directory from which to build ISO\n");
|
||||
usage(argv);
|
||||
@ -102,7 +102,7 @@ int main(int argc, char **argv)
|
||||
usage(argv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fd = fopen(argv[optind+1], "w");
|
||||
if (!fd) {
|
||||
err(1, "error opening output file");
|
||||
@ -114,7 +114,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||
|
||||
|
||||
result = iso_image_new(volid, &image);
|
||||
if (result < 0) {
|
||||
printf ("Error creating image\n");
|
||||
@ -125,13 +125,13 @@ int main(int argc, char **argv)
|
||||
iso_tree_set_ignore_special(image, 0);
|
||||
iso_set_abort_severity("SORRY");
|
||||
/*iso_tree_set_report_callback(image, callback);*/
|
||||
|
||||
|
||||
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[optind]);
|
||||
if (result < 0) {
|
||||
printf ("Error adding directory %d\n", result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (boot_img) {
|
||||
/* adds El-Torito boot info. Tunned for isolinux */
|
||||
ElToritoBootImage *bootimg;
|
||||
@ -154,22 +154,22 @@ int main(int argc, char **argv)
|
||||
iso_write_opts_set_rockridge(opts, rr);
|
||||
iso_write_opts_set_joliet(opts, j);
|
||||
iso_write_opts_set_iso1999(opts, iso1999);
|
||||
|
||||
|
||||
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||
if (result < 0) {
|
||||
printf ("Cant create image, error %d\n", result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
iso_write_opts_free(opts);
|
||||
|
||||
|
||||
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||
fwrite(buf, 1, 2048, fd);
|
||||
}
|
||||
fclose(fd);
|
||||
burn_src->free_data(burn_src);
|
||||
free(burn_src);
|
||||
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
|
@ -2,8 +2,8 @@
|
||||
* Little program to show how to modify an iso image.
|
||||
*/
|
||||
|
||||
#define LIBISOFS_WITHOUT_LIBBURN yes
|
||||
#include "libisofs.h"
|
||||
#include "libburn/libburn.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -2,8 +2,8 @@
|
||||
* Little program to show how to create a multisession iso image.
|
||||
*/
|
||||
|
||||
#define LIBISOFS_WITHOUT_LIBBURN yes
|
||||
#include "libisofs.h"
|
||||
#include "libburn/libburn.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -39,7 +39,7 @@ print_type(mode_t mode)
|
||||
case S_IFREG: printf("[R] "); break;
|
||||
case S_IFBLK: printf("[B] "); break;
|
||||
case S_IFDIR: printf("[D] "); break;
|
||||
case S_IFIFO: printf("[F] "); break;
|
||||
case S_IFIFO: printf("[F] "); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +51,7 @@ print_file_src(IsoFileSource *file)
|
||||
iso_file_source_lstat(file, &info);
|
||||
print_type(info.st_mode);
|
||||
print_permissions(info.st_mode);
|
||||
printf(" %10llu ", info.st_size);
|
||||
//printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
|
||||
name = iso_file_source_get_name(file);
|
||||
printf(" %s", name);
|
||||
@ -116,7 +117,7 @@ int main(int argc, char **argv)
|
||||
|
||||
iso_init();
|
||||
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||
|
||||
|
||||
result = iso_data_source_new_from_file(argv[1], &src);
|
||||
if (result < 0) {
|
||||
printf ("Error creating data source\n");
|
||||
@ -134,10 +135,10 @@ int main(int argc, char **argv)
|
||||
printf ("Error creating filesystem\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
printf("\nVOLUME INFORMATION\n");
|
||||
printf("==================\n\n");
|
||||
|
||||
|
||||
printf("Vol. id: %s\n", iso_image_fs_get_volume_id(fs));
|
||||
printf("Publisher: %s\n", iso_image_fs_get_publisher_id(fs));
|
||||
printf("Data preparer: %s\n", iso_image_fs_get_data_preparer_id(fs));
|
||||
@ -149,7 +150,7 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("\nDIRECTORY TREE\n");
|
||||
printf("==============\n");
|
||||
|
||||
|
||||
result = fs->get_root(fs, &root);
|
||||
if (result < 0) {
|
||||
printf ("Can't get root %d\n", result);
|
||||
@ -158,7 +159,7 @@ int main(int argc, char **argv)
|
||||
//print_file_src(root);
|
||||
print_dir(root, 0);
|
||||
iso_file_source_unref(root);
|
||||
|
||||
|
||||
fs->close(fs);
|
||||
iso_filesystem_unref((IsoFilesystem*)fs);
|
||||
iso_data_source_unref(src);
|
||||
|
58
doc/devel/cookbook/Multi-Extent.txt
Normal file
58
doc/devel/cookbook/Multi-Extent.txt
Normal file
@ -0,0 +1,58 @@
|
||||
===============================================================================
|
||||
ISO-9660 Level 3 Cookbook
|
||||
===============================================================================
|
||||
|
||||
Creation date: 2008-Aug-17
|
||||
Author: Vreixo Formoso
|
||||
_______________________________________________________________________________
|
||||
|
||||
Contents:
|
||||
---------
|
||||
|
||||
1. References
|
||||
2. General
|
||||
3. OS Support
|
||||
4. Implementation
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
1. References:
|
||||
|
||||
ECMA-119 "Volume and File Structure of CDROM for Information Interchange"
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
2. General
|
||||
|
||||
In ECMA-119 standard, the size of a file section cannot be bigger than 4GB - 1,
|
||||
because the Data Length field of the Directory Record is just 32 bits (9.1.4).
|
||||
|
||||
However, "each file shall consist of one or more File Sections" (6.5.1), and
|
||||
that way we can store files greater than 4GB in a ECMA-119 image. Such image,
|
||||
with multiple File Sections, is only supported at Level 3 (10.3), as Level 2
|
||||
(10.2) states that "each file shall consist of only one File Section".
|
||||
|
||||
On disc, each file section is stored in a Extent (6.4.2), i.e. a set of
|
||||
contiguous Logical Blocks.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
3. OS Support
|
||||
|
||||
Wikipedia states that "Microsoft Windows XP supports this, while Mac OS X
|
||||
(as of 10.4.8) does not handle this case properly. In the case of Mac OS X,
|
||||
the driver appears not to support file fragmentation at all (i.e. it only
|
||||
supports ISO 9660 Level 2 but not Level 3). Linux supports multiple extents.
|
||||
FreeBSD only shows and reads the last extent of a multi-extent file."
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
4. Implementation
|
||||
|
||||
Each File Section will have its own Directory Record (6.5.1). So, for files
|
||||
greater than 4 GB, we need to store several directory records, that will have
|
||||
the same File Identifier, and stored in the order of the File Sections they
|
||||
refer (9.3).
|
||||
|
||||
All but the last Directory Record must have the Multi-Extent flag set (9.1.6)
|
||||
|
||||
|
445
doc/susp_aaip_2_0.txt
Normal file
445
doc/susp_aaip_2_0.txt
Normal file
@ -0,0 +1,445 @@
|
||||
|
||||
|
||||
Arbitrary Attribute Interchange Protocol
|
||||
|
||||
Version 2.0
|
||||
|
||||
Mar 18 2009
|
||||
|
||||
Interchange of Persistent File Attributes
|
||||
|
||||
by Thomas Schmitt - mailto:scdbackup@gmx.net
|
||||
Libburnia project - mailto:libburn-hackers@pykix.org
|
||||
|
||||
|
||||
AAIP is intended as companion of the Rock Ridge Interchange Protocol RRIP
|
||||
which under the general design of System Use Sharing Protocol SUSP extends
|
||||
ISO 9660 aka ECMA-119 filesystem semantics to match POSIX needs.
|
||||
|
||||
Goal is to have for each file an arbitrary number of attributes which consist
|
||||
of two components (Name and Value) of arbitrary length and to have a compact
|
||||
representation of ACLs.
|
||||
|
||||
This document describes a SUSP entry with Signature Word "AL" which collides
|
||||
neither with SUSP 1.12 nor with RRIP 1.12. The AL entry has been designed
|
||||
to be as similar to the RRIP entry SL as possible.
|
||||
The presence of AAIP shall be announced by a particular ER entry.
|
||||
|
||||
Since the size of a SUSP entry is limited to 255, multiple entries may be
|
||||
needed to describe one component. The CE mechanism of SUSP shall be used to
|
||||
address enough storage if needed.
|
||||
|
||||
AL entries and the ER entry of AAIP shall only be present if the ER entry
|
||||
of RRIP is present.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
System Entries Provided by this Specification
|
||||
|
||||
* AL
|
||||
|
||||
Description of the "AL" System Use Entry
|
||||
|
||||
The entry has exactly the same layout as RRIP entry SL. One has to expect
|
||||
more data bytes than with SL, though, and any of the 256 possible byte values.
|
||||
The reader shall be prepared to detect and handle oversized data.
|
||||
|
||||
One or more AL entries form the Attribute List of a file object with
|
||||
an even number of components. Each two consequtive components form a pair of
|
||||
Name and Value.
|
||||
|
||||
The empty name indicates that the value is a compact representation of ACLs.
|
||||
Names must not contain byte value 0x00. Names which begin by bytes 0x01 to 0x1f
|
||||
represent names in particular namespaces. See below: Namespaces.
|
||||
The meaning of any other names or name parts is not specified by this document.
|
||||
|
||||
All AL entries except the last one shall have the CONTINUE flag set. An AL
|
||||
entry with CONTINUE set to 0 indicates the end of the Attribute List.
|
||||
|
||||
The format of the AL System Use Field is as follows:
|
||||
|
||||
[1] "BP 1 to BP 2 - Signature Word" shall be (41)(4C) ("AL").
|
||||
|
||||
[2] "BP 3 - Length" shall specify as an 8-bit number the length in bytes of
|
||||
the AL entry recorded according to ISO 9660:7.1.1.
|
||||
|
||||
[3] "BP 4 - System Use Entry Version" shall be 1 as in ISO 9660:7.1.1.
|
||||
|
||||
[4] "BP 5 - Flags" shall contain bit field flags numbered 0 to 7 starting
|
||||
with the least significant bit as follows:
|
||||
0 CONTINUE This AL entry continues in the next AL entry.
|
||||
All other bits shall be set to 0.
|
||||
|
||||
[5] "BP 6 to Length - Component Area" shall contain Component Records
|
||||
as described below.
|
||||
|
||||
| 'A' | 'L' | LENGTH | 1 | FLAGS | COMPONENT AREA |
|
||||
|
||||
|
||||
Within AL entries each component (Name or Value) shall be recorded as one
|
||||
or more component records. If a component does not fit into the remaining
|
||||
space of an AL entry then it shall be continued in following AL entries.
|
||||
|
||||
All Component Records of a component except the last one shall have the
|
||||
CONTINUE flag set. A Component Record with CONTINUE set to 0 indicates the end
|
||||
of the component. An eventually following Component Record starts the next
|
||||
component.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The Component Record format is identical to the one of the SL entry.
|
||||
The complete form of the following summary can be found in RRIP 1.12 "4.1.3.1".
|
||||
In case of discrepancies, RRIP 1.12 is the decisive specification. Please
|
||||
inform the author of this document if you find such a discrepancy.
|
||||
|
||||
Component Records shall be recorded contiguously within each Component Area,
|
||||
starting in the first byte of the Component Area. The last Component Record
|
||||
in the Component Area of an AL System Use Entry may be continued in the
|
||||
Component Area of the next recorded AL System Use Entry in the same
|
||||
System Use Area.
|
||||
|
||||
Each Component Record shall have the following format:
|
||||
|
||||
[A] "BP 1 - Component Flags" shall contain bit field flags numbered 0 to 7,
|
||||
starting with the least significant bit, as follows:
|
||||
0 CONTINUE This Component Record continues in the next
|
||||
AL Component Record.
|
||||
all others are RESERVED and shall be 0.
|
||||
|
||||
[B] "BP 2 - Component Length (LEN_CP)" shall specify as an 8-bit number the
|
||||
number of component bytes in the Component Record. This length shall not
|
||||
include the first two bytes of the Component Record.
|
||||
If any of the bit positions 1-3 is set, the value of this field shall be
|
||||
set to ZERO and no Component Content shall be recorded.
|
||||
This field shall be recorded according to ISO 9660 Format section 7.1.1.
|
||||
|
||||
[C] "BP 3 to 2 + LEN_CP - Component Content" shall contain the component
|
||||
bytes in the Component Record.
|
||||
|
||||
| COMPONENT FLAGS | LEN_CP | COMPONENT BYTES |
|
||||
|
||||
|
||||
Example: Two pairs of "name"="long...content" and "one"="more" encoded as
|
||||
two AL entries
|
||||
|
||||
Field 1 contains the Component Record of Name and one Component Record of
|
||||
Value :
|
||||
{ 'A', 'L', 255, 1, 1,
|
||||
0, 4, 'n', 'a', 'm', 'e',
|
||||
1, 255, 'l', 'o', 'n', 'g', ... 238 more bytes, 13 go to next AL ... }
|
||||
Field 2 contains the rest of "long...content" and the complete second pair.
|
||||
It marks the end of the Attribute List :
|
||||
{ 'A', 'L', 38, 1, 0,
|
||||
... 13 remaining bytes of the Component Record in first entry ...
|
||||
0, 7, 'c', 'o', 'n', 't', 'e', 'n', 't',
|
||||
0, 3, 'o', 'n', 'e',
|
||||
0, 4, 'm', 'o', 'r', 'e' }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Namespaces
|
||||
|
||||
AAIP provides a short notation for namespaces which uses a single non-printable
|
||||
byte at the start of the name.
|
||||
Reserved start bytes of names are
|
||||
0x01 to 0x1F
|
||||
|
||||
The names of extended file attributes are traditionally organized in
|
||||
namespaces, which get expressed as first part of an attribute name up to a
|
||||
period "." character. It is also tradition that names are printable text,
|
||||
single words and especially contain no 0-bytes.
|
||||
|
||||
AAIP does not enforce the use of any namespace but it urges that names in the
|
||||
following registered namespaces are used according to traditions.
|
||||
|
||||
The namespaces "system." and "user." are available with many file system
|
||||
types. "system." is file system dependent and often restricted in the
|
||||
choice of names. "user." is portable and allows to choose about any name.
|
||||
|
||||
Namespace "isofs." is defined for internal use of AAIP enhanced ISO 9660
|
||||
file systems. Names in this namespace should be registered at libburnia.org.
|
||||
|
||||
Further namespaces may be registered at libburnia.org.
|
||||
|
||||
The reserved start bytes of names have the following meaning
|
||||
0x01 escape reserved character at start of name
|
||||
0x02 namespace "system."
|
||||
0x03 namespace "user."
|
||||
0x04 namespace "isofs."
|
||||
0x05 namespace "trusted."
|
||||
0x06 namespace "security."
|
||||
0x07 to 0x1F shall not be used yet.
|
||||
|
||||
Examples:
|
||||
Name "user.abc" with and without short notation. Both is allowed.
|
||||
0, 4, 0x03, 'a', 'b', 'c'
|
||||
0 8, 'u', 's', 'e', 'r', '.', 'a', 'b', 'c'
|
||||
|
||||
Name "\003abc" (if really desired)
|
||||
0, 5, 0x01, 0x03, 'a', 'b', 'c'
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Specification of binary ACL representation as special Arbitrary Attribute
|
||||
|
||||
The Name component of a binary ACL shall be of length 0.
|
||||
|
||||
The Value shall be an arbitrary number of ACL Entries:
|
||||
|
||||
[a] "BP 1 - Entry Flags" shall contain bit field flags numbered 0 to 7,
|
||||
starting with the least significant bit, as follows:
|
||||
0 EXEC indicates that this entry grants execute permission
|
||||
1 WRITE write permission
|
||||
2 READ read permission
|
||||
3 QUALIFIER indicates that one or more Qualifier Records follow
|
||||
4 - 7 TYPE
|
||||
shall contain the tag type of the ACL entry as four bit code:
|
||||
0 TRANSLATE Entry for a global map of name to numeric id
|
||||
Qualifier is a record of number and text
|
||||
1 ACL_USER_OBJ Permissions of owning user (as of PX entry)
|
||||
3 ACL_GROUP_OBJ Permissions of owning group (as of PX entry)
|
||||
5 ACL_MASK Restricts 10, 3, and 12 via logical AND
|
||||
6 ACL_OTHER Permissions of non-listed, non-owning users
|
||||
8 SWITCH_MARK Switch from "access" ACL to "default" ACL
|
||||
10 ACL_USER_N Permissions of arbitrary user. Qualifier is
|
||||
the numeric user id (max. 4 bytes).
|
||||
12 ACL_GROUP_N Permissions of arbitrary group. Qualifier is
|
||||
the numeric group id (max. 4 bytes).
|
||||
15 FUTURE_VERSION Will indicate that this document
|
||||
does not apply to the entry.
|
||||
The other values are reserved. Readers shall ignore them if
|
||||
they are not aware of updates of this document which would
|
||||
assign a meaning to them.
|
||||
|
||||
The entries must match the permission bits of the PX entry. This shall obey the
|
||||
rule that ACL_USER_OBJ must match S_IRWXU, ACL_OTHER must match S_IRWXO,
|
||||
ACL_MASK - if present - must match S_IRWXG, else ACL_GROUP_OBJ must match
|
||||
S_IRWXG. If there is ACL_USER_N or ACL_GROUP_N there must also be ACL_MASK.
|
||||
|
||||
A numeric qualifier is a binary number of variable length up to 4 bytes. The
|
||||
Most Significant Byte comes first. The number shall be the "POSIX File User ID"
|
||||
resp. "POSIX File Group ID" as also used in RRIP PX entries. The ids of owning
|
||||
user and owning group shall be taken from the PX entry of the file object.
|
||||
|
||||
Optional TRANSLATE entries may associate user or group names with numeric
|
||||
ids to allow the reading system to remap the numeric ids. See below.
|
||||
The writer is not obliged to write them and the reader is not obliged to
|
||||
interpret them.
|
||||
|
||||
The ACL entries belong to the "access" ACL of a file object. An optional
|
||||
SWITCH_MARK entry may direct further entries to the "default" ACL which
|
||||
is defined for directory objects. The EXEC bit of SWITCH_MARK shall be 1.
|
||||
The bits for WRITE, READ, QUALIFIER shall be 0.
|
||||
|
||||
An eventually needed qualifier is stored in one or more Qualifier Records.
|
||||
|
||||
[b] "BP 2 - Qualifier Record Head" shall be present only if QUALIFIER is set
|
||||
to 1. It shall give the number of Qualifier Bytes and eventually
|
||||
indicate that the qualifier continues in a Qualifier Record which comes
|
||||
imediately after this record.
|
||||
0 to 127 Q_LENGTH, the qualifier is complete by this record
|
||||
128 to 255 Q_LENGTH+128, the qualifier is continued by next record
|
||||
So a Qualifier Record can contain at most 127 Qualifier Bytes.
|
||||
This field shall be recorded according to ISO 9660 Format section 7.1.1.
|
||||
|
||||
[c] "BP 3 to BP 2 + Q_LENGTH - Qualifier Bytes" shall be present only if
|
||||
QUALIFIER is set to 1 and hold the announced number of bytes of the
|
||||
user or group name.
|
||||
|
||||
| ENTRY FLAGS [ | QUALIFIER HEAD | QUALIFIER BYTES | ]
|
||||
|
||||
|
||||
Example: From man 5 acl: u::rw-,u:lisa:rw-,g::r--,g:toolies:rw-,m::r--,o::r--
|
||||
"lisa" has user number 123, "toolies" has group number 65534
|
||||
{ 'A', 'L', 20, 1, 0,
|
||||
0, 0,
|
||||
0, 11, 0x16,
|
||||
0xAE, 1, 123,
|
||||
0x34,
|
||||
0xCE, 2, 255, 254,
|
||||
0x54,
|
||||
0x64 }
|
||||
|
||||
Example: "Access" ACL and "default" ACL (0x81 is the switch mark)
|
||||
u::rwx,g::r-x,o::r-x, du::rwx,dg::r-x,dm::rwx,do::r-x,du:lisa:rwx
|
||||
{ 'A', 'L', 20, 1, 0,
|
||||
0, 0,
|
||||
0, 11, 0x17, 0x35, 0x65,
|
||||
0x81,
|
||||
0x17, 0x35, 0x57, 0x65,
|
||||
0xA7, 1, 123 }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Association of Names and Numeric Identifiers
|
||||
|
||||
The entry flag value 0x08 TRANSLATE is not a ACL entry of the hosting object
|
||||
but rather a global hint about the relation of roles, names and numeric ids.
|
||||
If it is recorded at all, then it shall be recorded with the first Directory
|
||||
Entry of the volume's root directory. According to the description of SUSP
|
||||
entry ER, this has to be "dot" or (00). Other than with ER, a TRANSLATE entry
|
||||
may not appear in the root of directory sub trees.
|
||||
|
||||
An interested reader shall examine the Arbitrary Attributes of this Directory
|
||||
Entry in order to collect a translation table.
|
||||
The advised translation is: PX or AL Id number -> name -> local id number.
|
||||
|
||||
The Qualifier Bytes of a TRANSLATE entry shall have the following format:
|
||||
|
||||
[i] "BP 0 - Role" shall tell whether it is about a user name (role 0) or
|
||||
a group name (role 1). Other values are not allowed.
|
||||
|
||||
[ii] "BP 1 to BP 8 - Numeric Id" shall hold the 32 bit POSIX Id number of the
|
||||
entry. This field shall be recorded according to ISO 9660:7.3.3.
|
||||
|
||||
[iii] "BP 9 to End Of Qualifier - Name" shall hold the name bytes of this
|
||||
entry.
|
||||
|
||||
| ROLE | NUMERIC ID | NAME |
|
||||
|
||||
Example: User id number 123 gets associated with user name "lisa"
|
||||
|
||||
0x08, 13, 0, 123,0,0,0, 0,0,0,123, 'l', 'i', 's', 'a',
|
||||
|
||||
|
||||
Example: A very long qualifier naming "His_Excellency_..._the_Boss" as user #1.
|
||||
This needs two qualifier records.
|
||||
0x08, 255, 0, 1,0,0,0, 0,0,0,1,
|
||||
'H', 'i', 's', '_', 'E', 'x', 'c', 'e', 'l', 'e',
|
||||
... 108 more bytes ...
|
||||
8, 't', 'h', 'e', '_', 'B', 'o', 's', 's',
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Specification of the ER System Use Entry Values for AAIP:
|
||||
|
||||
This ER system entry shall only be present if the ER entry of RRIP is present.
|
||||
To be compliant with SUSP-1.12, this ER entry must be present if AL entries
|
||||
are present, and ES entries have to mark RRIP and AAIP entries.
|
||||
If for some reason compliance with SUSP-1.10 is intended, then this ER entry
|
||||
and the ES entries must not be present, although SUSP-1.10 would allow ER.
|
||||
(See below: Compatibility considerations.)
|
||||
|
||||
The Extension Version number for this version of AAIP shall be 1.
|
||||
|
||||
The Extension Identifier field shall be "AAIP_0200" with Identifier Length 9.
|
||||
|
||||
The mandatory content form of the Extension Descriptor is
|
||||
"AL PROVIDES VIA AAIP 2.0 SUPPORT FOR ARBITRARY FILE ATTRIBUTES IN ISO 9660 IMAGES"
|
||||
The Description Length is 81.
|
||||
|
||||
The recommended content of the Extension Source is
|
||||
"PLEASE CONTACT THE LIBBURNIA PROJECT VIA LIBBURNIA-PROJECT.ORG".
|
||||
The corresponding Source Length is 62.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Compatibility Considerations
|
||||
|
||||
This extension is supposed not to disturb any reader system which complies
|
||||
to SUSP-1.10:
|
||||
"6.2 Requirements for a Receiving System
|
||||
[...]
|
||||
Any System Use Field which the receiving system does not recognize
|
||||
is to be ignored and skipped."
|
||||
|
||||
SUSP-1.12 extends this prescription by:
|
||||
"Any System Use Entry, with the exception of the set of System Use Entries
|
||||
defined in this document, following an "ES" System Use Entry that indicates
|
||||
an extension specification which the receiving system does not recognize
|
||||
shall be ignored and skipped."
|
||||
|
||||
According to SUSP-1.12 the ER entry is mandatory for a conformant extension.
|
||||
It also prescribes that in the case that ER entries of RRIP and AAIP are
|
||||
present, then ES entries shall be used to separate RRIP entries from AAIP
|
||||
entries.
|
||||
SUSP-1.12 frowns on extensions which are not announced by ER. Nevertheless
|
||||
is does not totally outrule them.
|
||||
|
||||
SUSP-1.10 does not specify ES entries at all and allows to have extension
|
||||
entries without announcing them by an ER entry. So if a second ER entry is
|
||||
not bearable, then the SUSP-1.10 downgrade of AAIP allows to omit the
|
||||
AAIP ER and the ES entries. But if there is the AAIP ER then there must be ES
|
||||
at the appropriate places. Else the format would explicitely violate SUSP-1.12.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Model Relations:
|
||||
|
||||
Attribute List ------------- [1:0..1] ------------- ACL
|
||||
[1:0..n] [1:0..n]
|
||||
Arbitrary Attribute ( [1:0..1] ACL ) Entry
|
||||
[1:2..2n] [1:0..1]
|
||||
Component ( [1..m:1..n] AL Field ) Qualifier
|
||||
[1:1..n] << one of >>
|
||||
Component Record / \
|
||||
[1..m:1..n] Translation Entry , Numeric Id
|
||||
AL Field | |
|
||||
[1:1..n] [1:1]
|
||||
\ /
|
||||
Qualifier Record
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Revoked drafts:
|
||||
|
||||
The following outdated versions may be interpreted at read time but they
|
||||
shall not be written any more.
|
||||
|
||||
AAIP-1.0
|
||||
|
||||
Previous versions up to AAIP 1.0 used field signature "AA" rather than "AL".
|
||||
This nearly collides with "Apple ISO 9660 Extensions". The Apple "AA" field of
|
||||
version 1 has a length of 7, whereas the shortest first AAIP field "AA" had
|
||||
length 9.
|
||||
|
||||
Beginning with AAIP 2.0, the field name has been changed to "AL".
|
||||
If a reader interprets old AAIP "AA" fields, then it must take precautions to
|
||||
distinguish them from Apple "AA" fields. But it is well compliant with AAIP 2.0
|
||||
to just ignore any kind of "AA" fields.
|
||||
|
||||
AAIP 1.0 had ER signature "AAIP_0100".
|
||||
|
||||
AAIP-0.2
|
||||
|
||||
AAIP 0.2 with ER signature "AAIP_0002" allowed to announce and use a different
|
||||
signature than "AA". This was revoked because ES entries serve the purpose
|
||||
to distinguish AAIP entries from eventual "AA" entries of any other extension.
|
||||
Regrettably no reader (kernel) was found which neatly interprets ES. Many do
|
||||
not even recognize the RRIP-1.12 ER signatures "IEEE_P1282", "IEEE_1282".
|
||||
|
||||
AAIP 0.2 defined two ACL types which did not make it into AAIP 1.0
|
||||
2 ACL_USER of arbitrary user, with name as qualifier
|
||||
4 ACL_GROUP of arbitrary group, with name as qualifier
|
||||
Their job was transferred to ACL_USER_N and ACL_GROUP_N which have numeric
|
||||
qualifiers.
|
||||
|
||||
AAIP-0.0
|
||||
|
||||
There was a draft AAIP 0.0 with ER signature "AAIP_2008A". It did not resemble
|
||||
the existing entry SL and was never implemented.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
References:
|
||||
|
||||
ECMA-119 aka ISO 9660
|
||||
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
|
||||
|
||||
SUSP 1.12 (entries CE , PD , SP , ST , ER , ES)
|
||||
ftp://ftp.ymi.com/pub/rockridge/susp112.ps
|
||||
|
||||
RRIP 1.12 (entries PX , PN , SL , NM , CL , PL , RE , TF , SF , obsolete: RR)
|
||||
ftp://ftp.ymi.com/pub/rockridge/rrip112.ps
|
||||
|
||||
Apple ISO 9660 Extensions (entries AA and BA)
|
||||
http://developer.apple.com/technotes/fl/fl_36.html
|
||||
|
||||
Amiga AS entry
|
||||
http://www.estamos.de/makecd/Rock_Ridge_Amiga_Specific
|
||||
|
||||
zisofs entry ZF (prepared by zisofs-tools, written by mkisofs)
|
||||
http://freshmeat.net/projects/zisofs-tools/
|
||||
|
||||
Program mkisofs emits entry XA
|
||||
ftp://ftp.berlios.de/pub/cdrecord/alpha
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
85
doc/susp_aaip_isofs_names.txt
Normal file
85
doc/susp_aaip_isofs_names.txt
Normal file
@ -0,0 +1,85 @@
|
||||
Arbitrary Attribute Interchange Protocol
|
||||
Interchange of Persistent File Attributes
|
||||
|
||||
Directory of Namespace "isofs."
|
||||
|
||||
by Thomas Schmitt - mailto:scdbackup@gmx.net
|
||||
Libburnia project - mailto:libburn-hackers@pykix.org
|
||||
|
||||
|
||||
The following names are defined for AAIP namespace "isofs." as mentioned in
|
||||
specification of AAIP :
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name:
|
||||
isofs.di
|
||||
|
||||
Purpose:
|
||||
Records .st_dev and .st_ino of struct stat of the file source in the
|
||||
local filesystem. See man 2 stat.
|
||||
|
||||
Format of Value:
|
||||
DEV_LEN | DEV_BYTES | INO_LEN | INO_BYTES
|
||||
The _LEN fields comply to ISO 9660 Format section 7.1.1.
|
||||
The byte strings begin with the most significant byte.
|
||||
|
||||
Example:
|
||||
Device number 2001, inode number 176343
|
||||
{ 2, 7, 209,
|
||||
3, 2, 176, 215 }
|
||||
|
||||
Registered:
|
||||
17 Feb 2009 by Thomas Schmitt for xorriso.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name:
|
||||
isofs.cs
|
||||
|
||||
Purpose:
|
||||
Records the name of the character set that was used as output character
|
||||
set when writing the RRIP name tree of the ISO 9660 image. It shall be
|
||||
suitable as parameter for function iconv_open(3).
|
||||
This attribute shall eventually be attached to the root directory entry
|
||||
and be global for the whole image.
|
||||
|
||||
Format of Value:
|
||||
Shall hold the character set name without terminating 0-byte.
|
||||
|
||||
Example:
|
||||
{ 'I', 'S', 'O', '-', '8', '8', '5', '9' , '-', '1' }
|
||||
|
||||
Registered:
|
||||
18 Mar 2009 by Thomas Schmitt for libisofs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name:
|
||||
isofs.st
|
||||
|
||||
Purpose:
|
||||
Records a time point at least 1 second before any nodes were added to a
|
||||
freshly loaded or created ISO image. Nodes in the image which have
|
||||
younger timestamps are suspect to have changed their content during
|
||||
image production and might bear inconsistent content.
|
||||
The RRIP timestamps have a blind second during which a change after
|
||||
node registration would not be recognizable for incremental backups
|
||||
which are based in "isofs.di" rather than on content comparison.
|
||||
This attribute shall eventually be attached to the root directory entry
|
||||
and be global for the whole image.
|
||||
|
||||
Format of Value:
|
||||
Shall hold UTC seconds since 1970 as decimal number string without
|
||||
terminating 0-byte.
|
||||
|
||||
Example:
|
||||
{ '1', '2', '3', '8', '7', '4', '2', '2', '9', '6' }
|
||||
|
||||
Registered:
|
||||
03 Apr 2009 by Thomas Schmitt for xorriso.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
|
143
doc/zisofs_format.txt
Normal file
143
doc/zisofs_format.txt
Normal file
@ -0,0 +1,143 @@
|
||||
|
||||
Description of the zisofs Format
|
||||
|
||||
as of zisofs-tools-1.0.8 by H. Peter Anvin
|
||||
and cdrtools-2.01.01a39 by Joerg Schilling
|
||||
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
- distribute freely , please report any errors or ambiguities -
|
||||
|
||||
Apr 11 2009
|
||||
|
||||
|
||||
The zisofs format was invented by H. Peter Anvin. It compresses data file
|
||||
content, marks it by a header and provides a pointer array for coarse random
|
||||
access. Within a RRIP enhanced ISO 9660 image the format is additionally marked
|
||||
by a System Use entry with signature "ZF".
|
||||
|
||||
The uncompressed size of a single zisofs compressed file is restricted
|
||||
to 4 GiB - 1. Larger files shall not be compressed.
|
||||
|
||||
|
||||
File Header
|
||||
|
||||
The file header has this layout (quoted from zisofs-tools-1.0.8/mkzftree.c):
|
||||
Byte offset iso9660 type Contents
|
||||
0 (8 bytes) Magic number (37 E4 53 96 C9 DB D6 07)
|
||||
8 7.3.1 Uncompressed file size
|
||||
12 7.1.1 header_size >> 2 (currently 4)
|
||||
13 7.1.1 log2(block_size)
|
||||
14 (2 bytes) Reserved, must be zero
|
||||
So its size is 16.
|
||||
7.3.1 means little endian 4-byte words. 7.1.1. means unsigned single bytes.
|
||||
|
||||
Readers shall be able to handle log2(block_size) values 15, 16 and 17
|
||||
i.e. block sizes 32 kB, 64 kB, and 128 kB. Writers must not use other sizes.
|
||||
|
||||
|
||||
Block Pointers
|
||||
|
||||
There are ceil(input_size / block_size) input resp. output blocks.
|
||||
Each input block is of fixed size whereas the output blocks have varying
|
||||
size (down to 0). For each output block there is an offset pointer giving
|
||||
its byte address in the overall file content. The next block pointer in the
|
||||
array tells the start of the next block which begins immediately after the
|
||||
end of its predecessor. A final pointer gives the first invalid byte address
|
||||
and thus marks the end of the last block.
|
||||
|
||||
So there are ceil(input_size / block_size) + 1 block pointers.
|
||||
They are stored as an array of 4-byte values which are in ISO 9660:7.3.1 format
|
||||
directly after the file header, i.e. beginning at byte 16.
|
||||
|
||||
|
||||
Data Part
|
||||
|
||||
The data part begins immediately after the pointer array. In principle it
|
||||
consists of the variable length output blocks as delivered by zlib function
|
||||
compress2() when fed with the fixed size input blocks.
|
||||
|
||||
A special case of input and output block is defined:
|
||||
Zero-length blocks represent a block full of 0-bytes.
|
||||
Such input blocks do not get processed by compress2() but shall be mapped to
|
||||
0-sized output directly. Vice versa 0-sized blocks have to bypass uncompress()
|
||||
when being read.
|
||||
|
||||
|
||||
ZF System Use Entry Format
|
||||
|
||||
ZF may only be applied to files with a single extent and less than 4 GiB of
|
||||
uncompressed size.
|
||||
|
||||
The ZF entry follows the general layout of SUSP resp. RRIP.
|
||||
Its fields are:
|
||||
|
||||
[1] "BP 1 to BP 2 - Signature Word" shall be (5A)(46) ("ZF").
|
||||
|
||||
[2] "BP 3 - Length" shall specify as an 8-bit number the length in bytes of
|
||||
the ZF entry recorded according to ISO 9660:7.1.1.
|
||||
This length is 16 decimal.
|
||||
|
||||
[3] "BP 4 - System Use Entry Version" shall be 1 as in ISO 9660:7.1.1.
|
||||
|
||||
[4] "BP 5 to BP 6 - Algorithm" shall be (70)(7A) ("pz") to indicate
|
||||
"paged zlib".
|
||||
|
||||
[5] "BP 7 - Header Size Div 4" shall specify as an 8-bit number the number of
|
||||
4-byte words in the header part of the file data recorded according
|
||||
to ISO 9660:7.1.1.
|
||||
(This is a copy of header byte 12, resp. header BP 13).
|
||||
|
||||
[6] "BP 8 - Log2 of Block Size" shall specify as an 8-bit number the binary
|
||||
logarithm of the compression block size recorded according to
|
||||
ISO 9660:7.1.1.
|
||||
(This is a copy of header byte 13, resp. header BP 14.
|
||||
The value has to be 15, 16 or 17 i.e. 32 kiB, 64 kiB, or 128 kiB.)
|
||||
|
||||
[7] "BP 9 to BP 16 - Uncompressed Size" shall tell the number of uncompressed
|
||||
bytes represented by the given extent. This field shall be recorded
|
||||
according to ISO 9660:7.3.3.
|
||||
(This number is the same as in header bytes 8 to 11, resp header BP 9
|
||||
to BP 12.)
|
||||
|
||||
| 'Z' | 'F' | LENGTH | 1 | 'p' | 'z' | HEADER SIZE DIV 4 | LOG2 BLOCK SIZE
|
||||
| UNCOMPRESSED SIZE |
|
||||
|
||||
ISO 9660:7.3.3 means 4-byte word in both byte orders, first little endian, then
|
||||
big endian.
|
||||
Example (block size 32 kiB, uncompressed file size = 1,234,567 bytes):
|
||||
{ 'Z', "F', 16, 1, 'p', 'z', 4, 15,
|
||||
0x87, 0xD6, 0x12, 0x00, 0x00, 0x12, 0xD6, 0x87 }
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Revoked specification aspects:
|
||||
|
||||
A comment in zisofs-tools-1.0.8 indicates a special case of output block:
|
||||
"a block the length of which is equal to the block size is unencoded."
|
||||
This is not implemented in zisofs-tools and in the Linux kernel. Existing
|
||||
zisofs enhanced ISO images might contain encoded blocks which could be
|
||||
mistaken for unencoded blocks.
|
||||
Therefore this rule is not part of this description and must not be
|
||||
implemented.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
References:
|
||||
|
||||
zisofs-tools
|
||||
http://freshmeat.net/projects/zisofs-tools/
|
||||
|
||||
zlib:
|
||||
/usr/include/zlib.h
|
||||
|
||||
cdrtools with mkisofs
|
||||
ftp://ftp.berlios.de/pub/cdrecord/alpha
|
||||
|
||||
ECMA-119 aka ISO 9660
|
||||
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
|
||||
|
||||
SUSP 1.12
|
||||
ftp://ftp.ymi.com/pub/rockridge/susp112.ps
|
||||
|
||||
RRIP 1.12
|
||||
ftp://ftp.ymi.com/pub/rockridge/rrip112.ps
|
||||
|
96
libisofs/aaip-os-dummy.c
Normal file
96
libisofs/aaip-os-dummy.c
Normal file
@ -0,0 +1,96 @@
|
||||
|
||||
/*
|
||||
|
||||
aaip-os-dummy.c
|
||||
|
||||
Idle placeholder for:
|
||||
Arbitrary Attribute Interchange Protocol , system adapter for getting and
|
||||
setting of ACLs and xattr.
|
||||
|
||||
See aaip-os-linux.c for a real implementation of this interface.
|
||||
|
||||
To be included by aaip_0_2.c
|
||||
|
||||
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
/* ------------------------------ Getters --------------------------------- */
|
||||
|
||||
/* Obtain the ACL of the given file in long text form.
|
||||
@return 0 ACL support not enabled at compile time
|
||||
*/
|
||||
int aaip_get_acl_text(char *path, char **text, int flag)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
|
||||
that is ready for aaip_encode().
|
||||
@return 1 ok
|
||||
*/
|
||||
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
|
||||
size_t **value_lengths, char ***values, int flag)
|
||||
{
|
||||
*num_attrs= 0;
|
||||
*names= NULL;
|
||||
*value_lengths= NULL;
|
||||
*values= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------ Setters --------------------------------- */
|
||||
|
||||
|
||||
/* Set the ACL of the given file to a given list in long text form.
|
||||
@return 0 ACL support not enabled at compile time
|
||||
*/
|
||||
int aaip_set_acl_text(char *path, char *text, int flag)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* Bring the given attributes and/or ACLs into effect with the given file.
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= decode and set ACLs
|
||||
bit1= first clear all existing attributes of the file
|
||||
bit2= do not set attributes other than ACLs
|
||||
@return 1 success (there was nothing to do)
|
||||
-6 support of xattr not enabled at compile time
|
||||
-7 support of ACL not enabled at compile time
|
||||
*/
|
||||
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
|
||||
size_t *value_lengths, char **values, int flag)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i= 0; i < num_attrs; i++) {
|
||||
if(names[i] == NULL || values[i] == NULL)
|
||||
continue;
|
||||
if(names[i][0] == 0) { /* ACLs */
|
||||
if(flag & 1)
|
||||
return(-7);
|
||||
continue;
|
||||
}
|
||||
/* Extended Attribute */
|
||||
if(!(flag & 4))
|
||||
return(-6);
|
||||
}
|
||||
if(flag & 2)
|
||||
return(-6);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
382
libisofs/aaip-os-freebsd.c
Normal file
382
libisofs/aaip-os-freebsd.c
Normal file
@ -0,0 +1,382 @@
|
||||
|
||||
/*
|
||||
|
||||
aaip-os-freebsd.c
|
||||
Arbitrary Attribute Interchange Protocol , system adapter for getting and
|
||||
setting of ACLs and ixattr.
|
||||
|
||||
To be included by aaip_0_2.c
|
||||
|
||||
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef Libisofs_with_aaip_acL
|
||||
/* It seems ACL is fixely integrated in FreeBSD libc. There is no libacl. */
|
||||
#define Libisofs_with_aaip_acL yes
|
||||
#endif
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
#include <sys/acl.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* ------------------------------ Getters --------------------------------- */
|
||||
|
||||
/* Obtain the ACL of the given file in long text form.
|
||||
@param path Path to the file
|
||||
@param text Will hold the result. This is a managed object which
|
||||
finally has to be freed by a call to this function
|
||||
with bit15 of flag.
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= obtain default ACL rather than access ACL
|
||||
bit4= set *text = NULL and return 2
|
||||
if the ACL matches st_mode permissions.
|
||||
bit5= in case of symbolic link: inquire link target
|
||||
bit15= free text and return 1
|
||||
@return > 0 ok
|
||||
0 ACL support not enabled at compile time
|
||||
-1 failure of system ACL service (see errno)
|
||||
-2 attempt to inquire ACL of a symbolic
|
||||
link without bit4 or bit5
|
||||
*/
|
||||
int aaip_get_acl_text(char *path, char **text, int flag)
|
||||
{
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
acl_t acl= NULL;
|
||||
#endif
|
||||
struct stat stbuf;
|
||||
int ret;
|
||||
|
||||
if(flag & (1 << 15)) {
|
||||
if(*text != NULL)
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
acl_free(*text);
|
||||
#else
|
||||
free(*text);
|
||||
#endif
|
||||
*text= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
*text= NULL;
|
||||
if(flag & 32)
|
||||
ret= stat(path, &stbuf);
|
||||
else
|
||||
ret= lstat(path, &stbuf);
|
||||
if(ret == -1)
|
||||
return(-1);
|
||||
if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
|
||||
if(flag & 16)
|
||||
return(2);
|
||||
return(-2);
|
||||
}
|
||||
|
||||
/* Note: no ACL_TYPE_DEFAULT in FreeBSD */
|
||||
if(flag & 1)
|
||||
return(0);
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
|
||||
acl= acl_get_file(path, ACL_TYPE_ACCESS);
|
||||
|
||||
if(acl == NULL)
|
||||
return(-1);
|
||||
*text= acl_to_text(acl, NULL);
|
||||
acl_free(acl);
|
||||
|
||||
#else /* Libisofs_with_aaip_acL */
|
||||
|
||||
/* ??? >>> Fake ACL */;
|
||||
|
||||
return(0);
|
||||
|
||||
#endif /* ! Libisofs_with_aaip_acL */
|
||||
|
||||
if(*text == NULL)
|
||||
return(-1);
|
||||
if(flag & 16) {
|
||||
ret = aaip_cleanout_st_mode(*text, &(stbuf.st_mode), 2);
|
||||
if(!(ret & (7 | 64)))
|
||||
(*text)[0]= 0;
|
||||
if((*text)[0] == 0 || strcmp(*text, "\n") == 0) {
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
acl_free(*text);
|
||||
#else
|
||||
free(*text);
|
||||
#endif
|
||||
*text= NULL;
|
||||
return(2);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
|
||||
that is ready for aaip_encode().
|
||||
|
||||
Note: There are no Extended Attributes in FreeBSD. So only ACL will be
|
||||
obtained.
|
||||
|
||||
@param path Path to the file
|
||||
@param num_attrs Will return the number of name-value pairs
|
||||
@param names Will return an array of pointers to 0-terminated names
|
||||
@param value_lengths Will return an arry with the lenghts of values
|
||||
@param values Will return an array of pointers to 8-bit values
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= obtain ACL (access and eventually default)
|
||||
bit1= use numeric ACL qualifiers rather than names
|
||||
bit2= do not encode attributes other than ACL
|
||||
bit3= -reserved-
|
||||
bit4= do not return trivial ACL that matches st_mode
|
||||
bit15= free memory of names, value_lengths, values
|
||||
@return >0 ok
|
||||
<=0 error
|
||||
*/
|
||||
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
|
||||
size_t **value_lengths, char ***values, int flag)
|
||||
{
|
||||
int ret;
|
||||
ssize_t i, num_names;
|
||||
size_t a_acl_len= 0, acl_len= 0;
|
||||
unsigned char *a_acl= NULL, *d_acl= NULL, *acl= NULL;
|
||||
char *acl_text= NULL;
|
||||
|
||||
if(flag & (1 << 15)) { /* Free memory */
|
||||
{ret= 1; goto ex;}
|
||||
}
|
||||
|
||||
*num_attrs= 0;
|
||||
*names= NULL;
|
||||
*value_lengths= NULL;
|
||||
*values= NULL;
|
||||
|
||||
num_names= 0;
|
||||
if(flag & 1)
|
||||
num_names++;
|
||||
if(num_names == 0)
|
||||
{ret= 1; goto ex;}
|
||||
(*names)= calloc(num_names, sizeof(char *));
|
||||
(*value_lengths)= calloc(num_names, sizeof(size_t));
|
||||
(*values)= calloc(num_names, sizeof(char *));
|
||||
if(*names == NULL || *value_lengths == NULL || *values == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
|
||||
for(i= 0; i < num_names; i++) {
|
||||
(*names)[i]= NULL;
|
||||
(*values)[i]= NULL;
|
||||
(*value_lengths)[i]= 0;
|
||||
}
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
|
||||
if(flag & 1) { /* Obtain ACL */
|
||||
/* access-ACL */
|
||||
ret= aaip_get_acl_text(path, &acl_text, flag & (16 | 32));
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
if(ret == 2)
|
||||
{ret= 1; goto ex;} /* empty ACL / only st_mode info was found in ACL */
|
||||
ret= aaip_encode_acl(acl_text, (mode_t) 0, &a_acl_len, &a_acl, flag & 2);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
aaip_get_acl_text("", &acl_text, 1 << 15); /* free */
|
||||
|
||||
/* Note: There are no default-ACL in FreeBSD */
|
||||
|
||||
/* Set as attribute with empty name */;
|
||||
(*names)[*num_attrs]= strdup("");
|
||||
if((*names)[*num_attrs] == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
(*values)[*num_attrs]= (char *) acl;
|
||||
(*value_lengths)[*num_attrs]= acl_len;
|
||||
(*num_attrs)++;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_with_aaip_acL */
|
||||
|
||||
ret= 1;
|
||||
ex:;
|
||||
if(a_acl != NULL)
|
||||
free(a_acl);
|
||||
if(d_acl != NULL)
|
||||
free(d_acl);
|
||||
if(acl_text != NULL)
|
||||
aaip_get_acl_text("", &acl_text, 1 << 15); /* free */
|
||||
|
||||
if(ret <= 0 || (flag & (1 << 15))) {
|
||||
if(*names != NULL) {
|
||||
for(i= 0; i < *num_attrs; i++)
|
||||
free((*names)[i]);
|
||||
free(*names);
|
||||
}
|
||||
*names= NULL;
|
||||
if(*value_lengths != NULL)
|
||||
free(*value_lengths);
|
||||
*value_lengths= NULL;
|
||||
if(*values != NULL) {
|
||||
for(i= 0; i < *num_attrs; i++)
|
||||
free((*values)[i]);
|
||||
free(*values);
|
||||
}
|
||||
if(acl != NULL)
|
||||
free(acl);
|
||||
*values= NULL;
|
||||
*num_attrs= 0;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------ Setters --------------------------------- */
|
||||
|
||||
|
||||
/* Set the ACL of the given file to a given list in long text form.
|
||||
@param path Path to the file
|
||||
@param text The input text (0 terminated, ACL long text form)
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= set default ACL rather than access ACL
|
||||
@return > 0 ok
|
||||
-1 failure of system ACL service (see errno)
|
||||
-2 ACL support not enabled at compile time
|
||||
*/
|
||||
int aaip_set_acl_text(char *path, char *text, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
|
||||
int ret;
|
||||
acl_t acl= NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if(flag & 32)
|
||||
ret= stat(path, &stbuf);
|
||||
else
|
||||
ret= lstat(path, &stbuf);
|
||||
if(ret == -1)
|
||||
return(-1);
|
||||
if((stbuf.st_mode & S_IFMT) == S_IFLNK)
|
||||
return(-2);
|
||||
|
||||
acl= acl_from_text(text);
|
||||
if(acl == NULL) {
|
||||
ret= -1; goto ex;
|
||||
}
|
||||
|
||||
/* Note: no ACL_TYPE_DEFAULT in FreeBSD */
|
||||
if(flag & 1)
|
||||
{ret= 0; goto ex;}
|
||||
|
||||
ret= acl_set_file(path, ACL_TYPE_ACCESS, acl);
|
||||
|
||||
if(ret == -1)
|
||||
goto ex;
|
||||
ret= 1;
|
||||
ex:
|
||||
if(acl != NULL)
|
||||
acl_free(acl);
|
||||
return(ret);
|
||||
|
||||
#else /* Libisofs_with_aaip_acL */
|
||||
|
||||
return(-2);
|
||||
|
||||
#endif /* ! Libisofs_with_aaip_acL */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Bring the given attributes and/or ACLs into effect with the given file.
|
||||
|
||||
Note: There are no Extended Attributes in FreeBSD. So only ACL get set.
|
||||
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= decode and set ACLs
|
||||
( bit1= first clear all existing attributes of the file )
|
||||
( bit2= do not set attributes other than ACLs )
|
||||
@return 1 success
|
||||
-1 error memory allocation
|
||||
-2 error with decoding of ACL
|
||||
-3 error with setting ACL
|
||||
( -4 error with setting attribute )
|
||||
( -5 error with deleting attribute )
|
||||
-6 support of xattr not enabled at compile time
|
||||
-7 support of ACL not enabled at compile time
|
||||
*/
|
||||
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
|
||||
size_t *value_lengths, char **values, int flag)
|
||||
{
|
||||
int ret, has_default_acl= 0, was_xattr= 0;
|
||||
size_t i, consumed, acl_text_fill;
|
||||
char *acl_text= NULL, *list= NULL;
|
||||
|
||||
for(i= 0; i < num_attrs; i++) {
|
||||
if(names[i] == NULL || values[i] == NULL)
|
||||
continue;
|
||||
if(names[i][0] == 0) { /* Decode ACLs */
|
||||
/* access ACL */
|
||||
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
|
||||
&consumed, NULL, 0, &acl_text_fill, 1);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
acl_text= calloc(acl_text_fill, 1);
|
||||
if(acl_text == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
|
||||
&consumed, acl_text, acl_text_fill, &acl_text_fill, 0);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
has_default_acl= (ret == 2);
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
ret= aaip_set_acl_text(path, acl_text, flag & 32);
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
#else
|
||||
{ret= -7; goto ex;}
|
||||
#endif
|
||||
/* "default" ACL */
|
||||
if(has_default_acl) {
|
||||
free(acl_text);
|
||||
acl_text= NULL;
|
||||
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
|
||||
value_lengths[i] - consumed, &consumed,
|
||||
NULL, 0, &acl_text_fill, 1);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
acl_text= calloc(acl_text_fill, 1);
|
||||
if(acl_text == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
|
||||
value_lengths[i] - consumed, &consumed,
|
||||
acl_text, acl_text_fill, &acl_text_fill, 0);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
ret= aaip_set_acl_text(path, acl_text, 1 | (flag & 32));
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
}
|
||||
} else
|
||||
was_xattr= 1;
|
||||
}
|
||||
ret= 1;
|
||||
if(was_xattr)
|
||||
ret= -6;
|
||||
ex:;
|
||||
if(acl_text != NULL)
|
||||
free(acl_text);
|
||||
if(list != NULL)
|
||||
free(list);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
500
libisofs/aaip-os-linux.c
Normal file
500
libisofs/aaip-os-linux.c
Normal file
@ -0,0 +1,500 @@
|
||||
|
||||
/*
|
||||
|
||||
aaip-os-linux.c
|
||||
Arbitrary Attribute Interchange Protocol , system adapter for getting and
|
||||
setting of ACLs and xattr.
|
||||
|
||||
To be included by aaip_0_2.c
|
||||
|
||||
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
#include <sys/acl.h>
|
||||
#endif
|
||||
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
#include <attr/xattr.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* ------------------------------ Getters --------------------------------- */
|
||||
|
||||
/* Obtain the ACL of the given file in long text form.
|
||||
@param path Path to the file
|
||||
@param text Will hold the result. This is a managed object which
|
||||
finally has to be freed by a call to this function
|
||||
with bit15 of flag.
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= obtain default ACL rather than access ACL
|
||||
behave like bit4 if ACL is empty
|
||||
bit4= set *text = NULL and return 2
|
||||
if the ACL matches st_mode permissions.
|
||||
bit5= in case of symbolic link: inquire link target
|
||||
bit15= free text and return 1
|
||||
@return 1 ok
|
||||
2 only st_mode permissions exist and bit 4 is set
|
||||
or empty ACL and bit0 is set
|
||||
0 ACL support not enabled at compile time
|
||||
-1 failure of system ACL service (see errno)
|
||||
-2 attempt to inquire ACL of a symbolic link without
|
||||
bit4 or bit5 resp. with no suitable link target
|
||||
*/
|
||||
int aaip_get_acl_text(char *path, char **text, int flag)
|
||||
{
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
|
||||
acl_t acl= NULL;
|
||||
struct stat stbuf;
|
||||
int ret;
|
||||
|
||||
if(flag & (1 << 15)) {
|
||||
if(*text != NULL)
|
||||
acl_free(*text);
|
||||
*text= NULL;
|
||||
return(1);
|
||||
}
|
||||
*text= NULL;
|
||||
|
||||
if(flag & 32)
|
||||
ret= stat(path, &stbuf);
|
||||
else
|
||||
ret= lstat(path, &stbuf);
|
||||
if(ret == -1)
|
||||
return(-1);
|
||||
if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
|
||||
if(flag & 16)
|
||||
return(2);
|
||||
return(-2);
|
||||
}
|
||||
|
||||
acl= acl_get_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS);
|
||||
if(acl == NULL)
|
||||
return(-1);
|
||||
*text= acl_to_text(acl, NULL);
|
||||
acl_free(acl);
|
||||
|
||||
if(*text == NULL)
|
||||
return(-1);
|
||||
if(flag & 16) {
|
||||
ret = aaip_cleanout_st_mode(*text, &(stbuf.st_mode), 2);
|
||||
if(!(ret & (7 | 64)))
|
||||
(*text)[0]= 0;
|
||||
}
|
||||
if(flag & (1 | 16)) {
|
||||
if((*text)[0] == 0 || strcmp(*text, "\n") == 0) {
|
||||
acl_free(*text);
|
||||
*text= NULL;
|
||||
return(2);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
|
||||
#else /* Libisofs_with_aaip_acL */
|
||||
|
||||
return(0);
|
||||
|
||||
#endif /* ! Libisofs_with_aaip_acL */
|
||||
}
|
||||
|
||||
|
||||
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
|
||||
that is ready for aaip_encode().
|
||||
@param path Path to the file
|
||||
@param num_attrs Will return the number of name-value pairs
|
||||
@param names Will return an array of pointers to 0-terminated names
|
||||
@param value_lengths Will return an arry with the lenghts of values
|
||||
@param values Will return an array of pointers to 8-bit values
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= obtain ACL (access and eventually default)
|
||||
bit1= use numeric ACL qualifiers rather than names
|
||||
bit2= do not obtain attributes other than ACL
|
||||
bit3= do not ignore eventual non-user attributes
|
||||
I.e. those with a name which does not begin
|
||||
by "user."
|
||||
bit4= do not return trivial ACL that matches st_mode
|
||||
bit5= in case of symbolic link: inquire link target
|
||||
bit15= free memory of names, value_lengths, values
|
||||
@return >0 ok
|
||||
<=0 error
|
||||
*/
|
||||
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
|
||||
size_t **value_lengths, char ***values, int flag)
|
||||
{
|
||||
int ret, retry= 0;
|
||||
char *list= NULL;
|
||||
ssize_t list_size= 0, i, num_names= 0, value_ret;
|
||||
size_t acl_len= 0;
|
||||
unsigned char *acl= NULL;
|
||||
char *a_acl_text= NULL, *d_acl_text= NULL;
|
||||
|
||||
if(flag & (1 << 15)) { /* Free memory */
|
||||
{ret= 1; goto ex;}
|
||||
}
|
||||
|
||||
*num_attrs= 0;
|
||||
*names= NULL;
|
||||
*value_lengths= NULL;
|
||||
*values= NULL;
|
||||
|
||||
/* Set up arrays */
|
||||
if(!(flag & 4)) { /* Get xattr names */
|
||||
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
|
||||
if(flag & 32)
|
||||
list_size= listxattr(path, list, 0);
|
||||
else
|
||||
list_size= llistxattr(path, list, 0);
|
||||
if(list_size == -1)
|
||||
{ret= -1; goto ex;}
|
||||
list= calloc(list_size, 1);
|
||||
if(list == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
if(flag & 32)
|
||||
list_size= listxattr(path, list, list_size);
|
||||
else
|
||||
list_size= llistxattr(path, list, list_size);
|
||||
if(list_size == -1)
|
||||
{ret= -1; goto ex;}
|
||||
|
||||
#else /* Libisofs_with_aaip_xattR */
|
||||
|
||||
list= strdup("");
|
||||
|
||||
#endif /* ! Libisofs_with_aaip_xattR */
|
||||
|
||||
for(i= 0; i < list_size; i+= strlen(list + i) + 1)
|
||||
num_names++;
|
||||
}
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
if(flag & 1)
|
||||
num_names++;
|
||||
#endif
|
||||
|
||||
if(num_names == 0)
|
||||
{ret= 1; goto ex;}
|
||||
(*names)= calloc(num_names, sizeof(char *));
|
||||
(*value_lengths)= calloc(num_names, sizeof(size_t));
|
||||
(*values)= calloc(num_names, sizeof(char *));
|
||||
if(*names == NULL || *value_lengths == NULL || *values == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
|
||||
for(i= 0; i < num_names; i++) {
|
||||
(*names)[i]= NULL;
|
||||
(*values)[i]= NULL;
|
||||
(*value_lengths)[i]= 0;
|
||||
}
|
||||
if(!(flag & 4)) {
|
||||
for(i= 0; i < list_size && num_names > *num_attrs;
|
||||
i+= strlen(list + i) + 1) {
|
||||
if(!(flag & 8))
|
||||
if(strncmp(list + i, "user.", 5))
|
||||
continue;
|
||||
(*names)[(*num_attrs)++]= strdup(list + i);
|
||||
if((*names)[(*num_attrs) - 1] == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
|
||||
if(!(flag & 4)) { /* Get xattr values */
|
||||
for(i= 0; i < *num_attrs; i++) {
|
||||
if(!(flag & 8))
|
||||
if(strncmp((*names)[i], "user.", 5))
|
||||
continue;
|
||||
if(flag & 32)
|
||||
value_ret= getxattr(path, (*names)[i], NULL, 0);
|
||||
else
|
||||
value_ret= lgetxattr(path, (*names)[i], NULL, 0);
|
||||
if(value_ret == -1)
|
||||
continue;
|
||||
(*values)[i]= calloc(value_ret + 1, 1);
|
||||
if((*values)[i] == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
if(flag & 32)
|
||||
value_ret= getxattr(path, (*names)[i], (*values)[i], value_ret);
|
||||
else
|
||||
value_ret= lgetxattr(path, (*names)[i], (*values)[i], value_ret);
|
||||
if(value_ret == -1) { /* there could be a race condition */
|
||||
if(retry++ > 5)
|
||||
{ret= -1; goto ex;}
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
(*value_lengths)[i]= value_ret;
|
||||
retry= 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Libisofs_with_aaip_xattR */
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
|
||||
if(flag & 1) { /* Obtain ACL */
|
||||
|
||||
aaip_get_acl_text(path, &a_acl_text, flag & (16 | 32));
|
||||
aaip_get_acl_text(path, &d_acl_text, 1 | (flag & 32));
|
||||
if(a_acl_text == NULL && d_acl_text == NULL)
|
||||
{ret= 1; goto ex;}
|
||||
ret= aaip_encode_both_acl(a_acl_text, d_acl_text, (mode_t) 0,
|
||||
&acl_len, &acl, (flag & 2));
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
|
||||
/* Set as attribute with empty name */;
|
||||
(*names)[*num_attrs]= strdup("");
|
||||
if((*names)[*num_attrs] == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
(*values)[*num_attrs]= (char *) acl;
|
||||
acl= NULL;
|
||||
(*value_lengths)[*num_attrs]= acl_len;
|
||||
(*num_attrs)++;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_with_aaip_acL */
|
||||
|
||||
ret= 1;
|
||||
ex:;
|
||||
if(a_acl_text != NULL)
|
||||
aaip_get_acl_text("", &a_acl_text, 1 << 15); /* free */
|
||||
if(d_acl_text != NULL)
|
||||
aaip_get_acl_text("", &d_acl_text, 1 << 15); /* free */
|
||||
if(ret <= 0 || (flag & (1 << 15))) {
|
||||
if(list != NULL)
|
||||
free(list);
|
||||
if(*names != NULL) {
|
||||
for(i= 0; i < *num_attrs; i++)
|
||||
free((*names)[i]);
|
||||
free(*names);
|
||||
}
|
||||
*names= NULL;
|
||||
if(*value_lengths != NULL)
|
||||
free(*value_lengths);
|
||||
*value_lengths= NULL;
|
||||
if(*values != NULL) {
|
||||
for(i= 0; i < *num_attrs; i++)
|
||||
free((*values)[i]);
|
||||
free(*values);
|
||||
}
|
||||
if(acl != NULL)
|
||||
free(acl);
|
||||
*values= NULL;
|
||||
*num_attrs= 0;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------ Setters --------------------------------- */
|
||||
|
||||
|
||||
/* Set the ACL of the given file to a given list in long text form.
|
||||
@param path Path to the file
|
||||
@param text The input text (0 terminated, ACL long text form)
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= set default ACL rather than access ACL
|
||||
bit5= in case of symbolic link: manipulate link target
|
||||
@return >0 ok
|
||||
0 ACL support not enabled at compile time
|
||||
-1 failure of system ACL service (see errno)
|
||||
-2 attempt to manipulate ACL of a symbolic link
|
||||
without bit5 resp. with no suitable link target
|
||||
*/
|
||||
int aaip_set_acl_text(char *path, char *text, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
|
||||
int ret;
|
||||
acl_t acl= NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if(flag & 32)
|
||||
ret= stat(path, &stbuf);
|
||||
else
|
||||
ret= lstat(path, &stbuf);
|
||||
if(ret == -1)
|
||||
return(-1);
|
||||
if((stbuf.st_mode & S_IFMT) == S_IFLNK)
|
||||
return(-2);
|
||||
|
||||
acl= acl_from_text(text);
|
||||
if(acl == NULL) {
|
||||
ret= -1; goto ex;
|
||||
}
|
||||
ret= acl_set_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS, acl);
|
||||
if(ret == -1)
|
||||
goto ex;
|
||||
ret= 1;
|
||||
ex:
|
||||
if(acl != NULL)
|
||||
acl_free(acl);
|
||||
return(ret);
|
||||
|
||||
#else /* Libisofs_with_aaip_acL */
|
||||
|
||||
return(0);
|
||||
|
||||
#endif /* ! Libisofs_with_aaip_acL */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Bring the given attributes and/or ACLs into effect with the given file.
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= decode and set ACLs
|
||||
bit1= first clear all existing attributes of the file
|
||||
bit2= do not set attributes other than ACLs
|
||||
bit3= do not ignore eventual non-user attributes.
|
||||
I.e. those with a name which does not begin
|
||||
by "user."
|
||||
bit5= in case of symbolic link: manipulate link target
|
||||
@return 1 success
|
||||
-1 error memory allocation
|
||||
-2 error with decoding of ACL
|
||||
-3 error with setting ACL
|
||||
-4 error with setting attribute
|
||||
-5 error with deleting attributes
|
||||
-6 support of xattr not enabled at compile time
|
||||
-7 support of ACL not enabled at compile time
|
||||
*/
|
||||
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
|
||||
size_t *value_lengths, char **values, int flag)
|
||||
{
|
||||
int ret, has_default_acl= 0;
|
||||
size_t i, consumed, acl_text_fill, list_size= 0, acl_idx= 0, h_consumed;
|
||||
char *acl_text= NULL, *list= NULL;
|
||||
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
|
||||
if(flag & 2) { /* Delete all file attributes */
|
||||
if(flag & 32)
|
||||
list_size= listxattr(path, list, 0);
|
||||
else
|
||||
list_size= llistxattr(path, list, 0);
|
||||
}
|
||||
if(list_size > 0) { /* Delete all file attributes */
|
||||
list= calloc(list_size, 1);
|
||||
if(list == NULL)
|
||||
{ret= -5; goto ex;}
|
||||
if(flag & 32)
|
||||
list_size= listxattr(path, list, list_size);
|
||||
else
|
||||
list_size= llistxattr(path, list, list_size);
|
||||
if(list_size == -1)
|
||||
{ret= -5; goto ex;}
|
||||
for(i= 0; i < list_size; i+= strlen(list + i) + 1) {
|
||||
if(!(flag & 8))
|
||||
if(strncmp(list + i, "user.", 5))
|
||||
continue;
|
||||
if(flag & 32)
|
||||
ret= removexattr(path, list + i);
|
||||
else
|
||||
ret= lremovexattr(path, list + i);
|
||||
if(ret == -1)
|
||||
{ret= -5; goto ex;}
|
||||
}
|
||||
free(list); list= NULL;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_with_aaip_xattR */
|
||||
|
||||
for(i= 0; i < num_attrs; i++) {
|
||||
if(names[i] == NULL || values[i] == NULL)
|
||||
continue;
|
||||
if(names[i][0] == 0) { /* ACLs */
|
||||
if(flag & 1)
|
||||
acl_idx= i + 1;
|
||||
continue;
|
||||
}
|
||||
/* Extended Attribute */
|
||||
if((flag & 1) && !(flag & 8))
|
||||
if(strncmp(names[i], "user.", 5))
|
||||
continue;
|
||||
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
|
||||
if(flag & 32)
|
||||
ret= setxattr(path, names[i], values[i], value_lengths[i], 0);
|
||||
else
|
||||
ret= lsetxattr(path, names[i], values[i], value_lengths[i], 0);
|
||||
if(ret == -1)
|
||||
{ret= -4; goto ex;}
|
||||
|
||||
#else
|
||||
|
||||
{ret= -6; goto ex;}
|
||||
|
||||
#endif /* Libisofs_with_aaip_xattR */
|
||||
|
||||
}
|
||||
|
||||
/* Decode ACLs */
|
||||
if(acl_idx == 0)
|
||||
{ret= 1; goto ex;}
|
||||
i= acl_idx - 1;
|
||||
/* "access" ACL */
|
||||
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
|
||||
&consumed, NULL, 0, &acl_text_fill, 1);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
acl_text= calloc(acl_text_fill, 1);
|
||||
if(acl_text == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
|
||||
&consumed, acl_text, acl_text_fill, &acl_text_fill, 0);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
has_default_acl= (ret == 2);
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
ret= aaip_set_acl_text(path, acl_text, flag & 32);
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
#else
|
||||
{ret= -7; goto ex;}
|
||||
#endif
|
||||
/* "default" ACL */
|
||||
if(has_default_acl) {
|
||||
free(acl_text);
|
||||
acl_text= NULL;
|
||||
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
|
||||
value_lengths[i] - consumed, &h_consumed,
|
||||
NULL, 0, &acl_text_fill, 1);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
acl_text= calloc(acl_text_fill, 1);
|
||||
if(acl_text == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
|
||||
value_lengths[i] - consumed, &h_consumed,
|
||||
acl_text, acl_text_fill, &acl_text_fill, 0);
|
||||
if(ret <= 0)
|
||||
{ret= -2; goto ex;}
|
||||
ret= aaip_set_acl_text(path, acl_text, 1 | (flag & 32));
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
}
|
||||
ret= 1;
|
||||
ex:;
|
||||
if(acl_text != NULL)
|
||||
free(acl_text);
|
||||
if(list != NULL)
|
||||
free(list);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
2138
libisofs/aaip_0_2.c
Normal file
2138
libisofs/aaip_0_2.c
Normal file
File diff suppressed because it is too large
Load Diff
486
libisofs/aaip_0_2.h
Normal file
486
libisofs/aaip_0_2.h
Normal file
@ -0,0 +1,486 @@
|
||||
|
||||
/*
|
||||
|
||||
Arbitrary Attribute Interchange Protocol , AAIP versions 0.2 and 1.0.
|
||||
Implementation for encoding and decoding xattr and ACL.
|
||||
|
||||
See http://libburnia-project.org/wiki/AAIP
|
||||
or doc/susp_aaip_2_0.txt
|
||||
|
||||
test/aaip_0_2.h - Public declarations
|
||||
|
||||
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
|
||||
|
||||
*/
|
||||
|
||||
#ifndef Aaip_h_is_includeD
|
||||
#define Aaip_h_is_includeD yes
|
||||
|
||||
|
||||
/* --------------------------------- Encoder ---------------------------- */
|
||||
|
||||
/* Convert an array of Arbitrary Attributes into a series of AAIP fields.
|
||||
@param num_attrs Number of attributes
|
||||
@param names Array of pointers to 0 terminated name strings
|
||||
@param value_lengths Array of byte lengths for each value
|
||||
@param values Array of pointers to the value bytes
|
||||
@param result_len Number of bytes in the resulting SUSP field string
|
||||
@param result *result will point to the start of the result string.
|
||||
This is malloc() memory which needs to be freed when
|
||||
no longer needed
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= set CONTINUE bit of last AAIP field to 1
|
||||
@return >0 is the number of SUSP fields generated,
|
||||
0 means error
|
||||
*/
|
||||
size_t aaip_encode(size_t num_attrs, char **names,
|
||||
size_t *value_lengths, char **values,
|
||||
size_t *result_len, unsigned char **result, int flag);
|
||||
|
||||
|
||||
/* ------ ACL representation ------ */
|
||||
|
||||
/* Convert an ACL from long text form into the value of an Arbitrary
|
||||
Attribute. According to AAIP this value is to be stored together with
|
||||
an empty name.
|
||||
@param acl_text The ACL in long text form
|
||||
@param st_mode The stat(2) permission bits to be used with flag bit3
|
||||
@param result_len Number of bytes in the resulting value
|
||||
@param result *result will point to the start of the result string.
|
||||
This is malloc() memory which needs to be freed when
|
||||
no longer needed
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= count only
|
||||
bit1= use numeric qualifiers rather than names
|
||||
bit2= this is a default ACL, prepend SWITCH_MARK
|
||||
bit3= check for completeness of list and eventually
|
||||
fill up with entries deduced from st_mode
|
||||
@return >0 means ok
|
||||
0 means error
|
||||
*/
|
||||
int aaip_encode_acl(char *acl_text, mode_t st_mode,
|
||||
size_t *result_len, unsigned char **result, int flag);
|
||||
|
||||
|
||||
/* Convert an "access" and "default" ACL from long text form into the value
|
||||
of an Arbitrary Attribute. According to AAIP this value is to be stored
|
||||
together with an empty name.
|
||||
@param a_acl_text The "access" ACL in long text form.
|
||||
Submit NULL if there is no such ACL to be encoded.
|
||||
@param d_acl_text The "default" ACL in long text form.
|
||||
Submit NULL if there is no such ACL to be encoded.
|
||||
@param st_mode The stat(2) permission bits to be used with flag bit3
|
||||
@param result_len Number of bytes in the resulting value
|
||||
@param result *result will point to the start of the result string.
|
||||
This is malloc() memory which needs to be freed when
|
||||
no longer needed
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= count only
|
||||
bit1= use numeric qualifiers rather than names
|
||||
bit3= check for completeness of list and eventually
|
||||
fill up with entries deduced from st_mode
|
||||
@return >0 means ok
|
||||
0 means error
|
||||
*/
|
||||
int aaip_encode_both_acl(char *a_acl_text, char *d_acl_text, mode_t st_mode,
|
||||
size_t *result_len, unsigned char **result, int flag);
|
||||
|
||||
|
||||
/* Analyze occurence of ACL tag types in long text form. If not disabled by
|
||||
parameter flag remove the entries of type "user::" , "group::" , "other::" ,
|
||||
or "other:" from an ACL in long text form if they match the bits in st_mode
|
||||
as described by man 2 stat and man 5 acl.
|
||||
@param acl_text The text to be analyzed and eventually shortened.
|
||||
@param st_mode The component of struct stat which tells permission
|
||||
bits and eventually shall take equivalent bits as read
|
||||
from the ACL. The caller should submit a pointer
|
||||
to the st_mode variable which holds permissions as
|
||||
indicated by stat(2) resp. ECMA-119 and RRIP data.
|
||||
@param flag bit0= do not remove entries, only determine return value
|
||||
bit1= like bit0 but return immediately if a non-st_mode
|
||||
ACL entry is found
|
||||
bit2= update *st_mode by acl_text
|
||||
("user::" -> S_IRWXU, "mask::"|"group::" -> S_IRWXG,
|
||||
"other::" -> S_IRWXO)
|
||||
bit3= update acl_text by *st_mode (same mapping as bit 2
|
||||
but with reversed transfer direction)
|
||||
bit4= map "group::" <-> S_IRWXG in any case.
|
||||
I.e. ignore "mask::".
|
||||
@return <0 failure
|
||||
>=0 tells in its bits which tag types were found.
|
||||
The first three tell which types deviate from the
|
||||
corresponding st_mode settings:
|
||||
bit0= "other::" overrides S_IRWXO
|
||||
bit1= "group::" overrides S_IRWXG (no "mask::" found)
|
||||
bit2= "user::" overrides S_IRWXU
|
||||
The second three tell which types comply with st_mode:
|
||||
bit3= "other::" matches S_IRWXO
|
||||
bit4= "group::" matches S_IRWXG (no "mask::" found)
|
||||
bit5= "user::" matches S_IRWXU
|
||||
Given the nature of ACLs nearly all combinations are
|
||||
possible although some would come from invalid ACLs.
|
||||
bit6= other ACL tag types are present. Particularly:
|
||||
bit7= "user:...:" is present
|
||||
bit8= "group:...:" is present
|
||||
bit9= "mask::" is present
|
||||
bit10= "group::" found and "mask::" exists
|
||||
|
||||
*/
|
||||
int aaip_cleanout_st_mode(char *acl_text, mode_t *st_mode, int flag);
|
||||
|
||||
|
||||
/* Append entries of type "user::" , "group::" , "other::" representing the
|
||||
permission bits in st_mode if those tag types are not present in the ACL
|
||||
text. Append "mask::" if missing although "user:...:" or "group:...:"
|
||||
is present. Eventually set it to S_IRWXG bits of st_mode.
|
||||
@param acl_text The text to be made longer. It must offer 43 bytes more
|
||||
storage space than its length when it is submitted.
|
||||
@param st_mode The component of struct stat which shall provide the
|
||||
permission information.
|
||||
@param flag Unused yet. Submit 0.
|
||||
@return <0 failure
|
||||
*/
|
||||
int aaip_add_acl_st_mode(char *acl_text, mode_t st_mode, int flag);
|
||||
|
||||
|
||||
/* ------ OS interface ------ */
|
||||
|
||||
/* Obtain the ACL of the given file in long text form.
|
||||
@param path Path to the file
|
||||
@param text Will hold the result. This is a managed object which
|
||||
finally has to be freed by a call to this function
|
||||
with bit15 of flag.
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= obtain default ACL rather than access ACL
|
||||
bit4= set *text = NULL and return 2
|
||||
if the ACL matches st_mode permissions.
|
||||
bit15= free text and return 1
|
||||
@return 1 ok
|
||||
2 only st_mode permissions exist and bit 4 is set
|
||||
0 ACL support not enabled at compile time
|
||||
-1 failure of system ACL service (see errno)
|
||||
*/
|
||||
int aaip_get_acl_text(char *path, char **text, int flag);
|
||||
|
||||
|
||||
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
|
||||
that is ready for aaip_encode(). The returned data objects finally have
|
||||
to be freed by a call with flag bit 15.
|
||||
@param path Path to the file
|
||||
@param num_attrs Will return the number of name-value pairs
|
||||
@param names Will return an array of pointers to 0-terminated names
|
||||
@param value_lengths Will return an arry with the lenghts of values
|
||||
@param values Will return an array of pointers to 8-bit values
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= obtain ACLs (access and eventually default) via
|
||||
system ACL API and encode
|
||||
bit1= use numeric ACL qualifiers rather than names
|
||||
bit2= do not obtain attributes other than ACLs
|
||||
bit3= do not ignore eventual non-user attributes.
|
||||
I.e. those with a name which does not begin
|
||||
by "user."
|
||||
bit4= do not return trivial ACL that matches st_mode
|
||||
bit15= free memory of names, value_lengths, values
|
||||
@return >0 ok
|
||||
<=0 error
|
||||
*/
|
||||
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
|
||||
size_t **value_lengths, char ***values, int flag);
|
||||
|
||||
|
||||
/* --------------------------------- Decoder ---------------------------- */
|
||||
|
||||
/*
|
||||
The AAIP decoder offers several levels of abstraction of which the
|
||||
lower two avoid the use of dynamic memory. It provides a stateful decoding
|
||||
context with a small buffer which delivers results to caller provided
|
||||
memory locations.
|
||||
|
||||
The lowest level is the stream-like Component Level Interface. It allows
|
||||
to decode very many very long attributes.
|
||||
|
||||
Next is the Pair Level Interface which delivers to fixly sized storage for
|
||||
name and value. It allows to decode very many attributes.
|
||||
|
||||
The List Level Interface uses dynamic memory allocation to provide arrays
|
||||
of names, values and value lengths. It is intended for moderately sized
|
||||
attribute lists but may also be used as alternative to Pair Level.
|
||||
*/
|
||||
|
||||
/* Operations on complete AAIP field strings which need no decoder context.
|
||||
These function expect to get submitted a complete chain of AAIP fields.
|
||||
*/
|
||||
|
||||
/* Determine the size of the AAIP string by interpreting the SUSP structure.
|
||||
@param data An arbitrary number of bytes beginning with the
|
||||
complete chain of AAIP fields. Trailing trash is
|
||||
ignored.
|
||||
@param flag Unused yet. Submit 0.
|
||||
@return The number of bytes of the AAIP field chain.
|
||||
*/
|
||||
size_t aaip_count_bytes(unsigned char *data, int flag);
|
||||
|
||||
|
||||
/* The AAIP decoder context.
|
||||
*/
|
||||
struct aaip_state;
|
||||
|
||||
|
||||
/* Obtain the size in bytes of an aaip_state object.
|
||||
*/
|
||||
size_t aaip_sizeof_aaip_state(void);
|
||||
|
||||
|
||||
/* Initialize a AAIP decoder context.
|
||||
This has to be done before the first AAIP field of a node is processed.
|
||||
The caller has to provide the storage of the struct aaip_state.
|
||||
@param aaip The AAIP decoder context to be initialized
|
||||
@param flag Bitfield for control purposes
|
||||
submit 0
|
||||
@return <=0 error , >0 ok
|
||||
*/
|
||||
int aaip_init_aaip_state(struct aaip_state *aaip, int flag);
|
||||
|
||||
|
||||
/* ------------------------- Component Level Interface ------------------- */
|
||||
/*
|
||||
Provides support for unlimited component size but demands the caller
|
||||
to have a growing storage facility resp. to do own oversize handling.
|
||||
|
||||
This interface expects moderatly sized input pieces and will hand out
|
||||
moderately sized result pieces. The number of transactions is virtually
|
||||
unlimited.
|
||||
*/
|
||||
|
||||
/* Submit small data chunk for decoding.
|
||||
The return value will tell whether data are pending for being fetched.
|
||||
@param aaip The AAIP decoder context
|
||||
@param data Not more than 2048 bytes input for the decoder
|
||||
@param num_data Number of bytes in data
|
||||
0 inquires the buffer status avoiding replies <= 0
|
||||
@param ready_bytes Number of decoded bytes ready for delivery
|
||||
@param flag Bitfield for control purposes
|
||||
@return -1= non-AAIP field detected
|
||||
*ready_bytes gives number of consumed bytes in data
|
||||
0= cannot accept data because buffer full
|
||||
1= no component record complete, submit more data
|
||||
2= component record complete, may be delivered
|
||||
3= component complete, may be delivered
|
||||
4= no component available, no more data expected, done
|
||||
*/
|
||||
int aaip_submit_data(struct aaip_state *aaip,
|
||||
unsigned char *data, size_t num_data,
|
||||
size_t *ready_bytes, int flag);
|
||||
|
||||
|
||||
/* Fetch the available part of current component.
|
||||
The return value will tell whether it belongs to name or to value and
|
||||
whether that name or value is completed now.
|
||||
@param aaip The AAIP decoder context
|
||||
@param result Has to point to storage for the component data
|
||||
@param result_size Gives the amount of provided result storage
|
||||
@param num_result Will tell the number of fetched result bytes
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= discard data rather than copying to result
|
||||
@return -2 = insufficient result_size
|
||||
-1 = no data ready for delivery
|
||||
0 = result holds the final part of a name
|
||||
1 = result holds an intermediate part of a name
|
||||
2 = result holds the final part of a value
|
||||
3 = result holds an intermediate part of a value
|
||||
*/
|
||||
int aaip_fetch_data(struct aaip_state *aaip,
|
||||
char *result, size_t result_size, size_t *num_result,
|
||||
int flag);
|
||||
|
||||
|
||||
/* Skip the current component and eventually the following value component.
|
||||
This has to be called if fetching of a component shall be aborted
|
||||
but the next component resp. pair shall be fetchable again.
|
||||
aaip_submit_data() will not indicate readiness for fetching until all
|
||||
bytes of the skipped components are submitted. Those bytes get discarded.
|
||||
@param aaip The AAIP decoder context
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not skip value if current component is name
|
||||
@return <=0 error , 1= now in skip state, 2= not in skip state
|
||||
*/
|
||||
int aaip_skip_component(struct aaip_state *aaip, int flag);
|
||||
|
||||
|
||||
/* ------------------------- Pair Level Interface ------------------------ */
|
||||
/*
|
||||
Provides support for names and values of limited size. The limits are
|
||||
given by the caller who has to provide the storage for name and value.
|
||||
|
||||
This interface expects moderatly sized input pieces.
|
||||
The number of input transcations is virtually unlimited.
|
||||
The number of pair transactions after aaip_init() should be limited
|
||||
to 4 billion.
|
||||
*/
|
||||
|
||||
|
||||
/* Accept raw input data and collect a pair of name and value.
|
||||
The return value will indicate whether the pair is complete, whether more
|
||||
pairs are complete or whether more data are desired. No input data will be
|
||||
accepted as long as complete pairs are pending. The end of the attribute
|
||||
list will be indicated.
|
||||
@param aaip The AAIP decoder context
|
||||
@param data The raw data to decode
|
||||
@param num_data Number of data bytes provided
|
||||
@param consumed Returns the number of consumed data bytes
|
||||
@param name Buffer to build the name string
|
||||
@param name_size Maximum number of bytes in name
|
||||
@param name_fill Holds the current buffer fill of name
|
||||
@param value Buffer to build the value string
|
||||
@param value_size Maximum number of bytes in value
|
||||
@param value_fill Holds the current buffer fill of value
|
||||
@param flag Bitfield for control purposes - submit 0 for now
|
||||
@return <0 error
|
||||
0 data not accepted, first fetch pending pairs with num_data == 0
|
||||
1 name and value are not valid yet, submit more data
|
||||
2 name and value are valid, submit more data
|
||||
3 name and value are valid, pairs pending, fetch with num_data == 0
|
||||
4 name and value are valid, no more data expected
|
||||
5 name and value are not valid, no more data expected
|
||||
|
||||
*/
|
||||
int aaip_decode_pair(struct aaip_state *aaip,
|
||||
unsigned char *data, size_t num_data, size_t *consumed,
|
||||
char *name, size_t name_size, size_t *name_fill,
|
||||
char *value, size_t value_size, size_t *value_fill,
|
||||
int flag);
|
||||
|
||||
|
||||
/* Inquire the number of pairs which were skipped because being oversized.
|
||||
@param aaip The AAIP decoder context
|
||||
@param flag Bitfield for control purposes - submit 0 for now
|
||||
@return The number of pairs skipped since aaip_init()
|
||||
*/
|
||||
unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag);
|
||||
|
||||
|
||||
/* ------------------------- List Level Interface ------------------------ */
|
||||
/*
|
||||
Provides support for names and values of limited size. The limits are
|
||||
given for total memory consumption and for number of attributes.
|
||||
|
||||
Iterated decoding is supported as long as no single attribute exceeds
|
||||
the memory limit.
|
||||
*/
|
||||
|
||||
/* Accept raw input data and collect arrays of name pointers, value lengths
|
||||
and value pointers. A handle object will emerge which finally has to be
|
||||
be freed by a call with bit 15.
|
||||
@param handle The decoding context.
|
||||
It will be created by this call with flag bit 0 or if
|
||||
*handle == NULL. This handle has to be the same as long
|
||||
as decoding goes on and finally has to be freed by a
|
||||
call with bit15.
|
||||
@param memory_limit Maximum number of bytes to allocate
|
||||
@param num_attr_limit Maximum number of name-value pairs to allocate
|
||||
@param data The raw data to decode
|
||||
@param num_data Number of data bytes provided
|
||||
@param consumed Returns the number of consumed data bytes
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= this is the first call for a file object
|
||||
bit15= end decoding :
|
||||
Free handle and its intermediate list memory.
|
||||
@return <=0 error
|
||||
1 not complete yet, submit more data
|
||||
2 arrays are complete, call aaip_get_decoded_attrs()
|
||||
3 limit exceeded, not complete yet, call with bit15 and give up
|
||||
4 limit exceeded, call aaip_get_decoded_attrs() and try again
|
||||
*/
|
||||
int aaip_decode_attrs(struct aaip_state **handle,
|
||||
size_t memory_limit, size_t num_attr_limit,
|
||||
unsigned char *data, size_t num_data, size_t *consumed,
|
||||
int flag);
|
||||
|
||||
|
||||
/* Obtain the resulting attributes when aaip_decode_attrs() indicates to
|
||||
be done or to have the maximum possible amount of result ready.
|
||||
The returned data objects get detached from handle making it ready for
|
||||
the next round of decoding with possibly a different input source. The
|
||||
returned data objects finally have to be freed by a call with flag bit 15.
|
||||
@param handle The decoding context created by aaip_decode_attrs()
|
||||
@param num_attrs Will return the number of name-value pairs
|
||||
@param names Will return an array of pointers to 0-terminated names
|
||||
@param value_lengths Will return an arry with the lenghts of values
|
||||
@param values Will return an array of pointers to 8-bit values
|
||||
@param flag Bitfield for control purposes
|
||||
bit15= free memory of names, value_lengths, values
|
||||
*/
|
||||
int aaip_get_decoded_attrs(struct aaip_state **handle, size_t *num_attrs,
|
||||
char ***names, size_t **value_lengths, char ***values,
|
||||
int flag);
|
||||
|
||||
|
||||
/* ------ ACL representation ------ */
|
||||
|
||||
/* Convert an AAIP ACL attribute value into the long text form of ACL.
|
||||
@param data The raw data to decode
|
||||
@param num_data Number of data bytes provided
|
||||
@param consumed Returns the number of consumed data bytes
|
||||
@param acl_text Will be filled with ACL long text form
|
||||
@param acl_text_size Maximum number of bytes to be written to acl_text
|
||||
@param acl_text_fill Will return the number of bytes in acl_text
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= count only, do not really produce bytes:
|
||||
acl_text will not be touched,
|
||||
acl_text_size will be ignored,
|
||||
*acl_text_fill will return the counted number
|
||||
bit1= expected is a default ACL (see return value 2)
|
||||
@return 1 success
|
||||
2 success, begin of default/access ACL encountered,
|
||||
submit data + *consumed for access/default ACL
|
||||
-1 error with reading of qualifier
|
||||
-2 error with writing of ACL text line
|
||||
-3 version mismatch
|
||||
-4 unknown tag type encountered
|
||||
*/
|
||||
int aaip_decode_acl(unsigned char *data, size_t num_data, size_t *consumed,
|
||||
char *acl_text, size_t acl_text_size,
|
||||
size_t *acl_text_fill, int flag);
|
||||
|
||||
|
||||
/* ------ OS interface ------ */
|
||||
|
||||
/* Set the ACL of the given file to a given list in long text form.
|
||||
@param path Path to the file
|
||||
@param text The input text (0 terminated, ACL long text form)
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= set default ACL rather than access ACL
|
||||
@return >0 ok
|
||||
0 ACL support not enabled at compile time
|
||||
-1 failure of system ACL service (see errno)
|
||||
*/
|
||||
int aaip_set_acl_text(char *path, char *text, int flag);
|
||||
|
||||
|
||||
/* Bring the given attributes and/or ACLs into effect with the given file.
|
||||
@param path Path to the file
|
||||
@param num_attrs Number of attributes
|
||||
@param names Array of pointers to 0 terminated name strings
|
||||
@param value_lengths Array of byte lengths for each attribute payload
|
||||
@param values Array of pointers to the attribute payload bytes
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= decode and set ACLs
|
||||
bit1= first clear all existing attributes of the file
|
||||
bit2= do not set attributes other than ACLs
|
||||
bit3= do not ignore eventual non-user attributes.
|
||||
I.e. those with a name which does not begin
|
||||
by "user."
|
||||
@return 1 success
|
||||
-1 error memory allocation
|
||||
-2 error with decoding of ACL
|
||||
-3 error with setting ACL
|
||||
-4 error with setting attribute
|
||||
-5 error with deleting attributes
|
||||
-6 support of xattr not enabled at compile time
|
||||
-7 support of ACL not enabled at compile time
|
||||
*/
|
||||
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
|
||||
size_t *value_lengths, char **values, int flag);
|
||||
|
||||
#endif /* ! Aaip_h_is_includeD */
|
||||
|
@ -1,23 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Synchronized ring buffer, works with a writer thread and a read thread.
|
||||
*
|
||||
*
|
||||
* TODO #00010 : optimize ring buffer
|
||||
* - write/read at the end of buffer requires a second mutex_lock, even if
|
||||
* there's enought space/data at the beginning
|
||||
* - pre-buffer for writes < BLOCK_SIZE
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Use the copy of the struct burn_source definition in libisofs.h
|
||||
*/
|
||||
#define LIBISOFS_WITHOUT_LIBBURN yes
|
||||
#include "libisofs.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "libburn/libburn.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
#include <pthread.h>
|
||||
@ -30,13 +35,13 @@
|
||||
struct iso_ring_buffer
|
||||
{
|
||||
uint8_t *buf;
|
||||
|
||||
|
||||
/*
|
||||
* Max number of bytes in buffer
|
||||
*/
|
||||
size_t cap;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Number of bytes available.
|
||||
*/
|
||||
size_t size;
|
||||
@ -45,11 +50,11 @@ struct iso_ring_buffer
|
||||
size_t rpos;
|
||||
size_t wpos;
|
||||
|
||||
/*
|
||||
/*
|
||||
* flags to report if read or writer threads ends execution
|
||||
* 0 not finished, 1 finished ok, 2 finish with error
|
||||
* 0 not finished, 1 finished ok, 2 finish with error
|
||||
*/
|
||||
unsigned int rend :2;
|
||||
unsigned int rend :2;
|
||||
unsigned int wend :2;
|
||||
|
||||
/* just for statistical purposes */
|
||||
@ -63,9 +68,9 @@ struct iso_ring_buffer
|
||||
|
||||
/**
|
||||
* Create a new buffer.
|
||||
*
|
||||
*
|
||||
* The created buffer should be freed with iso_ring_buffer_free()
|
||||
*
|
||||
*
|
||||
* @param size
|
||||
* Number of blocks in buffer. You should supply a number >= 32, otherwise
|
||||
* size will be ignored and 32 will be used by default, which leads to a
|
||||
@ -85,14 +90,14 @@ int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf)
|
||||
if (buffer == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
buffer->cap = (size > 32 ? size : 32) * BLOCK_SIZE;
|
||||
buffer->buf = malloc(buffer->cap);
|
||||
if (buffer->buf == NULL) {
|
||||
free(buffer);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
buffer->size = 0;
|
||||
buffer->wpos = 0;
|
||||
buffer->rpos = 0;
|
||||
@ -126,7 +131,7 @@ void iso_ring_buffer_free(IsoRingBuffer *buf)
|
||||
/**
|
||||
* Write count bytes into buffer. It blocks until all bytes where written or
|
||||
* reader close the buffer.
|
||||
*
|
||||
*
|
||||
* @param buf
|
||||
* the buffer
|
||||
* @param data
|
||||
@ -189,7 +194,7 @@ int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count)
|
||||
* bytes has been read. If the writer finishes before outputting enought
|
||||
* bytes, 0 (EOF) is returned, the number of bytes already read remains
|
||||
* unknown.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 success, 0 EOF, < 0 error
|
||||
*/
|
||||
@ -252,7 +257,7 @@ void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error)
|
||||
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error)
|
||||
{
|
||||
pthread_mutex_lock(&buf->mutex);
|
||||
|
||||
|
||||
if (buf->rend) {
|
||||
/* reader already closed */
|
||||
pthread_mutex_unlock(&buf->mutex);
|
||||
@ -285,9 +290,9 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
|
||||
|
||||
/**
|
||||
* Get the status of the buffer used by a burn_source.
|
||||
*
|
||||
*
|
||||
* @param b
|
||||
* A burn_source previously obtained with
|
||||
* A burn_source previously obtained with
|
||||
* iso_image_create_burn_source().
|
||||
* @param size
|
||||
* Will be filled with the total size of the buffer, in bytes
|
||||
@ -302,7 +307,7 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
|
||||
* 6="ended" : consumption has ended without input error
|
||||
* 7="aborted" : consumption has ended after input error
|
||||
*/
|
||||
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
|
||||
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
|
||||
size_t *free_bytes)
|
||||
{
|
||||
int ret;
|
||||
@ -311,7 +316,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
buf = ((Ecma119Image*)(b->data))->buffer;
|
||||
|
||||
|
||||
/* get mutex */
|
||||
pthread_mutex_lock(&buf->mutex);
|
||||
if (size) {
|
||||
@ -322,7 +327,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
|
||||
}
|
||||
|
||||
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
|
||||
|
||||
|
||||
pthread_mutex_unlock(&buf->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,19 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
/* libisofs.h defines aaip_xinfo_func */
|
||||
#include "libisofs.h"
|
||||
|
||||
#include "builder.h"
|
||||
#include "node.h"
|
||||
#include "fsource.h"
|
||||
#include "image.h"
|
||||
#include "aaip_0_2.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
|
||||
void iso_node_builder_ref(IsoNodeBuilder *builder)
|
||||
{
|
||||
++builder->refcount;
|
||||
@ -52,12 +60,13 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* take a ref to the src, as stream has taken our ref */
|
||||
iso_file_source_ref(src);
|
||||
|
||||
name = iso_file_source_get_name(src);
|
||||
ret = iso_node_new_file(name, stream, &node);
|
||||
if (ret < 0) {
|
||||
/* the stream has taken our ref to src, so we need to add one */
|
||||
iso_file_source_ref(src);
|
||||
iso_stream_unref(stream);
|
||||
free(name);
|
||||
return ret;
|
||||
@ -83,7 +92,10 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
int ret;
|
||||
struct stat info;
|
||||
IsoNode *new;
|
||||
IsoFilesystem *fs;
|
||||
char *name;
|
||||
unsigned char *aa_string;
|
||||
char *a_text = NULL, *d_text = NULL;
|
||||
|
||||
if (builder == NULL || src == NULL || node == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
@ -100,6 +112,7 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
}
|
||||
|
||||
name = iso_file_source_get_name(src);
|
||||
fs = iso_file_source_get_filesystem(src);
|
||||
new = NULL;
|
||||
|
||||
switch (info.st_mode & S_IFMT) {
|
||||
@ -143,6 +156,13 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
}
|
||||
ret = iso_node_new_symlink(name, strdup(dest), &link);
|
||||
new = (IsoNode*) link;
|
||||
if (fs != NULL) {
|
||||
link->fs_id = fs->get_id(fs);
|
||||
if (link->fs_id != 0) {
|
||||
link->st_ino = info.st_ino;
|
||||
link->st_dev = info.st_dev;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
@ -155,6 +175,13 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
ret = iso_node_new_special(name, info.st_mode, info.st_rdev,
|
||||
&special);
|
||||
new = (IsoNode*) special;
|
||||
if (fs != NULL) {
|
||||
special->fs_id = fs->get_id(fs);
|
||||
if (special->fs_id != 0) {
|
||||
special->st_ino = info.st_ino;
|
||||
special->st_dev = info.st_dev;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -165,7 +192,7 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
}
|
||||
|
||||
/* fill fields */
|
||||
iso_node_set_permissions(new, info.st_mode);
|
||||
iso_node_set_perms_internal(new, info.st_mode, 1);
|
||||
iso_node_set_uid(new, info.st_uid);
|
||||
iso_node_set_gid(new, info.st_gid);
|
||||
iso_node_set_atime(new, info.st_atime);
|
||||
@ -173,7 +200,31 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
iso_node_set_ctime(new, info.st_ctime);
|
||||
iso_node_set_uid(new, info.st_uid);
|
||||
|
||||
/* Eventually set S_IRWXG from ACL */
|
||||
if (image->builder_ignore_acl) {
|
||||
ret = iso_file_source_get_aa_string(src, &aa_string, 4);
|
||||
if (aa_string != NULL)
|
||||
iso_aa_get_acl_text(aa_string, info.st_mode, &a_text, &d_text, 16);
|
||||
if (a_text != NULL) {
|
||||
aaip_cleanout_st_mode(a_text, &(info.st_mode), 4 | 16);
|
||||
iso_node_set_perms_internal(new, info.st_mode, 1);
|
||||
}
|
||||
iso_aa_get_acl_text(aa_string, info.st_mode, &a_text, &d_text,
|
||||
1 << 15); /* free ACL texts */
|
||||
}
|
||||
|
||||
/* Obtain ownership of eventual AAIP string */
|
||||
ret = iso_file_source_get_aa_string(src, &aa_string,
|
||||
1 | (image->builder_ignore_acl << 1) |
|
||||
(image->builder_ignore_ea << 2 ));
|
||||
if (ret == 1 && aa_string != NULL) {
|
||||
ret = iso_node_add_xinfo(new, aaip_xinfo_func, aa_string);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*node = new;
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,7 @@ struct Iso_Node_Builder
|
||||
* In that case, if the implementation can't do the conversion, it
|
||||
* should fail propertly.
|
||||
*
|
||||
* On sucess, the ref. to src will be owned by file, so you musn't
|
||||
* unref it.
|
||||
* Note that the src is never unref, so you need to free it.
|
||||
*
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
|
@ -57,7 +57,7 @@ int ds_open(IsoDataSource *src)
|
||||
|
||||
data = (struct file_data_src*) src->data;
|
||||
if (data->fd != -1) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
fd = open(data->path, O_RDONLY);
|
||||
@ -81,7 +81,7 @@ int ds_close(IsoDataSource *src)
|
||||
|
||||
data = (struct file_data_src*) src->data;
|
||||
if (data->fd == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
/* close can fail if fd is not valid, but that should never happen */
|
||||
@ -102,7 +102,7 @@ static int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
|
||||
|
||||
data = (struct file_data_src*) src->data;
|
||||
if (data->fd == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
/* goes to requested block */
|
||||
|
@ -1,13 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2007 Mario Danic
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
Use the copy of the struct burn_source definition in libisofs.h
|
||||
*/
|
||||
#define LIBISOFS_WITHOUT_LIBBURN yes
|
||||
#include "libisofs.h"
|
||||
|
||||
#include "ecma119.h"
|
||||
#include "joliet.h"
|
||||
#include "iso1999.h"
|
||||
@ -19,8 +25,7 @@
|
||||
#include "messages.h"
|
||||
#include "rockridge.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "libburn/libburn.h"
|
||||
#include "system_area.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@ -90,10 +95,10 @@ size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n)
|
||||
/**
|
||||
* Computes the total size of all directory entries of a single dir,
|
||||
* acording to ECMA-119 6.8.1.1
|
||||
*
|
||||
*
|
||||
* This also take into account the size needed for RR entries and
|
||||
* SUSP continuation areas (SUSP, 5.1).
|
||||
*
|
||||
*
|
||||
* @param ce
|
||||
* Will be filled with the size needed for Continuation Areas
|
||||
* @return
|
||||
@ -117,24 +122,29 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||
size_t remaining;
|
||||
int section, nsections;
|
||||
Ecma119Node *child = dir->info.dir->children[i];
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
if (t->rockridge) {
|
||||
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
|
||||
*ce += ce_len;
|
||||
}
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
|
||||
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
if (t->rockridge) {
|
||||
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
|
||||
*ce += ce_len;
|
||||
}
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The size of a dir is always a multiple of block size, as we must add
|
||||
* the size of the unused space after the last directory record
|
||||
* The size of a dir is always a multiple of block size, as we must add
|
||||
* the size of the unused space after the last directory record
|
||||
* (ECMA-119, 6.8.1.3)
|
||||
*/
|
||||
len = ROUND_UP(len, BLOCK_SIZE);
|
||||
@ -222,28 +232,31 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
|
||||
/**
|
||||
* Write a single directory record (ECMA-119, 9.1)
|
||||
*
|
||||
*
|
||||
* @param file_id
|
||||
* if >= 0, we use it instead of the filename (for "." and ".." entries).
|
||||
* @param len_fi
|
||||
* Computed length of the file identifier. Total size of the directory
|
||||
* entry will be len + 33 + padding if needed (ECMA-119, 9.1.12)
|
||||
* @param info
|
||||
* SUSP entries for the given directory record. It will be NULL for the
|
||||
* root directory record in the PVD (ECMA-119, 8.4.18) (in order to
|
||||
* SUSP entries for the given directory record. It will be NULL for the
|
||||
* root directory record in the PVD (ECMA-119, 8.4.18) (in order to
|
||||
* distinguish it from the "." entry in the root directory)
|
||||
*/
|
||||
static
|
||||
void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
|
||||
uint8_t *buf, size_t len_fi, struct susp_info *info)
|
||||
uint8_t *buf, size_t len_fi, struct susp_info *info,
|
||||
int extent)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr; /*< size of dir entry without SUSP fields */
|
||||
int multi_extend = 0;
|
||||
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
|
||||
: (uint8_t*)node->iso_name;
|
||||
|
||||
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
||||
IsoNode *iso;
|
||||
|
||||
len_dr = 33 + len_fi + (len_fi % 2 ? 0 : 1);
|
||||
|
||||
@ -260,12 +273,13 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
|
||||
len = node->info.dir->len;
|
||||
block = node->info.dir->block;
|
||||
} else if (node->type == ECMA119_FILE) {
|
||||
len = iso_file_src_get_size(node->info.file);
|
||||
block = node->info.file->block;
|
||||
block = node->info.file->sections[extent].block;
|
||||
len = node->info.file->sections[extent].size;
|
||||
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
|
||||
} else {
|
||||
/*
|
||||
* for nodes other than files and dirs, we set both
|
||||
* len and block to 0
|
||||
/*
|
||||
* for nodes other than files and dirs, we set both
|
||||
* len and block to 0
|
||||
*/
|
||||
len = 0;
|
||||
block = 0;
|
||||
@ -280,12 +294,21 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
|
||||
rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0);
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
|
||||
rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
|
||||
if(t->dir_rec_mtime) {
|
||||
iso= node->node;
|
||||
iso_datetime_7(rec->recording_time,
|
||||
t->replace_timestamps ? t->timestamp : iso->mtime,
|
||||
t->always_gmt);
|
||||
} else {
|
||||
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
|
||||
}
|
||||
rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
|
||||
/* and finally write the SUSP fields */
|
||||
/*
|
||||
* and finally write the SUSP fields.
|
||||
*/
|
||||
if (info != NULL) {
|
||||
rrip_write_susp_fields(t, info, buf + len_dr);
|
||||
}
|
||||
@ -306,8 +329,8 @@ char *get_relaxed_vol_id(Ecma119Image *t, const char *name)
|
||||
return str;
|
||||
}
|
||||
iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
|
||||
"Charset conversion error. Can't convert %s from %s to %s",
|
||||
name, t->input_charset, t->output_charset);
|
||||
"Charset conversion error. Cannot convert from %s to %s",
|
||||
t->input_charset, t->output_charset);
|
||||
}
|
||||
return strdup(name);
|
||||
}
|
||||
@ -365,7 +388,7 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4);
|
||||
iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4);
|
||||
|
||||
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL);
|
||||
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0);
|
||||
|
||||
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
|
||||
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
|
||||
@ -396,7 +419,7 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
}
|
||||
|
||||
static
|
||||
int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
@ -410,14 +433,14 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
/* initialize buffer with 0s */
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
|
||||
/*
|
||||
/*
|
||||
* set susp_info to 0's, this way code for both plain ECMA-119 and
|
||||
* RR is very similar
|
||||
*/
|
||||
memset(&info, 0, sizeof(struct susp_info));
|
||||
if (t->rockridge) {
|
||||
/* initialize the ce_block, it might be needed */
|
||||
info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
|
||||
info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
|
||||
BLOCK_SIZE);
|
||||
}
|
||||
|
||||
@ -429,7 +452,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
}
|
||||
}
|
||||
len = 34 + info.suf_len;
|
||||
write_one_dir_record(t, dir, 0, buf, 1, &info);
|
||||
write_one_dir_record(t, dir, 0, buf, 1, &info, 0);
|
||||
buf += len;
|
||||
|
||||
if (t->rockridge) {
|
||||
@ -439,40 +462,46 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
}
|
||||
}
|
||||
len = 34 + info.suf_len;
|
||||
write_one_dir_record(t, dir, 1, buf, 1, &info);
|
||||
write_one_dir_record(t, parent, 1, buf, 1, &info, 0);
|
||||
buf += len;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
int section, nsections;
|
||||
Ecma119Node *child = dir->info.dir->children[i];
|
||||
|
||||
/* compute len of directory entry */
|
||||
fi_len = strlen(child->iso_name);
|
||||
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
|
||||
if (need_version_number(t, child)) {
|
||||
len += 2;
|
||||
}
|
||||
|
||||
/* get the SUSP fields if rockridge is enabled */
|
||||
if (t->rockridge) {
|
||||
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
len += info.suf_len;
|
||||
}
|
||||
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
/* compute len of directory entry */
|
||||
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
|
||||
if (need_version_number(t, child)) {
|
||||
len += 2;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
|
||||
/* get the SUSP fields if rockridge is enabled */
|
||||
if (t->rockridge) {
|
||||
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
len += info.suf_len;
|
||||
}
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, &info, section);
|
||||
buf += len;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, &info);
|
||||
buf += len;
|
||||
}
|
||||
|
||||
/* write the last block */
|
||||
@ -490,13 +519,13 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
}
|
||||
|
||||
static
|
||||
int write_dirs(Ecma119Image *t, Ecma119Node *root)
|
||||
int write_dirs(Ecma119Image *t, Ecma119Node *root, Ecma119Node *parent)
|
||||
{
|
||||
int ret;
|
||||
size_t i;
|
||||
|
||||
/* write all directory entries for this dir */
|
||||
ret = write_one_dir(t, root);
|
||||
ret = write_one_dir(t, root, parent);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -505,7 +534,7 @@ int write_dirs(Ecma119Image *t, Ecma119Node *root)
|
||||
for (i = 0; i < root->info.dir->nchildren; i++) {
|
||||
Ecma119Node *child = root->info.dir->children[i];
|
||||
if (child->type == ECMA119_DIR) {
|
||||
ret = write_dirs(t, child);
|
||||
ret = write_dirs(t, child, root);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -624,7 +653,7 @@ int ecma119_writer_write_data(IsoImageWriter *writer)
|
||||
t = writer->target;
|
||||
|
||||
/* first of all, we write the directory structure */
|
||||
ret = write_dirs(t, t->root);
|
||||
ret = write_dirs(t, t->root, t->root);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -709,7 +738,7 @@ int pad_writer_write_data(IsoImageWriter *writer)
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
t = writer->target;
|
||||
|
||||
|
||||
if (t->pad_blocks == 0) {
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
@ -768,10 +797,14 @@ void *write_function(void *arg)
|
||||
target->bytes_written = (off_t) 0;
|
||||
target->percent_written = 0;
|
||||
|
||||
/* Write System Area, 16 blocks of zeros (ECMA-119, 6.2.1) */
|
||||
memset(buf, 0, BLOCK_SIZE);
|
||||
for (i = 0; i < 16; ++i) {
|
||||
res = iso_write(target, buf, BLOCK_SIZE);
|
||||
/* Write System Area (ECMA-119, 6.2.1) */
|
||||
{
|
||||
uint8_t sa[16 * BLOCK_SIZE];
|
||||
res = iso_write_system_area(target, sa);
|
||||
if (res < 0) {
|
||||
goto write_error;
|
||||
}
|
||||
res = iso_write(target, sa, 16 * BLOCK_SIZE);
|
||||
if (res < 0) {
|
||||
goto write_error;
|
||||
}
|
||||
@ -820,7 +853,7 @@ void *write_function(void *arg)
|
||||
iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED, 0, NULL);
|
||||
} else {
|
||||
/* image write error */
|
||||
iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
|
||||
iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
|
||||
"Image write error");
|
||||
}
|
||||
iso_ring_buffer_writer_close(target->buffer, 1);
|
||||
@ -832,6 +865,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
{
|
||||
int ret, i, voldesc_size, nwriters;
|
||||
Ecma119Image *target;
|
||||
int el_torito_writer_index = -1, file_src_writer_index= -1;
|
||||
|
||||
/* 1. Allocate target and copy opts there */
|
||||
target = calloc(1, sizeof(Ecma119Image));
|
||||
@ -853,9 +887,15 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
target->rockridge = opts->rockridge;
|
||||
target->joliet = opts->joliet;
|
||||
target->iso1999 = opts->iso1999;
|
||||
target->hardlinks = opts->hardlinks;
|
||||
target->aaip = opts->aaip;
|
||||
target->always_gmt = opts->always_gmt;
|
||||
|
||||
#ifndef Libisofs_hardlink_matcheR
|
||||
target->ino = 0;
|
||||
target->omit_version_numbers = opts->omit_version_numbers
|
||||
#endif
|
||||
|
||||
target->omit_version_numbers = opts->omit_version_numbers
|
||||
| opts->max_37_char_filenames;
|
||||
target->allow_deep_paths = opts->allow_deep_paths;
|
||||
target->allow_longer_paths = opts->allow_longer_paths;
|
||||
@ -865,6 +905,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
target->allow_full_ascii = opts->allow_full_ascii;
|
||||
target->relaxed_vol_atts = opts->relaxed_vol_atts;
|
||||
target->joliet_longer_paths = opts->joliet_longer_paths;
|
||||
target->rrip_version_1_10 = opts->rrip_version_1_10;
|
||||
target->rrip_1_10_px_ino = opts->rrip_1_10_px_ino;
|
||||
target->aaip_susp_1_10 = opts->aaip_susp_1_10;
|
||||
target->dir_rec_mtime = opts->dir_rec_mtime;
|
||||
target->sort_files = opts->sort_files;
|
||||
|
||||
target->replace_uid = opts->replace_uid ? 1 : 0;
|
||||
@ -882,16 +926,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
target->appendable = opts->appendable;
|
||||
|
||||
target->replace_timestamps = opts->replace_timestamps ? 1 : 0;
|
||||
target->timestamp = opts->replace_timestamps == 2 ?
|
||||
target->timestamp = opts->replace_timestamps == 2 ?
|
||||
opts->timestamp : target->now;
|
||||
|
||||
/* el-torito? */
|
||||
target->eltorito = (src->bootcat == NULL ? 0 : 1);
|
||||
target->catalog = src->bootcat;
|
||||
|
||||
/* default to locale charset */
|
||||
setlocale(LC_CTYPE, "");
|
||||
target->input_charset = strdup(nl_langinfo(CODESET));
|
||||
target->input_charset = strdup(iso_get_local_charset(0));
|
||||
if (target->input_charset == NULL) {
|
||||
iso_image_unref(src);
|
||||
free(target);
|
||||
@ -909,10 +951,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* 2. Based on those options, create needed writers: iso, joliet...
|
||||
* Each writer inits its structures and stores needed info into
|
||||
* target.
|
||||
* target.
|
||||
* If the writer needs an volume descriptor, it increments image
|
||||
* current block.
|
||||
* Finally, create Writer for files.
|
||||
@ -944,15 +986,16 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
if (ret < 0) {
|
||||
goto target_cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* create writer for El-Torito */
|
||||
if (target->eltorito) {
|
||||
ret = eltorito_writer_create(target);
|
||||
if (ret < 0) {
|
||||
goto target_cleanup;
|
||||
}
|
||||
el_torito_writer_index = target->nwriters - 1;
|
||||
}
|
||||
|
||||
|
||||
/* create writer for Joliet structure */
|
||||
if (target->joliet) {
|
||||
ret = joliet_writer_create(target);
|
||||
@ -960,7 +1003,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
goto target_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* create writer for ISO 9660:1999 structure */
|
||||
if (target->iso1999) {
|
||||
ret = iso1999_writer_create(target);
|
||||
@ -970,11 +1013,11 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
}
|
||||
|
||||
voldesc_size = target->curblock - target->ms_block - 16;
|
||||
|
||||
|
||||
/* Volume Descriptor Set Terminator */
|
||||
target->curblock++;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Create the writer for possible padding to ensure that in case of image
|
||||
* growing we can safety overwrite the first 64 KiB of image.
|
||||
*/
|
||||
@ -988,20 +1031,44 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
if (ret < 0) {
|
||||
goto target_cleanup;
|
||||
}
|
||||
file_src_writer_index = target->nwriters - 1;
|
||||
|
||||
/*
|
||||
* 3.
|
||||
* 3.
|
||||
* Call compute_data_blocks() in each Writer.
|
||||
* That function computes the size needed by its structures and
|
||||
* increments image current block propertly.
|
||||
*/
|
||||
for (i = 0; i < target->nwriters; ++i) {
|
||||
IsoImageWriter *writer = target->writers[i];
|
||||
|
||||
#define Libisofs_patch_ticket_145 yes
|
||||
#ifdef Libisofs_patch_ticket_145
|
||||
/* Delaying boot image patching until new LBA is known */
|
||||
if (i == el_torito_writer_index)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Exposing address of data start to IsoWriteOpts */
|
||||
if (i == file_src_writer_index) {
|
||||
opts->data_start_lba = target->curblock;
|
||||
}
|
||||
|
||||
ret = writer->compute_data_blocks(writer);
|
||||
if (ret < 0) {
|
||||
goto target_cleanup;
|
||||
}
|
||||
}
|
||||
#ifdef Libisofs_patch_ticket_145
|
||||
/* Now perform delayed image patching */
|
||||
if (el_torito_writer_index >= 0) {
|
||||
IsoImageWriter *writer = target->writers[el_torito_writer_index];
|
||||
ret = writer->compute_data_blocks(writer);
|
||||
if (ret < 0) {
|
||||
goto target_cleanup;
|
||||
}
|
||||
}
|
||||
#endif /* Libisofs_patch_ticket_145 */
|
||||
|
||||
/* create the ring buffer */
|
||||
ret = iso_ring_buffer_new(opts->fifo_size, &target->buffer);
|
||||
@ -1038,6 +1105,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
|
||||
}
|
||||
}
|
||||
|
||||
/* write the system area */
|
||||
ret = iso_write_system_area(target, opts->overwrite);
|
||||
if (ret < 0) {
|
||||
iso_msg_debug(target->image->id,
|
||||
"Error writing system area to overwrite buffer");
|
||||
goto target_cleanup;
|
||||
}
|
||||
|
||||
/* skip the first 16 blocks (system area) */
|
||||
buf = opts->overwrite + 16 * BLOCK_SIZE;
|
||||
voldesc_size *= BLOCK_SIZE;
|
||||
@ -1130,14 +1205,14 @@ static void bs_free_data(struct burn_source *bs)
|
||||
if (st < 4) {
|
||||
/* forces writer to stop if it is still running */
|
||||
iso_ring_buffer_reader_close(target->buffer, 0);
|
||||
|
||||
|
||||
/* wait until writer thread finishes */
|
||||
pthread_join(target->wthread, NULL);
|
||||
iso_msg_debug(target->image->id, "Writer thread joined");
|
||||
}
|
||||
|
||||
iso_msg_debug(target->image->id,
|
||||
"Ring buffer was %d times full and %d times empty",
|
||||
|
||||
iso_msg_debug(target->image->id,
|
||||
"Ring buffer was %d times full and %d times empty",
|
||||
iso_ring_buffer_get_times_full(target->buffer),
|
||||
iso_ring_buffer_get_times_empty(target->buffer));
|
||||
|
||||
@ -1153,9 +1228,9 @@ int bs_cancel(struct burn_source *bs)
|
||||
Ecma119Image *target = (Ecma119Image*)bs->data;
|
||||
|
||||
st = iso_ring_buffer_get_status(bs, &cap, &free);
|
||||
|
||||
|
||||
if (free == cap && (st == 2 || st == 3)) {
|
||||
/* image was already consumed */
|
||||
/* image was already consumed */
|
||||
iso_ring_buffer_reader_close(target->buffer, 0);
|
||||
} else {
|
||||
iso_msg_debug(target->image->id, "Reader thread being cancelled");
|
||||
@ -1176,7 +1251,7 @@ int bs_set_size(struct burn_source *bs, off_t size)
|
||||
{
|
||||
Ecma119Image *target = (Ecma119Image*)bs->data;
|
||||
|
||||
/*
|
||||
/*
|
||||
* just set the value to be returned by get_size. This is not used at
|
||||
* all by libisofs, it is here just for helping libburn to correctly pad
|
||||
* the image if needed.
|
||||
@ -1235,12 +1310,12 @@ int iso_write(Ecma119Image *target, void *buf, size_t count)
|
||||
if (ret > 0 && (target->total_size != (off_t) 0)){
|
||||
unsigned int kbw, kbt;
|
||||
int percent;
|
||||
|
||||
|
||||
target->bytes_written += (off_t) count;
|
||||
kbw = (unsigned int) (target->bytes_written >> 10);
|
||||
kbt = (unsigned int) (target->total_size >> 10);
|
||||
percent = (kbw * 100) / kbt;
|
||||
|
||||
|
||||
/* only report in 5% chunks */
|
||||
if (percent >= target->percent_written + 5) {
|
||||
iso_msg_debug(target->image->id, "Processed %u of %u KB (%d %%)",
|
||||
@ -1248,32 +1323,32 @@ int iso_write(Ecma119Image *target, void *buf, size_t count)
|
||||
target->percent_written = percent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iso_write_opts_new(IsoWriteOpts **opts, int profile)
|
||||
{
|
||||
IsoWriteOpts *wopts;
|
||||
|
||||
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (profile < 0 || profile > 2) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
|
||||
|
||||
wopts = calloc(1, sizeof(IsoWriteOpts));
|
||||
if (wopts == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
switch (profile) {
|
||||
case 0:
|
||||
wopts->level = 1;
|
||||
break;
|
||||
case 1:
|
||||
wopts->level = 2;
|
||||
wopts->level = 3;
|
||||
wopts->rockridge = 1;
|
||||
break;
|
||||
case 2:
|
||||
@ -1305,7 +1380,7 @@ void iso_write_opts_free(IsoWriteOpts *opts)
|
||||
if (opts == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
free(opts->output_charset);
|
||||
free(opts);
|
||||
}
|
||||
@ -1315,7 +1390,7 @@ int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level)
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (level != 1 && level != 2) {
|
||||
if (level != 1 && level != 2 && level != 3) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
opts->level = level;
|
||||
@ -1349,6 +1424,24 @@ int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable)
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_hardlinks(IsoWriteOpts *opts, int enable)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
opts->hardlinks = enable ? 1 : 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
opts->aaip = enable ? 1 : 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
@ -1430,6 +1523,42 @@ int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow)
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_rrip_version_1_10(IsoWriteOpts *opts, int oldvers)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
opts->rrip_version_1_10 = oldvers ? 1 : 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_rrip_1_10_px_ino(IsoWriteOpts *opts, int enable)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
opts->rrip_1_10_px_ino = enable ? 1 : 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_aaip_susp_1_10(IsoWriteOpts *opts, int oldvers)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
opts->aaip_susp_1_10 = oldvers ? 1 : 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_dir_rec_mtime(IsoWriteOpts *opts, int allow)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
opts->dir_rec_mtime = allow ? 1 : 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
@ -1577,3 +1706,13 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size)
|
||||
opts->fifo_size = fifo_size;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_write_opts_get_data_start(IsoWriteOpts *opts, uint32_t *data_start,
|
||||
int flag)
|
||||
{
|
||||
if(opts->data_start_lba == 0)
|
||||
return ISO_ERROR;
|
||||
*data_start = opts->data_start_lba;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -18,6 +19,18 @@
|
||||
|
||||
#define BLOCK_SIZE 2048
|
||||
|
||||
/*
|
||||
* Maximum file section size. Set to 4GB - 1 = 0xffffffff
|
||||
*/
|
||||
#define MAX_ISO_FILE_SECTION_SIZE 0xffffffff
|
||||
|
||||
/*
|
||||
* When a file need to be splitted in several sections, the maximum size
|
||||
* of such sections, but the last one. Set to a multiple of BLOCK_SIZE.
|
||||
* Default to 4GB - 2048 = 0xFFFFF800
|
||||
*/
|
||||
#define ISO_EXTENT_SIZE 0xFFFFF800
|
||||
|
||||
/**
|
||||
* Holds the options for the image generation.
|
||||
*/
|
||||
@ -30,14 +43,16 @@ struct iso_write_opts {
|
||||
unsigned int joliet :1;
|
||||
unsigned int iso1999 :1;
|
||||
|
||||
unsigned int aaip :1; /* whether to write eventual ACL and EAs */
|
||||
|
||||
/* allways write timestamps in GMT */
|
||||
unsigned int always_gmt :1;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Relaxed constraints. Setting any of these to 1 break the specifications,
|
||||
* but it is supposed to work on most moderns systems. Use with caution.
|
||||
* but it is supposed to work on most moderns systems. Use with caution.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Omit the version number (";1") at the end of the ISO-9660 identifiers.
|
||||
* Version numbers are usually not used.
|
||||
@ -45,7 +60,7 @@ struct iso_write_opts {
|
||||
unsigned int omit_version_numbers :1;
|
||||
|
||||
/**
|
||||
* Allow ISO-9660 directory hierarchy to be deeper than 8 levels.
|
||||
* Allow ISO-9660 directory hierarchy to be deeper than 8 levels.
|
||||
*/
|
||||
unsigned int allow_deep_paths :1;
|
||||
|
||||
@ -64,35 +79,74 @@ struct iso_write_opts {
|
||||
|
||||
/**
|
||||
* ISO-9660 forces filenames to have a ".", that separates file name from
|
||||
* extension. libisofs adds it if original filename doesn't has one. Set
|
||||
* extension. libisofs adds it if original filename doesn't has one. Set
|
||||
* this to 1 to prevent this behavior
|
||||
*/
|
||||
unsigned int no_force_dots :1;
|
||||
|
||||
|
||||
/**
|
||||
* Allow lowercase characters in ISO-9660 filenames. By default, only
|
||||
* uppercase characters, numbers and a few other characters are allowed.
|
||||
* Allow lowercase characters in ISO-9660 filenames. By default, only
|
||||
* uppercase characters, numbers and a few other characters are allowed.
|
||||
*/
|
||||
unsigned int allow_lowercase :1;
|
||||
|
||||
|
||||
/**
|
||||
* Allow all ASCII characters to be appear on an ISO-9660 filename. Note
|
||||
* that "/" and "\0" characters are never allowed, even in RR names.
|
||||
*/
|
||||
unsigned int allow_full_ascii :1;
|
||||
|
||||
|
||||
/**
|
||||
* Allow all characters to be part of Volume and Volset identifiers on
|
||||
* the Primary Volume Descriptor. This breaks ISO-9660 contraints, but
|
||||
* should work on modern systems.
|
||||
*/
|
||||
unsigned int relaxed_vol_atts :1;
|
||||
|
||||
|
||||
/**
|
||||
* Allow paths in the Joliet tree to have more than 240 characters.
|
||||
*/
|
||||
unsigned int joliet_longer_paths :1;
|
||||
|
||||
/**
|
||||
* Write Rock Ridge info as of specification RRIP-1.10 rather than
|
||||
* RRIP-1.12: signature "RRIP_1991A" rather than "IEEE_1282",
|
||||
* field PX without file serial number
|
||||
*/
|
||||
unsigned int rrip_version_1_10 :1;
|
||||
|
||||
/**
|
||||
* Write field PX with file serial number even with RRIP-1.10
|
||||
*/
|
||||
unsigned int rrip_1_10_px_ino :1;
|
||||
|
||||
/**
|
||||
* See iso_write_opts_set_hardlinks()
|
||||
*/
|
||||
unsigned int hardlinks:1;
|
||||
|
||||
/**
|
||||
* Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12.
|
||||
* I.e. without announcing it by an ER field and thus without the need
|
||||
* to preceed the RRIP fields by an ES and to preceed the AA field by ES.
|
||||
* This saves bytes and might avoid problems with readers which dislike
|
||||
* ER fields other than the ones for RRIP.
|
||||
* On the other hand, SUSP 1.12 frowns on such unannounced extensions
|
||||
* and prescribes ER and ES. It does this since year 1994.
|
||||
*
|
||||
* In effect only if above flag .aaip is set to 1.
|
||||
*/
|
||||
unsigned int aaip_susp_1_10 :1;
|
||||
|
||||
/**
|
||||
* Store as ECMA-119 Directory Record timestamp the mtime of the source
|
||||
* rather than the image creation time. (The ECMA-119 prescription seems
|
||||
* to expect that we do have a creation timestamp with the source.
|
||||
* mkisofs writes mtimes and the result seems more suitable if mounted
|
||||
* without Rock Ridge support.)
|
||||
*/
|
||||
unsigned int dir_rec_mtime :1;
|
||||
|
||||
/** If files should be sorted based on their weight. */
|
||||
unsigned int sort_files :1;
|
||||
|
||||
@ -102,7 +156,7 @@ struct iso_write_opts {
|
||||
* If 0, the corresponding attribute will be kept as setted in the IsoNode.
|
||||
* Unless you have changed it, it corresponds to the value on disc, so it
|
||||
* is suitable for backup purposes. If set to 1, the corresponding attrib.
|
||||
* will be changed by a default suitable value. Finally, if you set it to
|
||||
* will be changed by a default suitable value. Finally, if you set it to
|
||||
* 2, the attrib. will be changed with the value specified in the options
|
||||
* below. Note that for mode attributes, only the permissions are set, the
|
||||
* file type remains unchanged.
|
||||
@ -133,68 +187,76 @@ struct iso_write_opts {
|
||||
|
||||
/**
|
||||
* This flags control the type of the image to create. Libisofs support
|
||||
* two kind of images: stand-alone and appendable.
|
||||
*
|
||||
* two kind of images: stand-alone and appendable.
|
||||
*
|
||||
* A stand-alone image is an image that is valid alone, and that can be
|
||||
* mounted by its own. This is the kind of image you will want to create
|
||||
* in most cases. A stand-alone image can be burned in an empty CD or DVD,
|
||||
* or write to an .iso file for future burning or distribution.
|
||||
*
|
||||
*
|
||||
* On the other side, an appendable image is not self contained, it refers
|
||||
* to serveral files that are stored outside the image. Its usage is for
|
||||
* multisession discs, where you add data in a new session, while the
|
||||
* previous session data can still be accessed. In those cases, the old
|
||||
* multisession discs, where you add data in a new session, while the
|
||||
* previous session data can still be accessed. In those cases, the old
|
||||
* data is not written again. Instead, the new image refers to it, and thus
|
||||
* it's only valid when appended to the original. Note that in those cases
|
||||
* the image will be written after the original, and thus you will want
|
||||
* to use a ms_block greater than 0.
|
||||
*
|
||||
* Note that if you haven't import a previous image (by means of
|
||||
* to use a ms_block greater than 0.
|
||||
*
|
||||
* Note that if you haven't import a previous image (by means of
|
||||
* iso_image_import()), the image will always be a stand-alone image, as
|
||||
* there is no previous data to refer to.
|
||||
*/
|
||||
unsigned int appendable : 1;
|
||||
|
||||
|
||||
/**
|
||||
* Start block of the image. It is supposed to be the lba where the first
|
||||
* block of the image will be written on disc. All references inside the
|
||||
* ISO image will take this into account, thus providing a mountable image.
|
||||
*
|
||||
* For appendable images, that are written to a new session, you should
|
||||
*
|
||||
* For appendable images, that are written to a new session, you should
|
||||
* pass here the lba of the next writable address on disc.
|
||||
*
|
||||
* In stand alone images this is usually 0. However, you may want to
|
||||
*
|
||||
* In stand alone images this is usually 0. However, you may want to
|
||||
* provide a different ms_block if you don't plan to burn the image in the
|
||||
* first session on disc, such as in some CD-Extra disc whether the data
|
||||
* image is written in a new session after some audio tracks.
|
||||
* image is written in a new session after some audio tracks.
|
||||
*/
|
||||
uint32_t ms_block;
|
||||
|
||||
/**
|
||||
* When not NULL, it should point to a buffer of at least 64KiB, where
|
||||
* When not NULL, it should point to a buffer of at least 64KiB, where
|
||||
* libisofs will write the contents that should be written at the beginning
|
||||
* of a overwriteable media, to grow the image. The growing of an image is
|
||||
* a way, used by first time in growisofs by Andy Polyakov, to allow the
|
||||
* appending of new data to non-multisession media, such as DVD+RW, in the
|
||||
* same way you append a new session to a multisession disc, i.e., without
|
||||
* need to write again the contents of the previous image.
|
||||
*
|
||||
* need to write again the contents of the previous image.
|
||||
*
|
||||
* Note that if you want this kind of image growing, you will also need to
|
||||
* set appendable to "1" and provide a valid ms_block after the previous
|
||||
* image.
|
||||
*
|
||||
* You should initialize the buffer either with 0s, or with the contents of
|
||||
* the first blocks of the image you're growing. In most cases, 0 is good
|
||||
*
|
||||
* You should initialize the buffer either with 0s, or with the contents of
|
||||
* the first blocks of the image you're growing. In most cases, 0 is good
|
||||
* enought.
|
||||
*/
|
||||
uint8_t *overwrite;
|
||||
|
||||
|
||||
/**
|
||||
* Size, in number of blocks, of the FIFO buffer used between the writer
|
||||
* thread and the burn_source. You have to provide at least a 32 blocks
|
||||
* buffer.
|
||||
*/
|
||||
size_t fifo_size;
|
||||
|
||||
/**
|
||||
* This is not an option setting but a value returned after the options
|
||||
* were used to compute the layout of the image.
|
||||
* It tells the LBA of the first plain file data block in the image.
|
||||
*/
|
||||
uint32_t data_start_lba;
|
||||
|
||||
};
|
||||
|
||||
typedef struct ecma119_image Ecma119Image;
|
||||
@ -217,6 +279,10 @@ struct ecma119_image
|
||||
unsigned int eltorito :1;
|
||||
unsigned int iso1999 :1;
|
||||
|
||||
unsigned int hardlinks:1; /* see iso_write_opts_set_hardlinks() */
|
||||
|
||||
unsigned int aaip :1; /* see iso_write_opts_set_aaip() */
|
||||
|
||||
/* allways write timestamps in GMT */
|
||||
unsigned int always_gmt :1;
|
||||
|
||||
@ -228,13 +294,25 @@ struct ecma119_image
|
||||
unsigned int no_force_dots :1;
|
||||
unsigned int allow_lowercase :1;
|
||||
unsigned int allow_full_ascii :1;
|
||||
|
||||
|
||||
unsigned int relaxed_vol_atts : 1;
|
||||
|
||||
|
||||
/** Allow paths on Joliet tree to be larger than 240 bytes */
|
||||
unsigned int joliet_longer_paths :1;
|
||||
|
||||
/*
|
||||
/** Write old fashioned RRIP-1.10 rather than RRIP-1.12 */
|
||||
unsigned int rrip_version_1_10 :1;
|
||||
|
||||
/** Write field PX with file serial number even with RRIP-1.10 */
|
||||
unsigned int rrip_1_10_px_ino :1;
|
||||
|
||||
/* Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12. */
|
||||
unsigned int aaip_susp_1_10 :1;
|
||||
|
||||
/* Store in ECMA-119 timestamp mtime of source */
|
||||
unsigned int dir_rec_mtime :1;
|
||||
|
||||
/*
|
||||
* Mode replace. If one of these flags is set, the correspodent values are
|
||||
* replaced with values below.
|
||||
*/
|
||||
@ -251,16 +329,22 @@ struct ecma119_image
|
||||
time_t timestamp;
|
||||
|
||||
/**
|
||||
* if sort files or not. Sorting is based of the weight of each file
|
||||
* if sort files or not. Sorting is based of the weight of each file
|
||||
*/
|
||||
int sort_files;
|
||||
|
||||
|
||||
#ifndef Libisofs_hardlink_matcheR
|
||||
|
||||
/* ts A90508 : <<< this is on its way out */
|
||||
/**
|
||||
* In the CD, each file must have an unique inode number. So each
|
||||
* time we add a new file, this is incremented.
|
||||
*/
|
||||
ino_t ino;
|
||||
|
||||
#endif /* ! Libisofs_hardlink_matcheR */
|
||||
|
||||
char *input_charset;
|
||||
char *output_charset;
|
||||
|
||||
@ -282,7 +366,7 @@ struct ecma119_image
|
||||
*/
|
||||
uint32_t curblock;
|
||||
|
||||
/*
|
||||
/*
|
||||
* number of dirs in ECMA-119 tree, computed together with dir position,
|
||||
* and needed for path table computation in a efficient way
|
||||
*/
|
||||
@ -290,7 +374,7 @@ struct ecma119_image
|
||||
uint32_t path_table_size;
|
||||
uint32_t l_path_table_pos;
|
||||
uint32_t m_path_table_pos;
|
||||
|
||||
|
||||
/*
|
||||
* Joliet related information
|
||||
*/
|
||||
@ -299,7 +383,7 @@ struct ecma119_image
|
||||
uint32_t joliet_path_table_size;
|
||||
uint32_t joliet_l_path_table_pos;
|
||||
uint32_t joliet_m_path_table_pos;
|
||||
|
||||
|
||||
/*
|
||||
* ISO 9660:1999 related information
|
||||
*/
|
||||
@ -308,7 +392,7 @@ struct ecma119_image
|
||||
uint32_t iso1999_path_table_size;
|
||||
uint32_t iso1999_l_path_table_pos;
|
||||
uint32_t iso1999_m_path_table_pos;
|
||||
|
||||
|
||||
/*
|
||||
* El-Torito related information
|
||||
*/
|
||||
@ -322,10 +406,10 @@ struct ecma119_image
|
||||
* data. These padding blocks are added by libisofs to improve the handling
|
||||
* of image growing. The idea is that the first blocks in the image are
|
||||
* overwritten with the volume descriptors of the new image. These first
|
||||
* blocks usually correspond to the volume descriptors and directory
|
||||
* structure of the old image, and can be safety overwritten. However,
|
||||
* with very small images they might correspond to valid data. To ensure
|
||||
* this never happens, what we do is to add padding bytes, to ensure no
|
||||
* blocks usually correspond to the volume descriptors and directory
|
||||
* structure of the old image, and can be safety overwritten. However,
|
||||
* with very small images they might correspond to valid data. To ensure
|
||||
* this never happens, what we do is to add padding bytes, to ensure no
|
||||
* file data is written in the first 64 KiB, that are the bytes we usually
|
||||
* overwrite.
|
||||
*/
|
||||
@ -473,4 +557,5 @@ struct ecma119_vol_desc_terminator
|
||||
uint8_t reserved BP(8, 2048);
|
||||
};
|
||||
|
||||
|
||||
#endif /*LIBISO_ECMA119_H_*/
|
||||
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -61,18 +62,18 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||
}
|
||||
} else {
|
||||
if (img->max_37_char_filenames) {
|
||||
isoname = iso_r_fileid(ascii_name, 36, relaxed,
|
||||
isoname = iso_r_fileid(ascii_name, 36, relaxed,
|
||||
img->no_force_dots ? 0 : 1);
|
||||
} else if (img->iso_level == 1) {
|
||||
if (relaxed) {
|
||||
isoname = iso_r_fileid(ascii_name, 11, relaxed,
|
||||
isoname = iso_r_fileid(ascii_name, 11, relaxed,
|
||||
img->no_force_dots ? 0 : 1);
|
||||
} else {
|
||||
isoname = iso_1_fileid(ascii_name);
|
||||
}
|
||||
} else {
|
||||
if (relaxed) {
|
||||
isoname = iso_r_fileid(ascii_name, 30, relaxed,
|
||||
isoname = iso_r_fileid(ascii_name, 30, relaxed,
|
||||
img->no_force_dots ? 0 : 1);
|
||||
} else {
|
||||
isoname = iso_2_fileid(ascii_name);
|
||||
@ -84,7 +85,7 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||
*name = isoname;
|
||||
return ISO_SUCCESS;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* only possible if mem error, as check for empty names is done
|
||||
* in public tree
|
||||
*/
|
||||
@ -106,10 +107,38 @@ int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node)
|
||||
ecma->node = iso;
|
||||
iso_node_ref(iso);
|
||||
|
||||
/* TODO #00009 : add true support for harlinks and inode numbers */
|
||||
ecma->nlink = 1;
|
||||
|
||||
#ifndef Libisofs_hardlink_matcheR
|
||||
|
||||
/* ts A90503 : This is obsolete with Libisofs_hardlink_matcheR
|
||||
which will later hand out image inode numbers for all. */
|
||||
|
||||
#ifdef Libisofs_hardlink_prooF
|
||||
|
||||
/* Looking only for valid ISO image inode numbers. */
|
||||
{
|
||||
unsigned int fs_id;
|
||||
dev_t dev_id;
|
||||
int ret;
|
||||
|
||||
ret = iso_node_get_id(iso, &fs_id, &dev_id, &(ecma->ino), 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else if (ret == 0) {
|
||||
/* What has not got a valid ISO image inode yet, gets it now. */
|
||||
ecma->ino = img_give_ino_number(img->image, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* Libisofs_hardlink_prooF */
|
||||
|
||||
/* TODO #00009 : add true support for harlinks and inode numbers */
|
||||
ecma->ino = ++img->ino;
|
||||
|
||||
#endif /* ! Libisofs_hardlink_prooF */
|
||||
#endif /* ! Libisofs_hardlink_matcheR */
|
||||
|
||||
*node = ecma;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
@ -129,7 +158,7 @@ int create_dir(Ecma119Image *img, IsoDir *iso, Ecma119Node **node)
|
||||
if (children == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
dir_info = calloc(1, sizeof(struct ecma119_dir_info));
|
||||
if (dir_info == NULL) {
|
||||
free(children);
|
||||
@ -161,10 +190,13 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
|
||||
off_t size;
|
||||
|
||||
size = iso_stream_get_size(iso->stream);
|
||||
if (size > (off_t)0xffffffff) {
|
||||
return iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && img->iso_level != 3) {
|
||||
char *ipath = iso_tree_get_node_path(ISO_NODE(iso));
|
||||
ret = iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
"File \"%s\" can't be added to image because "
|
||||
"is greater than 4GB", iso->node.name);
|
||||
"is greater than 4GB", ipath);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iso_file_src_create(img, iso, &src);
|
||||
@ -174,9 +206,9 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
|
||||
|
||||
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
/*
|
||||
* the src doesn't need to be freed, it is free together with
|
||||
* the Ecma119Image
|
||||
* the Ecma119Image
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
@ -203,9 +235,9 @@ int create_boot_cat(Ecma119Image *img, IsoBoot *iso, Ecma119Node **node)
|
||||
|
||||
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
/*
|
||||
* the src doesn't need to be freed, it is free together with
|
||||
* the Ecma119Image
|
||||
* the Ecma119Image
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
@ -267,10 +299,10 @@ void ecma119_node_free(Ecma119Node *node)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @return
|
||||
* 1 success, 0 node ignored, < 0 error
|
||||
*
|
||||
*
|
||||
*/
|
||||
static
|
||||
int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
@ -296,15 +328,21 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
max_path = pathlen + 1 + (iso_name ? strlen(iso_name) : 0);
|
||||
if (!image->rockridge) {
|
||||
if ((iso->type == LIBISO_DIR && depth > 8) && !image->allow_deep_paths) {
|
||||
free(iso_name);
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
return iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
"File \"%s\" can't be added, because directory depth "
|
||||
"is greater than 8.", iso->name);
|
||||
} else if (max_path > 255 && !image->allow_longer_paths) {
|
||||
"is greater than 8.", ipath);
|
||||
free(iso_name);
|
||||
return iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
free(ipath);
|
||||
return ret;
|
||||
} else if (max_path > 255 && !image->allow_longer_paths) {
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
"File \"%s\" can't be added, because path length "
|
||||
"is greater than 255 characters", iso->name);
|
||||
"is greater than 255 characters", ipath);
|
||||
free(iso_name);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,19 +355,23 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
ret = create_symlink(image, (IsoSymlink*)iso, &node);
|
||||
} else {
|
||||
/* symlinks are only supported when RR is enabled */
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
|
||||
"File \"%s\" ignored. Symlinks need RockRidge extensions.",
|
||||
iso->name);
|
||||
"File \"%s\" ignored. Symlinks need RockRidge extensions.",
|
||||
ipath);
|
||||
free(ipath);
|
||||
}
|
||||
break;
|
||||
case LIBISO_SPECIAL:
|
||||
if (image->rockridge) {
|
||||
ret = create_special(image, (IsoSpecial*)iso, &node);
|
||||
} else {
|
||||
/* symlinks are only supported when RR is enabled */
|
||||
/* special files are only supported when RR is enabled */
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
|
||||
"File \"%s\" ignored. Special files need RockRidge extensions.",
|
||||
iso->name);
|
||||
"File \"%s\" ignored. Special files need RockRidge extensions.",
|
||||
ipath);
|
||||
free(ipath);
|
||||
}
|
||||
break;
|
||||
case LIBISO_BOOT:
|
||||
@ -338,8 +380,7 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
} else {
|
||||
/* log and ignore */
|
||||
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
|
||||
"El-Torito catalog found on a image without El-Torito.",
|
||||
iso->name);
|
||||
"El-Torito catalog found on a image without El-Torito.");
|
||||
}
|
||||
break;
|
||||
case LIBISO_DIR:
|
||||
@ -430,9 +471,9 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
|
||||
nchildren = dir->info.dir->nchildren;
|
||||
children = dir->info.dir->children;
|
||||
|
||||
|
||||
/* a hash table will temporary hold the names, for fast searching */
|
||||
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||
(compare_function_t)strcmp, &table);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -463,7 +504,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
}
|
||||
|
||||
/*
|
||||
* A max of 7 characters is good enought, it allows handling up to
|
||||
* A max of 7 characters is good enought, it allows handling up to
|
||||
* 9,999,999 files with same name. We can increment this to
|
||||
* max_name_len, but the int_pow() function must then be modified
|
||||
* to return a bigger integer.
|
||||
@ -480,8 +521,8 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
dot = strrchr(full_name, '.');
|
||||
if (dot != NULL && children[i]->type != ECMA119_DIR) {
|
||||
|
||||
/*
|
||||
* File (not dir) with extension
|
||||
/*
|
||||
* File (not dir) with extension
|
||||
* Note that we don't need to check for placeholders, as
|
||||
* tree reparent happens later, so no placeholders can be
|
||||
* here at this time.
|
||||
@ -491,26 +532,26 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
name = full_name;
|
||||
ext = dot + 1;
|
||||
|
||||
/*
|
||||
/*
|
||||
* For iso level 1 we force ext len to be 3, as name
|
||||
* can't grow on the extension space
|
||||
* can't grow on the extension space
|
||||
*/
|
||||
extlen = (max_file_len == 12) ? 3 : strlen(ext);
|
||||
max = max_file_len - extlen - 1 - digits;
|
||||
if (max <= 0) {
|
||||
/* this can happen if extension is too long */
|
||||
if (extlen + max > 3) {
|
||||
/*
|
||||
/*
|
||||
* reduce extension len, to give name an extra char
|
||||
* note that max is negative or 0
|
||||
* note that max is negative or 0
|
||||
*/
|
||||
extlen = extlen + max - 1;
|
||||
ext[extlen] = '\0';
|
||||
max = max_file_len - extlen - 1 - digits;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* error, we don't support extensions < 3
|
||||
* This can't happen with current limit of digits.
|
||||
* This can't happen with current limit of digits.
|
||||
*/
|
||||
ret = ISO_ERROR;
|
||||
goto mangle_cleanup;
|
||||
@ -572,7 +613,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
children[k]->iso_name = new;
|
||||
iso_htable_add(table, new, new);
|
||||
|
||||
/*
|
||||
/*
|
||||
* if we change a name we need to sort again children
|
||||
* at the end
|
||||
*/
|
||||
@ -603,7 +644,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
|
||||
|
||||
mangle_cleanup : ;
|
||||
iso_htable_destroy(table, NULL);
|
||||
return ret;
|
||||
@ -658,7 +699,7 @@ int mangle_tree(Ecma119Image *img, int recurse)
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a placeholder for a relocated
|
||||
* dir.
|
||||
*
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5 for details
|
||||
*/
|
||||
static
|
||||
@ -672,10 +713,10 @@ int create_placeholder(Ecma119Node *parent, Ecma119Node *real,
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* TODO
|
||||
* If real is a dir, while placeholder is a file, ISO name restricctions
|
||||
* are different, what to do?
|
||||
* If real is a dir, while placeholder is a file, ISO name restricctions
|
||||
* are different, what to do?
|
||||
*/
|
||||
ret->iso_name = strdup(real->iso_name);
|
||||
if (ret->iso_name == NULL) {
|
||||
@ -708,10 +749,10 @@ size_t max_child_name_len(Ecma119Node *dir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Relocates a directory, as specified in Rock Ridge Specification
|
||||
* Relocates a directory, as specified in Rock Ridge Specification
|
||||
* (see IEEE P1282, section 4.1.5). This is needed when the number of levels
|
||||
* on a directory hierarchy exceeds 8, or the length of a path is higher
|
||||
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
|
||||
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
|
||||
*/
|
||||
static
|
||||
int reparent(Ecma119Node *child, Ecma119Node *parent)
|
||||
@ -743,7 +784,7 @@ int reparent(Ecma119Node *child, Ecma119Node *parent)
|
||||
/* add the child to its new parent */
|
||||
child->parent = parent;
|
||||
parent->info.dir->nchildren++;
|
||||
parent->info.dir->children = realloc(parent->info.dir->children,
|
||||
parent->info.dir->children = realloc(parent->info.dir->children,
|
||||
sizeof(void*) * parent->info.dir->nchildren);
|
||||
parent->info.dir->children[parent->info.dir->nchildren - 1] = child;
|
||||
return ISO_SUCCESS;
|
||||
@ -754,7 +795,7 @@ int reparent(Ecma119Node *child, Ecma119Node *parent)
|
||||
* - the depth is at most 8
|
||||
* - each path length is at most 255 characters
|
||||
* This restriction is imposed by ECMA-119 specification (ECMA-119, 6.8.2.1).
|
||||
*
|
||||
*
|
||||
* @param dir
|
||||
* Dir we are currently processing
|
||||
* @param level
|
||||
@ -778,9 +819,9 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* we are appended to the root's children now, so there is no
|
||||
* need to recurse (the root will hit us again)
|
||||
* need to recurse (the root will hit us again)
|
||||
*/
|
||||
} else {
|
||||
size_t i;
|
||||
@ -799,6 +840,174 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen)
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* @param flag
|
||||
* bit0= recursion
|
||||
* bit1= count nodes rather than fill them into *nodes
|
||||
* @return
|
||||
* <0 error
|
||||
* bit0= saw ino == 0
|
||||
* bit1= saw ino != 0
|
||||
*/
|
||||
static
|
||||
int make_node_array(Ecma119Image *img, Ecma119Node *dir,
|
||||
Ecma119Node **nodes, size_t nodes_size, size_t *node_count,
|
||||
int flag)
|
||||
{
|
||||
int ret, result = 0;
|
||||
size_t i;
|
||||
Ecma119Node *child;
|
||||
|
||||
if (!(flag & 1)) {
|
||||
*node_count = 0;
|
||||
if (!(flag & 2)) {
|
||||
/* Register the tree root node */
|
||||
if (*node_count >= nodes_size) {
|
||||
iso_msg_submit(img->image->id, ISO_ASSERT_FAILURE, 0,
|
||||
"Programming error: Overflow of hardlink sort array");
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
nodes[*node_count] = dir;
|
||||
}
|
||||
result|= (dir->ino == 0 ? 1 : 2);
|
||||
(*node_count)++;
|
||||
}
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
child = dir->info.dir->children[i];
|
||||
if (!(flag & 2)) {
|
||||
if (*node_count >= nodes_size) {
|
||||
iso_msg_submit(img->image->id, ISO_ASSERT_FAILURE, 0,
|
||||
"Programming error: Overflow of hardlink sort array");
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
nodes[*node_count] = child;
|
||||
}
|
||||
result|= (child->ino == 0 ? 1 : 2);
|
||||
(*node_count)++;
|
||||
|
||||
if (child->type == ECMA119_DIR) {
|
||||
ret = make_node_array(img, child,
|
||||
nodes, nodes_size, node_count, flag | 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* @param flag
|
||||
* bit0= compare stat properties and attributes
|
||||
* bit1= treat all nodes with image ino == 0 as unique
|
||||
*/
|
||||
static
|
||||
int ecma119_node_cmp_flag(const void *v1, const void *v2, int flag)
|
||||
{
|
||||
int ret;
|
||||
Ecma119Node *n1, *n2;
|
||||
|
||||
n1 = *((Ecma119Node **) v1);
|
||||
n2 = *((Ecma119Node **) v2);
|
||||
if (n1 == n2)
|
||||
return 0;
|
||||
|
||||
ret = iso_node_cmp_flag(n1->node, n2->node, flag & (1 | 2));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int ecma119_node_cmp_hard(const void *v1, const void *v2)
|
||||
{
|
||||
return ecma119_node_cmp_flag(v1, v2, 1);
|
||||
}
|
||||
|
||||
static
|
||||
int ecma119_node_cmp_nohard(const void *v1, const void *v2)
|
||||
{
|
||||
return ecma119_node_cmp_flag(v1, v2, 1 | 2);
|
||||
}
|
||||
|
||||
static
|
||||
int family_set_ino(Ecma119Image *img, Ecma119Node **nodes, size_t family_start,
|
||||
size_t next_family, ino_t img_ino, ino_t prev_ino, int flag)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (img_ino != 0) {
|
||||
/* Check whether this is the same img_ino as in the previous
|
||||
family (e.g. by property divergence of imported hardlink).
|
||||
*/
|
||||
if (img_ino == prev_ino)
|
||||
img_ino = 0;
|
||||
}
|
||||
if (img_ino == 0) {
|
||||
img_ino = img_give_ino_number(img->image, 0);
|
||||
}
|
||||
for (i = family_start; i < next_family; i++) {
|
||||
nodes[i]->ino = img_ino;
|
||||
nodes[i]->nlink = next_family - family_start;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int match_hardlinks(Ecma119Image *img, Ecma119Node *dir, int flag)
|
||||
{
|
||||
int ret;
|
||||
size_t nodes_size = 0, node_count = 0, i, family_start;
|
||||
Ecma119Node **nodes = NULL;
|
||||
unsigned int fs_id;
|
||||
dev_t dev_id;
|
||||
ino_t img_ino = 0, prev_ino = 0;
|
||||
|
||||
ret = make_node_array(img, dir, nodes, nodes_size, &node_count, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nodes_size = node_count;
|
||||
nodes = (Ecma119Node **) calloc(sizeof(Ecma119Node *), nodes_size);
|
||||
if (nodes == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
ret = make_node_array(img, dir, nodes, nodes_size, &node_count, 0);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
|
||||
/* Sort according to id tuples, IsoFileSrc identity, properties, xattr. */
|
||||
if (img->hardlinks)
|
||||
qsort(nodes, node_count, sizeof(Ecma119Node *), ecma119_node_cmp_hard);
|
||||
else
|
||||
qsort(nodes, node_count, sizeof(Ecma119Node *),
|
||||
ecma119_node_cmp_nohard);
|
||||
|
||||
/* Hand out image inode numbers to all Ecma119Node.ino == 0 .
|
||||
Same sorting rank gets same inode number.
|
||||
Split those image inode number families where the sort criterion
|
||||
differs.
|
||||
*/
|
||||
iso_node_get_id(nodes[0]->node, &fs_id, &dev_id, &img_ino, 1);
|
||||
family_start = 0;
|
||||
for (i = 1; i < node_count; i++) {
|
||||
if (ecma119_node_cmp_hard(nodes + (i - 1), nodes + i) == 0) {
|
||||
/* Still in same ino family */
|
||||
if (img_ino == 0) { /* Just in case any member knows its img_ino */
|
||||
iso_node_get_id(nodes[0]->node, &fs_id, &dev_id, &img_ino, 1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
family_set_ino(img, nodes, family_start, i, img_ino, prev_ino, 0);
|
||||
prev_ino = img_ino;
|
||||
iso_node_get_id(nodes[i]->node, &fs_id, &dev_id, &img_ino, 1);
|
||||
family_start = i;
|
||||
}
|
||||
family_set_ino(img, nodes, family_start, i, img_ino, prev_ino, 0);
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (nodes != NULL)
|
||||
free((char *) nodes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ecma119_tree_create(Ecma119Image *img)
|
||||
{
|
||||
int ret;
|
||||
@ -814,6 +1023,16 @@ int ecma119_tree_create(Ecma119Image *img)
|
||||
}
|
||||
img->root = root;
|
||||
|
||||
#ifdef Libisofs_hardlink_matcheR
|
||||
|
||||
iso_msg_debug(img->image->id, "Matching hardlinks...");
|
||||
ret = match_hardlinks(img, img->root, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* ! Libisofs_hardlink_matcheR */
|
||||
|
||||
iso_msg_debug(img->image->id, "Sorting the low level tree...");
|
||||
sort_tree(root);
|
||||
|
||||
@ -831,7 +1050,7 @@ int ecma119_tree_create(Ecma119Image *img)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* and we need to remangle the root directory, as the function
|
||||
* above could insert new directories into the root.
|
||||
* Note that recurse = 0, as we don't need to recurse.
|
||||
|
@ -62,8 +62,10 @@ struct ecma119_node
|
||||
|
||||
IsoNode *node; /*< reference to the iso node */
|
||||
|
||||
/* TODO #00009 : add true support for harlinks and inode numbers */
|
||||
/* >>> ts A90501 : Shouldn't this be uint32_t
|
||||
as this is what PX will take ? */
|
||||
ino_t ino;
|
||||
|
||||
nlink_t nlink;
|
||||
|
||||
/**< file, symlink, special, directory or placeholder */
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -26,7 +26,7 @@ struct boot_info_table {
|
||||
uint8_t bi_file BP(5, 8); /* LBA of boot file */
|
||||
uint8_t bi_length BP(9, 12); /* Length of boot file */
|
||||
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
|
||||
uint8_t bi_reserved BP(17, 56); /* Reserved */
|
||||
uint8_t bi_reserved BP(17, 56); /* Reserved */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -60,19 +60,19 @@ struct hard_disc_mbr {
|
||||
*/
|
||||
void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment)
|
||||
{
|
||||
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||
if (bootimg->type != 0)
|
||||
return;
|
||||
bootimg->load_seg = segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of sectors (512b) to be load at load segment during
|
||||
* the initial boot procedure. This is only for no emulation boot images,
|
||||
* the initial boot procedure. This is only for no emulation boot images,
|
||||
* and is a NOP for other image types.
|
||||
*/
|
||||
void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors)
|
||||
{
|
||||
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||
if (bootimg->type != 0)
|
||||
return;
|
||||
bootimg->load_size = sectors;
|
||||
}
|
||||
@ -93,7 +93,61 @@ void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
|
||||
*/
|
||||
void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
|
||||
{
|
||||
bootimg->isolinux = 1;
|
||||
bootimg->isolinux_options |= 0x01;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies options for IsoLinux boot images. This should only be used with
|
||||
* isolinux boot images.
|
||||
*
|
||||
* @param options
|
||||
* bitmask style flag. The following values are defined:
|
||||
*
|
||||
* bit 0 -> 1 to path the image, 0 to not
|
||||
* Patching the image involves the writting of a 56 bytes
|
||||
* boot information table at offset 8 of the boot image file.
|
||||
* The original boot image file won't be modified. This is needed
|
||||
* to allow isolinux images to be bootable.
|
||||
* bit 1 -> 1 to generate an hybrid image, 0 to not
|
||||
* An hybrid image is a boot image that boots from either CD/DVD
|
||||
* media or from USB sticks. For that, you should use an isolinux
|
||||
* image that supports hybrid mode. Recent images support this.
|
||||
* @return
|
||||
* 1 if success, < 0 on error
|
||||
* @since 0.6.12
|
||||
*/
|
||||
int el_torito_set_isolinux_options(ElToritoBootImage *bootimg, int options, int flag)
|
||||
{
|
||||
bootimg->isolinux_options = (options & 0x03);
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/* TODO getter for boot image properties should be exposed
|
||||
* useful when reading discs */
|
||||
int el_torito_get_boot_media_type(const ElToritoBootImage *bootimg)
|
||||
{
|
||||
if (bootimg) {
|
||||
switch (bootimg->type) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return ELTORITO_FLOPPY_EMUL;
|
||||
break;
|
||||
case 4:
|
||||
return ELTORITO_HARD_DISC_EMUL;
|
||||
break;
|
||||
case 0:
|
||||
return ELTORITO_NO_EMUL;
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
@ -109,7 +163,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
|
||||
if (boot) {
|
||||
*boot = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* check if the name is valid */
|
||||
if (!iso_node_is_valid_name(name)) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
@ -162,7 +216,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
static
|
||||
int create_image(IsoImage *image, const char *image_path,
|
||||
enum eltorito_boot_media_type type,
|
||||
struct el_torito_boot_image **bootimg)
|
||||
@ -182,18 +236,18 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
if (ret == 0) {
|
||||
return ISO_NODE_DOESNT_EXIST;
|
||||
}
|
||||
|
||||
|
||||
if (imgfile->type != LIBISO_FILE) {
|
||||
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||
}
|
||||
|
||||
|
||||
stream = ((IsoFile*)imgfile)->stream;
|
||||
|
||||
|
||||
/* we need to read the image at least two times */
|
||||
if (!iso_stream_is_repeatable(stream)) {
|
||||
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||
}
|
||||
|
||||
|
||||
switch (type) {
|
||||
case ELTORITO_FLOPPY_EMUL:
|
||||
switch (iso_stream_get_size(stream)) {
|
||||
@ -211,9 +265,9 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
"Invalid image size %d Kb. Must be one of 1.2, 1.44"
|
||||
"or 2.88 Mb", iso_stream_get_size(stream) / 1024);
|
||||
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
/* it seems that for floppy emulation we need to load
|
||||
/* it seems that for floppy emulation we need to load
|
||||
* a single sector (512b) */
|
||||
load_sectors = 1;
|
||||
break;
|
||||
@ -222,7 +276,7 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
size_t i;
|
||||
struct hard_disc_mbr mbr;
|
||||
int used_partition;
|
||||
|
||||
|
||||
/* read the MBR on disc and get the type of the partition */
|
||||
ret = iso_stream_open(stream);
|
||||
if (ret < 0) {
|
||||
@ -237,14 +291,14 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
"Can't read MBR from image file.");
|
||||
return ret < 0 ? ret : ISO_FILE_READ_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* check valid MBR signature */
|
||||
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
|
||||
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||
"Invalid MBR. Wrong signature.");
|
||||
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||
}
|
||||
|
||||
|
||||
/* ensure single partition */
|
||||
used_partition = -1;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
@ -252,7 +306,7 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
/* it's an used partition */
|
||||
if (used_partition != -1) {
|
||||
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||
"Invalid MBR. At least 2 partitions: %d and "
|
||||
"Invalid MBR. At least 2 partitions: %d and "
|
||||
"%d, are being used\n", used_partition, i);
|
||||
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||
} else
|
||||
@ -262,15 +316,15 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
partition_type = mbr.partition[used_partition].type;
|
||||
}
|
||||
boot_media_type = 4;
|
||||
|
||||
|
||||
/* only load the MBR */
|
||||
load_sectors = 1;
|
||||
break;
|
||||
case ELTORITO_NO_EMUL:
|
||||
boot_media_type = 0;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
boot = calloc(1, sizeof(struct el_torito_boot_image));
|
||||
if (boot == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
@ -281,11 +335,11 @@ int create_image(IsoImage *image, const char *image_path,
|
||||
boot->type = boot_media_type;
|
||||
boot->load_size = load_sectors;
|
||||
boot->partition_type = partition_type;
|
||||
|
||||
|
||||
if (bootimg) {
|
||||
*bootimg = boot;
|
||||
}
|
||||
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -298,14 +352,14 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
ElToritoBootImage *boot_image= NULL;
|
||||
IsoBoot *cat_node= NULL;
|
||||
|
||||
|
||||
if (image == NULL || image_path == NULL || catalog_path == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (image->bootcat != NULL) {
|
||||
return ISO_IMAGE_ALREADY_BOOTABLE;
|
||||
}
|
||||
|
||||
|
||||
/* create the node for the catalog */
|
||||
{
|
||||
IsoDir *parent;
|
||||
@ -314,8 +368,8 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
|
||||
if (catdir == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* get both the dir and the name */
|
||||
|
||||
/* get both the dir and the name */
|
||||
catname = strrchr(catdir, '/');
|
||||
if (catname == NULL) {
|
||||
free(catdir);
|
||||
@ -345,13 +399,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* create the boot image */
|
||||
ret = create_image(image, image_path, type, &boot_image);
|
||||
if (ret < 0) {
|
||||
goto boot_image_cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* creates the catalog with the given image */
|
||||
catalog = malloc(sizeof(struct el_torito_boot_catalog));
|
||||
if (catalog == NULL) {
|
||||
@ -362,13 +416,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
|
||||
catalog->node = cat_node;
|
||||
iso_node_ref((IsoNode*)cat_node);
|
||||
image->bootcat = catalog;
|
||||
|
||||
|
||||
if (boot) {
|
||||
*boot = boot_image;
|
||||
}
|
||||
|
||||
|
||||
return ISO_SUCCESS;
|
||||
|
||||
|
||||
boot_image_cleanup:;
|
||||
if (cat_node) {
|
||||
iso_node_take((IsoNode*)cat_node);
|
||||
@ -383,32 +437,32 @@ boot_image_cleanup:;
|
||||
|
||||
/**
|
||||
* Get El-Torito boot image of an ISO image, if any.
|
||||
*
|
||||
*
|
||||
* This can be useful, for example, to check if a volume read from a previous
|
||||
* session or an existing image is bootable. It can also be useful to get
|
||||
* the image and catalog tree nodes. An application would want those, for
|
||||
* the image and catalog tree nodes. An application would want those, for
|
||||
* example, to prevent the user removing it.
|
||||
*
|
||||
*
|
||||
* Both nodes are owned by libisofs and should not be freed. You can get your
|
||||
* own ref with iso_node_ref(). You can can also check if the node is already
|
||||
* on the tree by getting its parent (note that when reading El-Torito info
|
||||
* from a previous image, the nodes might not be on the tree even if you haven't
|
||||
* removed them). Remember that you'll need to get a new ref
|
||||
* (with iso_node_ref()) before inserting them again to the tree, and probably
|
||||
* own ref with iso_node_ref(). You can can also check if the node is already
|
||||
* on the tree by getting its parent (note that when reading El-Torito info
|
||||
* from a previous image, the nodes might not be on the tree even if you haven't
|
||||
* removed them). Remember that you'll need to get a new ref
|
||||
* (with iso_node_ref()) before inserting them again to the tree, and probably
|
||||
* you will also need to set the name or permissions.
|
||||
*
|
||||
*
|
||||
* @param image
|
||||
* The image from which to get the boot image.
|
||||
* @param boot
|
||||
* If not NULL, it will be filled with a pointer to the boot image, if
|
||||
* any. That object is owned by the IsoImage and should not be freed by
|
||||
* If not NULL, it will be filled with a pointer to the boot image, if
|
||||
* any. That object is owned by the IsoImage and should not be freed by
|
||||
* the user, nor dereferenced once the last reference to the IsoImage was
|
||||
* disposed via iso_image_unref().
|
||||
* @param imgnode
|
||||
* @param imgnode
|
||||
* When not NULL, it will be filled with the image tree node. No extra ref
|
||||
* is added, you can use iso_node_ref() to get one if you need it.
|
||||
* @param catnode
|
||||
* When not NULL, it will be filled with the catnode tree node. No extra
|
||||
* @param catnode
|
||||
* When not NULL, it will be filled with the catnode tree node. No extra
|
||||
* ref is added, you can use iso_node_ref() to get one if you need it.
|
||||
* @return
|
||||
* 1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
|
||||
@ -423,7 +477,7 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
|
||||
if (image->bootcat == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ok, image is bootable */
|
||||
if (boot) {
|
||||
*boot = image->bootcat->image;
|
||||
@ -438,8 +492,8 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the El-Torito bootable image.
|
||||
*
|
||||
* Removes the El-Torito bootable image.
|
||||
*
|
||||
* The IsoBoot node that acts as placeholder for the catalog is also removed
|
||||
* for the image tree, if there.
|
||||
* If the image is not bootable (don't have el-torito boot image) this function
|
||||
@ -449,13 +503,13 @@ void iso_image_remove_boot_image(IsoImage *image)
|
||||
{
|
||||
if (image == NULL || image->bootcat == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* remove catalog node from its parent
|
||||
* (the reference will be disposed next)
|
||||
|
||||
/*
|
||||
* remove catalog node from its parent
|
||||
* (the reference will be disposed next)
|
||||
*/
|
||||
iso_node_take((IsoNode*)image->bootcat->node);
|
||||
|
||||
|
||||
/* free boot catalog and image, including references to nodes */
|
||||
el_torito_boot_catalog_free(image->bootcat);
|
||||
image->bootcat = NULL;
|
||||
@ -464,11 +518,11 @@ void iso_image_remove_boot_image(IsoImage *image)
|
||||
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
|
||||
{
|
||||
struct el_torito_boot_image *image;
|
||||
|
||||
|
||||
if (cat == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
image = cat->image;
|
||||
iso_node_unref((IsoNode*)image->image);
|
||||
free(image);
|
||||
@ -486,19 +540,19 @@ struct catalog_stream
|
||||
int offset; /* -1 if stream is not openned */
|
||||
};
|
||||
|
||||
static void
|
||||
static void
|
||||
write_validation_entry(uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int checksum;
|
||||
|
||||
struct el_torito_validation_entry *ve =
|
||||
|
||||
struct el_torito_validation_entry *ve =
|
||||
(struct el_torito_validation_entry*)buf;
|
||||
ve->header_id[0] = 1;
|
||||
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
|
||||
ve->key_byte1[0] = 0x55;
|
||||
ve->key_byte2[0] = 0xAA;
|
||||
|
||||
|
||||
/* calculate the checksum, to ensure sum of all words is 0 */
|
||||
checksum = 0;
|
||||
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
|
||||
@ -515,9 +569,9 @@ static void
|
||||
write_section_entry(uint8_t *buf, Ecma119Image *t)
|
||||
{
|
||||
struct el_torito_boot_image *img;
|
||||
struct el_torito_section_entry *se =
|
||||
struct el_torito_section_entry *se =
|
||||
(struct el_torito_section_entry*)buf;
|
||||
|
||||
|
||||
img = t->catalog->image;
|
||||
|
||||
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
|
||||
@ -525,7 +579,7 @@ write_section_entry(uint8_t *buf, Ecma119Image *t)
|
||||
iso_lsb(se->load_seg, img->load_seg, 2);
|
||||
se->system_type[0] = img->partition_type;
|
||||
iso_lsb(se->sec_count, img->load_size, 2);
|
||||
iso_lsb(se->block, t->bootimg->block, 4);
|
||||
iso_lsb(se->block, t->bootimg->sections[0].block, 4);
|
||||
}
|
||||
|
||||
static
|
||||
@ -536,13 +590,13 @@ int catalog_open(IsoStream *stream)
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
|
||||
if (data->offset != -1) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
|
||||
memset(data->buffer, 0, BLOCK_SIZE);
|
||||
|
||||
|
||||
/* fill the buffer with the catalog contents */
|
||||
write_validation_entry(data->buffer);
|
||||
|
||||
@ -561,9 +615,9 @@ int catalog_close(IsoStream *stream)
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
data->offset = -1;
|
||||
return ISO_SUCCESS;
|
||||
@ -587,11 +641,11 @@ int catalog_read(IsoStream *stream, void *buf, size_t count)
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
|
||||
len = MIN(count, BLOCK_SIZE - data->offset);
|
||||
memcpy(buf, data->buffer + data->offset, len);
|
||||
return len;
|
||||
@ -606,7 +660,7 @@ int catalog_is_repeatable(IsoStream *stream)
|
||||
/**
|
||||
* fs_id will be the id reserved for El-Torito
|
||||
* dev_id will be 0 for catalog, 1 for boot image (if needed)
|
||||
* we leave ino_id for future use when we support multiple boot images
|
||||
* we leave ino_id for future use when we support multiple boot images
|
||||
*/
|
||||
static
|
||||
void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
@ -617,12 +671,6 @@ void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
*ino_id = 0;
|
||||
}
|
||||
|
||||
static
|
||||
char *catalog_get_name(IsoStream *stream)
|
||||
{
|
||||
return strdup("El-Torito Boot Catalog");
|
||||
}
|
||||
|
||||
static
|
||||
void catalog_free(IsoStream *stream)
|
||||
{
|
||||
@ -630,18 +678,19 @@ void catalog_free(IsoStream *stream)
|
||||
}
|
||||
|
||||
IsoStreamIface catalog_stream_class = {
|
||||
0,
|
||||
"boot",
|
||||
catalog_open,
|
||||
catalog_close,
|
||||
catalog_get_size,
|
||||
catalog_read,
|
||||
catalog_is_repeatable,
|
||||
catalog_get_id,
|
||||
catalog_get_name,
|
||||
catalog_free
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an IsoStream for writing El-Torito catalog for a given target.
|
||||
* Create an IsoStream for writing El-Torito catalog for a given target.
|
||||
*/
|
||||
static
|
||||
int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
|
||||
@ -680,17 +729,17 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
|
||||
int ret;
|
||||
IsoFileSrc *file;
|
||||
IsoStream *stream;
|
||||
|
||||
|
||||
if (target == NULL || src == NULL || target->catalog == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
if (target->cat != NULL) {
|
||||
/* catalog file src already created */
|
||||
*src = target->cat;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
file = malloc(sizeof(IsoFileSrc));
|
||||
if (file == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
@ -701,10 +750,11 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
|
||||
free(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* fill fields */
|
||||
file->prev_img = 0; /* TODO allow copy of old img catalog???? */
|
||||
file->block = 0; /* to be filled later */
|
||||
file->nsections = 1;
|
||||
file->sections = calloc(1, sizeof(struct iso_file_section));
|
||||
file->sort_weight = 1000; /* slightly high */
|
||||
file->stream = stream;
|
||||
|
||||
@ -720,10 +770,104 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
|
||||
|
||||
/******************* EL-TORITO WRITER *******************************/
|
||||
|
||||
/**
|
||||
* Patch an isolinux boot image.
|
||||
*
|
||||
* @return
|
||||
* 1 on success, 0 error (but continue), < 0 error
|
||||
*/
|
||||
static
|
||||
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
|
||||
{
|
||||
struct boot_info_table *info;
|
||||
uint32_t checksum;
|
||||
size_t offset;
|
||||
|
||||
if (imgsize < 64) {
|
||||
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
|
||||
"Isolinux image too small. We won't patch it.");
|
||||
}
|
||||
|
||||
/* compute checksum, as the the sum of all 32 bit words in boot image
|
||||
* from offset 64 */
|
||||
checksum = 0;
|
||||
offset = (size_t) 64;
|
||||
|
||||
while (offset <= imgsize - 4) {
|
||||
checksum += iso_read_lsb(buf + offset, 4);
|
||||
offset += 4;
|
||||
}
|
||||
if (offset != imgsize) {
|
||||
/*
|
||||
* file length not multiple of 4
|
||||
* empty space in isofs is padded with zero;
|
||||
* assume same for last dword
|
||||
*/
|
||||
checksum += iso_read_lsb(buf + offset, imgsize - offset);
|
||||
}
|
||||
|
||||
/* patch boot info table */
|
||||
info = (struct boot_info_table*)(buf + 8);
|
||||
/*memset(info, 0, sizeof(struct boot_info_table));*/
|
||||
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
|
||||
iso_lsb(info->bi_file, t->bootimg->sections[0].block, 4);
|
||||
iso_lsb(info->bi_length, imgsize, 4);
|
||||
iso_lsb(info->bi_csum, checksum, 4);
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
{
|
||||
/* nothing to do, the files are written by the file writer */
|
||||
/*
|
||||
* We have nothing to write, but if we need to patch an isolinux image,
|
||||
* this is a good place to do so.
|
||||
*/
|
||||
Ecma119Image *t;
|
||||
int ret;
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
t = writer->target;
|
||||
|
||||
if (t->catalog->image->isolinux_options & 0x01) {
|
||||
/* we need to patch the image */
|
||||
size_t size;
|
||||
uint8_t *buf;
|
||||
IsoStream *new = NULL;
|
||||
IsoStream *original = t->bootimg->stream;
|
||||
size = (size_t) iso_stream_get_size(original);
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
ret = iso_stream_open(original);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = iso_stream_read(original, buf, size);
|
||||
iso_stream_close(original);
|
||||
if (ret != size) {
|
||||
return (ret < 0) ? ret : ISO_FILE_READ_ERROR;
|
||||
}
|
||||
|
||||
/* ok, patch the read buffer */
|
||||
ret = patch_boot_image(buf, t, size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* replace the original stream with a memory stream that reads from
|
||||
* the patched buffer */
|
||||
ret = iso_memory_stream_new(buf, size, &new);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
t->bootimg->stream = new;
|
||||
iso_stream_unref(original);
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -751,106 +895,15 @@ int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
memcpy(vol.std_identifier, "CD001", 5);
|
||||
vol.vol_desc_version[0] = 1;
|
||||
memcpy(vol.boot_sys_id, "EL TORITO SPECIFICATION", 23);
|
||||
iso_lsb(vol.boot_catalog, t->cat->block, 4);
|
||||
|
||||
return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
|
||||
}
|
||||
iso_lsb(vol.boot_catalog, t->cat->sections[0].block, 4);
|
||||
|
||||
/**
|
||||
* Patch an isolinux boot image.
|
||||
*
|
||||
* @return
|
||||
* 1 on success, 0 error (but continue), < 0 error
|
||||
*/
|
||||
static
|
||||
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
|
||||
{
|
||||
struct boot_info_table *info;
|
||||
uint32_t checksum;
|
||||
size_t offset;
|
||||
|
||||
if (imgsize < 64) {
|
||||
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
|
||||
"Isolinux image too small. We won't patch it.");
|
||||
}
|
||||
|
||||
/* compute checksum, as the the sum of all 32 bit words in boot image
|
||||
* from offset 64 */
|
||||
checksum = 0;
|
||||
offset = (size_t) 64;
|
||||
|
||||
while (offset <= imgsize - 4) {
|
||||
checksum += iso_read_lsb(buf + offset, 4);
|
||||
offset += 4;
|
||||
}
|
||||
if (offset != imgsize) {
|
||||
/* file length not multiple of 4 */
|
||||
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
|
||||
"Unexpected isolinux image length. Patch might not work.");
|
||||
}
|
||||
|
||||
/* patch boot info table */
|
||||
info = (struct boot_info_table*)(buf + 8);
|
||||
/*memset(info, 0, sizeof(struct boot_info_table));*/
|
||||
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
|
||||
iso_lsb(info->bi_file, t->bootimg->block, 4);
|
||||
iso_lsb(info->bi_length, imgsize, 4);
|
||||
iso_lsb(info->bi_csum, checksum, 4);
|
||||
return ISO_SUCCESS;
|
||||
return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
|
||||
}
|
||||
|
||||
static
|
||||
int eltorito_writer_write_data(IsoImageWriter *writer)
|
||||
{
|
||||
/*
|
||||
* We have nothing to write, but if we need to patch an isolinux image,
|
||||
* this is a good place to do so.
|
||||
*/
|
||||
Ecma119Image *t;
|
||||
int ret;
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
t = writer->target;
|
||||
|
||||
if (t->catalog->image->isolinux) {
|
||||
/* we need to patch the image */
|
||||
size_t size;
|
||||
uint8_t *buf;
|
||||
IsoStream *new = NULL;
|
||||
IsoStream *original = t->bootimg->stream;
|
||||
size = (size_t) iso_stream_get_size(original);
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
ret = iso_stream_open(original);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = iso_stream_read(original, buf, size);
|
||||
iso_stream_close(original);
|
||||
if (ret != size) {
|
||||
return (ret < 0) ? ret : ISO_FILE_READ_ERROR;
|
||||
}
|
||||
|
||||
/* ok, patch the read buffer */
|
||||
ret = patch_boot_image(buf, t, size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* replace the original stream with a memory stream that reads from
|
||||
* the patched buffer */
|
||||
ret = iso_memory_stream_new(buf, size, &new);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
t->bootimg->stream = new;
|
||||
iso_stream_unref(original);
|
||||
}
|
||||
/* nothing to do, the files are written by the file writer */
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -883,7 +936,7 @@ int eltorito_writer_create(Ecma119Image *target)
|
||||
/* add this writer to image */
|
||||
target->writers[target->nwriters++] = writer;
|
||||
|
||||
/*
|
||||
/*
|
||||
* get catalog and image file sources.
|
||||
* Note that the catalog may be already added, when creating the low
|
||||
* level ECMA-119 tree.
|
||||
@ -900,9 +953,9 @@ int eltorito_writer_create(Ecma119Image *target)
|
||||
return ret;
|
||||
}
|
||||
target->bootimg = src;
|
||||
|
||||
|
||||
/* if we have selected to patch the image, it needs to be copied always */
|
||||
if (target->catalog->image->isolinux) {
|
||||
if (target->catalog->image->isolinux_options & 0x01) {
|
||||
src->prev_img = 0;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -35,7 +35,12 @@ struct el_torito_boot_image {
|
||||
IsoFile *image;
|
||||
|
||||
unsigned int bootable:1; /**< If the entry is bootable. */
|
||||
unsigned int isolinux:1; /**< If the image will be patched */
|
||||
/**
|
||||
* isolinux options
|
||||
* bit 0 -> whether to patch image
|
||||
* bit 1 -> whether to create isolinux image
|
||||
*/
|
||||
unsigned int isolinux_options:2;
|
||||
unsigned char type; /**< The type of image */
|
||||
unsigned char partition_type; /**< type of partition for HD-emul images */
|
||||
short load_seg; /**< Load segment for the initial boot image. */
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -12,38 +12,28 @@
|
||||
#include "writer.h"
|
||||
#include "messages.h"
|
||||
#include "image.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
int iso_file_src_cmp(const void *n1, const void *n2)
|
||||
{
|
||||
int ret;
|
||||
const IsoFileSrc *f1, *f2;
|
||||
unsigned int fs_id1, fs_id2;
|
||||
dev_t dev_id1, dev_id2;
|
||||
ino_t ino_id1, ino_id2;
|
||||
|
||||
if (n1 == n2) {
|
||||
return 0; /* Normally just a shortcut.
|
||||
But important if Libisofs_file_src_cmp_non_zerO */
|
||||
}
|
||||
|
||||
f1 = (const IsoFileSrc *)n1;
|
||||
f2 = (const IsoFileSrc *)n2;
|
||||
|
||||
iso_stream_get_id(f1->stream, &fs_id1, &dev_id1, &ino_id1);
|
||||
iso_stream_get_id(f2->stream, &fs_id2, &dev_id2, &ino_id2);
|
||||
|
||||
if (fs_id1 < fs_id2) {
|
||||
return -1;
|
||||
} else if (fs_id1 > fs_id2) {
|
||||
return 1;
|
||||
} else {
|
||||
/* files belong to the same fs */
|
||||
if (dev_id1 > dev_id2) {
|
||||
return -1;
|
||||
} else if (dev_id1 < dev_id2) {
|
||||
return 1;
|
||||
} else {
|
||||
/* files belong to same device in same fs */
|
||||
return (ino_id1 < ino_id2) ? -1 : (ino_id1 > ino_id2) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
ret = iso_stream_cmp_ino(f1->stream, f2->stream, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
@ -60,20 +50,45 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
|
||||
iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id);
|
||||
|
||||
fsrc = malloc(sizeof(IsoFileSrc));
|
||||
fsrc = calloc(1, sizeof(IsoFileSrc));
|
||||
if (fsrc == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* fill key and other atts */
|
||||
fsrc->prev_img = file->msblock ? 1 : 0;
|
||||
fsrc->block = file->msblock;
|
||||
fsrc->prev_img = file->from_old_session;
|
||||
if (file->from_old_session && img->appendable) {
|
||||
/*
|
||||
* On multisession discs we keep file sections from old image.
|
||||
*/
|
||||
int ret = iso_file_get_old_image_sections(file, &(fsrc->nsections),
|
||||
&(fsrc->sections), 0);
|
||||
if (ret < 0) {
|
||||
free(fsrc);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
* For new files, or for image copy, we compute our own file sections.
|
||||
* Block and size of each section will be filled later.
|
||||
*/
|
||||
off_t section_size = iso_stream_get_size(file->stream);
|
||||
if (section_size > (off_t) MAX_ISO_FILE_SECTION_SIZE) {
|
||||
fsrc->nsections = DIV_UP(section_size - (off_t) MAX_ISO_FILE_SECTION_SIZE,
|
||||
(off_t)ISO_EXTENT_SIZE) + 1;
|
||||
} else {
|
||||
fsrc->nsections = 1;
|
||||
}
|
||||
fsrc->sections = calloc(fsrc->nsections, sizeof(struct iso_file_section));
|
||||
}
|
||||
fsrc->sort_weight = file->sort_weight;
|
||||
fsrc->stream = file->stream;
|
||||
|
||||
/* insert the filesrc in the tree */
|
||||
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
|
||||
if (ret <= 0) {
|
||||
free(fsrc->sections);
|
||||
free(fsrc);
|
||||
return ret;
|
||||
}
|
||||
@ -83,12 +98,12 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
|
||||
/**
|
||||
* Add a given IsoFileSrc to the given image target.
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
* being written several times to image. If you call again this function
|
||||
* with a node that refers to the same source file, the previously
|
||||
* created one will be returned.
|
||||
*
|
||||
*
|
||||
* @param img
|
||||
* The image where this file is to be written
|
||||
* @param new
|
||||
@ -96,7 +111,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
* @param src
|
||||
* Will be filled with a pointer to the IsoFileSrc really present in
|
||||
* the tree. It could be different than new if the same file already
|
||||
* exists in the tree.
|
||||
* exists in the tree.
|
||||
* @return
|
||||
* 1 on success, 0 if file already exists on tree, < 0 error
|
||||
*/
|
||||
@ -107,7 +122,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
|
||||
if (img == NULL || new == NULL || src == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
|
||||
/* insert the filesrc in the tree */
|
||||
ret = iso_rbtree_insert(img->files, new, (void**)src);
|
||||
return ret;
|
||||
@ -116,6 +131,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
|
||||
void iso_file_src_free(void *node)
|
||||
{
|
||||
iso_stream_unref(((IsoFileSrc*)node)->stream);
|
||||
free(((IsoFileSrc*)node)->sections);
|
||||
free(node);
|
||||
}
|
||||
|
||||
@ -159,7 +175,7 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
} else {
|
||||
inc_item = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* store the filesrcs in a array */
|
||||
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size);
|
||||
if (filelist == NULL) {
|
||||
@ -173,8 +189,23 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
|
||||
/* fill block value */
|
||||
for (i = 0; i < size; ++i) {
|
||||
int extent = 0;
|
||||
IsoFileSrc *file = filelist[i];
|
||||
file->block = t->curblock;
|
||||
|
||||
off_t section_size = iso_stream_get_size(file->stream);
|
||||
for (extent = 0; extent < file->nsections - 1; ++extent) {
|
||||
file->sections[extent].block = t->curblock + extent *
|
||||
(ISO_EXTENT_SIZE / BLOCK_SIZE);
|
||||
file->sections[extent].size = ISO_EXTENT_SIZE;
|
||||
section_size -= (off_t) ISO_EXTENT_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* final section
|
||||
*/
|
||||
file->sections[extent].block = t->curblock + extent * (ISO_EXTENT_SIZE / BLOCK_SIZE);
|
||||
file->sections[extent].size = (uint32_t)section_size;
|
||||
|
||||
t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
|
||||
}
|
||||
|
||||
@ -243,7 +274,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
Ecma119Image *t;
|
||||
IsoFileSrc *file;
|
||||
IsoFileSrc **filelist;
|
||||
char *name;
|
||||
char name[PATH_MAX];
|
||||
char buffer[BLOCK_SIZE];
|
||||
|
||||
if (writer == NULL) {
|
||||
@ -258,23 +289,18 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
i = 0;
|
||||
while ((file = filelist[i++]) != NULL) {
|
||||
|
||||
/*
|
||||
* TODO WARNING
|
||||
* when we allow files greater than 4GB, current DIV_UP implementation
|
||||
* can overflow!!
|
||||
*/
|
||||
uint32_t nblocks = DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
|
||||
|
||||
res = filesrc_open(file);
|
||||
iso_stream_get_file_name(file->stream, name);
|
||||
if (res < 0) {
|
||||
/*
|
||||
/*
|
||||
* UPS, very ugly error, the best we can do is just to write
|
||||
* 0's to image
|
||||
*/
|
||||
name = iso_stream_get_name(file->stream);
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||
"File \"%s\" can't be opened. Filling with 0s.", name);
|
||||
free(name);
|
||||
if (res < 0) {
|
||||
return res; /* aborted due to error severity */
|
||||
}
|
||||
@ -288,11 +314,10 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
}
|
||||
continue;
|
||||
} else if (res > 1) {
|
||||
name = iso_stream_get_name(file->stream);
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"Size of file \"%s\" has changed. It will be %s", name,
|
||||
(res == 2 ? "truncated" : "padded with 0's"));
|
||||
free(name);
|
||||
if (res < 0) {
|
||||
filesrc_close(file);
|
||||
return res; /* aborted due to error severity */
|
||||
@ -300,9 +325,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
}
|
||||
#ifdef LIBISOFS_VERBOSE_DEBUG
|
||||
else {
|
||||
name = iso_stream_get_name(file->stream);
|
||||
iso_msg_debug(t->image->id, "Writing file %s", name);
|
||||
free(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -326,7 +349,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
|
||||
if (b < nblocks) {
|
||||
/* premature end of file, due to error or eof */
|
||||
char *name = iso_stream_get_name(file->stream);
|
||||
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||
if (res < 0) {
|
||||
/* error */
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||
@ -336,12 +359,11 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"Premature end of file %s.", name);
|
||||
}
|
||||
free(name);
|
||||
|
||||
if (res < 0) {
|
||||
return res; /* aborted due error severity */
|
||||
}
|
||||
|
||||
|
||||
/* fill with 0s */
|
||||
iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"Filling with 0");
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_FILESRC_H_
|
||||
@ -17,7 +17,11 @@
|
||||
struct Iso_File_Src
|
||||
{
|
||||
unsigned int prev_img :1; /**< if the file comes from a previous image */
|
||||
uint32_t block; /**< Block where this file will be written on image */
|
||||
|
||||
/** File Sections of the file in the image */
|
||||
struct iso_file_section *sections;
|
||||
int nsections;
|
||||
|
||||
int sort_weight;
|
||||
IsoStream *stream;
|
||||
};
|
||||
@ -26,12 +30,12 @@ int iso_file_src_cmp(const void *n1, const void *n2);
|
||||
|
||||
/**
|
||||
* Create a new IsoFileSrc to get data from a specific IsoFile.
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
* being written several times to image. If you call again this function
|
||||
* with a node that refers to the same source file, the previously
|
||||
* created one will be returned. No new IsoFileSrc is created in that case.
|
||||
*
|
||||
*
|
||||
* @param img
|
||||
* The image where this file is to be written
|
||||
* @param file
|
||||
@ -45,12 +49,12 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
|
||||
|
||||
/**
|
||||
* Add a given IsoFileSrc to the given image target.
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
* being written several times to image. If you call again this function
|
||||
* with a node that refers to the same source file, the previously
|
||||
* created one will be returned.
|
||||
*
|
||||
*
|
||||
* @param img
|
||||
* The image where this file is to be written
|
||||
* @param new
|
||||
@ -58,7 +62,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
|
||||
* @param src
|
||||
* Will be filled with a pointer to the IsoFileSrc really present in
|
||||
* the tree. It could be different than new if the same file already
|
||||
* exists in the tree.
|
||||
* exists in the tree.
|
||||
* @return
|
||||
* 1 on success, 0 if file already exists on tree, < 0 error
|
||||
*/
|
||||
@ -76,7 +80,7 @@ off_t iso_file_src_get_size(IsoFileSrc *file);
|
||||
|
||||
/**
|
||||
* Create a Writer for file contents.
|
||||
*
|
||||
*
|
||||
* It takes care of written the files in the correct order.
|
||||
*/
|
||||
int iso_file_src_writer_create(Ecma119Image *target);
|
||||
|
66
libisofs/filter.c
Normal file
66
libisofs/filter.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "filter.h"
|
||||
#include "node.h"
|
||||
|
||||
|
||||
void iso_filter_ref(FilterContext *filter)
|
||||
{
|
||||
++filter->refcount;
|
||||
}
|
||||
|
||||
void iso_filter_unref(FilterContext *filter)
|
||||
{
|
||||
if (--filter->refcount == 0) {
|
||||
filter->free(filter);
|
||||
free(filter);
|
||||
}
|
||||
}
|
||||
|
||||
int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag)
|
||||
{
|
||||
int ret;
|
||||
IsoStream *original, *filtered;
|
||||
if (file == NULL || filter == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
original = file->stream;
|
||||
|
||||
if (!iso_stream_is_repeatable(original)) {
|
||||
/* TODO use custom error */
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
|
||||
ret = filter->get_filter(filter, original, &filtered);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
iso_stream_unref(original);
|
||||
file->stream = filtered;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int iso_file_remove_filter(IsoFile *file, int flag)
|
||||
{
|
||||
IsoStream *file_stream, *input_stream;
|
||||
|
||||
file_stream = file->stream;
|
||||
input_stream = iso_stream_get_input_stream(file_stream, 0);
|
||||
if (input_stream == NULL)
|
||||
return 0;
|
||||
file->stream = input_stream;
|
||||
iso_stream_ref(input_stream); /* Protect against _unref(file_stream) */
|
||||
iso_stream_unref(file_stream);
|
||||
return 1;
|
||||
}
|
||||
|
75
libisofs/filter.h
Normal file
75
libisofs/filter.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_FILTER_H_
|
||||
#define LIBISO_FILTER_H_
|
||||
|
||||
/*
|
||||
* Definitions of filters.
|
||||
*/
|
||||
|
||||
|
||||
/* dev_id for stream identification */
|
||||
|
||||
/* libisofs/filters/xor_encrypt.c */
|
||||
#define XOR_ENCRYPT_DEV_ID 1
|
||||
|
||||
/* libisofs/filters/external.c */
|
||||
#define ISO_FILTER_EXTERNAL_DEV_ID 2
|
||||
|
||||
/* libisofs/filters/zisofs.c */
|
||||
#define ISO_FILTER_ZISOFS_DEV_ID 3
|
||||
|
||||
/* libisofs/filters/gzip.c */
|
||||
#define ISO_FILTER_GZIP_DEV_ID 4
|
||||
|
||||
|
||||
typedef struct filter_context FilterContext;
|
||||
|
||||
struct filter_context {
|
||||
int version; /* reserved for future usage, set to 0 */
|
||||
int refcount;
|
||||
|
||||
/** filter specific shared data */
|
||||
void *data;
|
||||
|
||||
/**
|
||||
* Factory method to create a filtered stream from another stream.
|
||||
*
|
||||
* @param original
|
||||
* The original stream to be filtered. If the filter needs a ref to
|
||||
* it (most cases), it should take a ref to it with iso_stream_ref().
|
||||
* @param filtered
|
||||
* Will be filled with the filtered IsoStream (reference belongs to
|
||||
* caller).
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
*/
|
||||
int (*get_filter)(FilterContext *filter, IsoStream *original,
|
||||
IsoStream **filtered);
|
||||
|
||||
/**
|
||||
* Free implementation specific data. Should never be called by user.
|
||||
* Use iso_filter_unref() instead.
|
||||
*/
|
||||
void (*free)(FilterContext *filter);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param flag
|
||||
* Reserved for future usage, pass always 0 for now.
|
||||
* TODO in a future a different value can mean filter caching, where
|
||||
* the filter is applied once and the filtered file is stored in a temp
|
||||
* dir. This prevent filter to be applied several times.
|
||||
*/
|
||||
int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag);
|
||||
|
||||
void iso_filter_ref(FilterContext *filter);
|
||||
void iso_filter_unref(FilterContext *filter);
|
||||
|
||||
#endif /*LIBISO_FILTER_H_*/
|
780
libisofs/filters/external.c
Normal file
780
libisofs/filters/external.c
Normal file
@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*
|
||||
* It implements a filter facility which can pipe a IsoStream into an external
|
||||
* process, read its output and forward it as IsoStream output to an IsoFile.
|
||||
* The external processes get started according to an IsoExternalFilterCommand
|
||||
* which is described in libisofs.h.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../libisofs.h"
|
||||
#include "../filter.h"
|
||||
#include "../fsource.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef Libisofs_external_filters_selecT
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A filter that starts an external process and uses its stdin and stdout
|
||||
* for classical pipe filtering.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Individual runtime properties exist only as long as the stream is opened.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int send_fd;
|
||||
int recv_fd;
|
||||
pid_t pid;
|
||||
off_t in_counter;
|
||||
int in_eof;
|
||||
off_t out_counter;
|
||||
int out_eof;
|
||||
uint8_t pipebuf[2048]; /* buffers in case of EAGAIN on write() */
|
||||
int pipebuf_fill;
|
||||
} ExternalFilterRuntime;
|
||||
|
||||
|
||||
static
|
||||
int extf_running_new(ExternalFilterRuntime **running, int send_fd, int recv_fd,
|
||||
pid_t child_pid, int flag)
|
||||
{
|
||||
ExternalFilterRuntime *o;
|
||||
*running = o = calloc(sizeof(ExternalFilterRuntime), 1);
|
||||
if (o == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
o->send_fd = send_fd;
|
||||
o->recv_fd = recv_fd;
|
||||
o->pid = child_pid;
|
||||
o->in_counter = 0;
|
||||
o->in_eof = 0;
|
||||
o->out_counter = 0;
|
||||
o->out_eof = 0;
|
||||
memset(o->pipebuf, 0, sizeof(o->pipebuf));
|
||||
o->pipebuf_fill = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The data payload of an individual IsoStream from External Filter
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ino_t id;
|
||||
|
||||
IsoStream *orig;
|
||||
|
||||
IsoExternalFilterCommand *cmd;
|
||||
|
||||
off_t size; /* -1 means that the size is unknown yet */
|
||||
|
||||
ExternalFilterRuntime *running; /* is non-NULL when open */
|
||||
|
||||
} ExternalFilterStreamData;
|
||||
|
||||
|
||||
/* Each individual ExternalFilterStreamData needs a unique id number. */
|
||||
/* >>> This is very suboptimal:
|
||||
The counter can rollover.
|
||||
*/
|
||||
static ino_t extf_ino_id = 0;
|
||||
|
||||
|
||||
/* <<< */
|
||||
static int print_fd= 0;
|
||||
|
||||
|
||||
/*
|
||||
* Methods for the IsoStreamIface of an External Filter object.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit0= original stream is not open
|
||||
*/
|
||||
static
|
||||
int extf_stream_close_flag(IsoStream *stream, int flag)
|
||||
{
|
||||
int ret, status;
|
||||
ExternalFilterStreamData *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
if (data->running == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* <<< */
|
||||
if (print_fd) {
|
||||
fprintf(stderr, "libisofs_DEBUG: filter close in = %d , ic= %.f\n",
|
||||
data->running->recv_fd, (double) data->running->in_counter);
|
||||
fprintf(stderr, "libisofs_DEBUG: filter close out = %d , oc= %.f\n",
|
||||
data->running->send_fd, (double) data->running->out_counter);
|
||||
}
|
||||
|
||||
if(data->running->recv_fd != -1)
|
||||
close(data->running->recv_fd);
|
||||
if(data->running->send_fd != -1)
|
||||
close(data->running->send_fd);
|
||||
|
||||
ret = waitpid(data->running->pid, &status, WNOHANG);
|
||||
if (ret == 0 && data->running->pid != 0) {
|
||||
kill(data->running->pid, SIGKILL);
|
||||
waitpid(data->running->pid, &status, 0);
|
||||
}
|
||||
free(data->running);
|
||||
data->running = NULL;
|
||||
if (flag & 1)
|
||||
return 1;
|
||||
return iso_stream_close(data->orig);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int extf_stream_close(IsoStream *stream)
|
||||
{
|
||||
return extf_stream_close_flag(stream, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit0= do not run .get_size() if size is < 0
|
||||
*/
|
||||
static
|
||||
int extf_stream_open_flag(IsoStream *stream, int flag)
|
||||
{
|
||||
ExternalFilterStreamData *data;
|
||||
ExternalFilterRuntime *running = NULL;
|
||||
pid_t child_pid;
|
||||
int send_pipe[2], recv_pipe[2], ret, stream_open = 0;
|
||||
|
||||
send_pipe[0] = send_pipe[1] = recv_pipe[0] = recv_pipe[1] = -1;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = (ExternalFilterStreamData*)stream->data;
|
||||
if (data->running != NULL) {
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
if (data->size < 0 && !(flag & 1)) {
|
||||
/* Do the size determination run now, so that the size gets cached
|
||||
and .get_size() will not fail on an opened stream.
|
||||
*/
|
||||
stream->class->get_size(stream);
|
||||
}
|
||||
|
||||
ret = pipe(send_pipe);
|
||||
if (ret == -1) {
|
||||
ret = ISO_OUT_OF_MEM;
|
||||
goto parent_failed;
|
||||
}
|
||||
ret = pipe(recv_pipe);
|
||||
if (ret == -1) {
|
||||
ret = ISO_OUT_OF_MEM;
|
||||
goto parent_failed;
|
||||
}
|
||||
|
||||
child_pid= fork();
|
||||
if (child_pid == -1) {
|
||||
ret = ISO_DATA_SOURCE_FATAL;
|
||||
goto parent_failed;
|
||||
}
|
||||
|
||||
if (child_pid != 0) {
|
||||
/* parent */
|
||||
ret = extf_running_new(&running, send_pipe[1], recv_pipe[0], child_pid,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
goto parent_failed;
|
||||
}
|
||||
data->running = running;
|
||||
|
||||
/* <<< */
|
||||
if (print_fd) {
|
||||
fprintf(stderr, "libisofs_DEBUG: filter parent in = %d\n",
|
||||
data->running->recv_fd);
|
||||
fprintf(stderr, "libisofs_DEBUG: filter parent out = %d\n",
|
||||
data->running->send_fd);
|
||||
}
|
||||
|
||||
/* Give up the child-side pipe ends */
|
||||
close(send_pipe[0]);
|
||||
close(recv_pipe[1]);
|
||||
|
||||
/* Open stream only after forking so that the child does not know
|
||||
the pipe inlets of eventually underlying other filter streams.
|
||||
They would stay open and prevent those underlying filter children
|
||||
from seeing EOF at their input.
|
||||
*/
|
||||
ret = iso_stream_open(data->orig);
|
||||
|
||||
|
||||
/* <<< TEST <<<
|
||||
ret= ISO_FILE_READ_ERROR;
|
||||
*/
|
||||
|
||||
if (ret < 0) {
|
||||
/* Dispose pipes and child */
|
||||
extf_stream_close_flag(stream, 1);
|
||||
return ret;
|
||||
}
|
||||
stream_open = 1;
|
||||
/* Make filter outlet non-blocking */
|
||||
ret = fcntl(recv_pipe[0], F_GETFL);
|
||||
if (ret != -1) {
|
||||
ret |= O_NONBLOCK;
|
||||
fcntl(recv_pipe[0], F_SETFL, ret);
|
||||
}
|
||||
/* Make filter sink non-blocking */
|
||||
ret = fcntl(send_pipe[1], F_GETFL);
|
||||
if (ret != -1) {
|
||||
ret |= O_NONBLOCK;
|
||||
fcntl(send_pipe[1], F_SETFL, ret);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* child */
|
||||
|
||||
/* Give up the parent-side pipe ends */
|
||||
close(send_pipe[1]);
|
||||
close(recv_pipe[0]);
|
||||
|
||||
/* attach pipe ends to stdin and stdout */;
|
||||
close(0);
|
||||
ret = dup2(send_pipe[0], 0);
|
||||
if (ret == -1) {
|
||||
goto child_failed;
|
||||
}
|
||||
close(1);
|
||||
ret = dup2(recv_pipe[1], 1);
|
||||
if (ret == -1) {
|
||||
goto child_failed;
|
||||
}
|
||||
|
||||
/* <<< */
|
||||
if (print_fd) {
|
||||
fprintf(stderr, "libisofs_DEBUG: filter child in = %d\n",
|
||||
send_pipe[0]);
|
||||
fprintf(stderr, "libisofs_DEBUG: filter child out = %d\n",
|
||||
recv_pipe[1]);
|
||||
}
|
||||
|
||||
/* Self conversion into external program */
|
||||
execv(data->cmd->path, data->cmd->argv); /* should never come back */
|
||||
|
||||
child_failed:;
|
||||
fprintf(stderr,"--- execution of external filter command failed:\n");
|
||||
fprintf(stderr," %s\n", data->cmd->path);
|
||||
exit(127);
|
||||
|
||||
parent_failed:;
|
||||
|
||||
/* <<< */
|
||||
if (print_fd) {
|
||||
fprintf(stderr, "libisofs_DEBUG: FAILED : filter parent in = %d\n",
|
||||
recv_pipe[0]);
|
||||
fprintf(stderr, "libisofs_DEBUG: FAILED : filter parent out = %d\n",
|
||||
send_pipe[1]);
|
||||
}
|
||||
|
||||
if (stream_open)
|
||||
iso_stream_close(data->orig);
|
||||
if(send_pipe[0] != -1)
|
||||
close(send_pipe[0]);
|
||||
if(send_pipe[1] != -1)
|
||||
close(send_pipe[1]);
|
||||
if(recv_pipe[0] != -1)
|
||||
close(recv_pipe[0]);
|
||||
if(recv_pipe[1] != -1)
|
||||
close(recv_pipe[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int extf_stream_open(IsoStream *stream)
|
||||
{
|
||||
return extf_stream_open_flag(stream, 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef Libisofs_external_filters_selecT
|
||||
|
||||
/* Performance is weaker than with non-blocking i/o and usleep(). */
|
||||
|
||||
static
|
||||
int extf_wait_for_io(int fd_in, int fd_out, int microsec, int flag)
|
||||
{
|
||||
struct timeval wt;
|
||||
fd_set rds,wts,exs;
|
||||
int ready, fd_max;
|
||||
|
||||
fd_max = fd_out;
|
||||
if (fd_in > fd_out)
|
||||
fd_max = fd_in;
|
||||
|
||||
FD_ZERO(&rds);
|
||||
FD_ZERO(&wts);
|
||||
FD_ZERO(&exs);
|
||||
if (fd_in >= 0) {
|
||||
FD_SET(fd_in,&rds);
|
||||
FD_SET(fd_in,&exs);
|
||||
}
|
||||
if (fd_out >= 0) {
|
||||
FD_SET(fd_out,&rds);
|
||||
FD_SET(fd_in,&exs);
|
||||
}
|
||||
wt.tv_sec = microsec/1000000;
|
||||
wt.tv_usec = microsec%1000000;
|
||||
ready = select(fd_max + 1, &rds, &wts, &exs, &wt);
|
||||
if (ready <= 0)
|
||||
return 0;
|
||||
if (fd_in >= 0) {
|
||||
if (FD_ISSET(fd_in, &rds))
|
||||
return 1;
|
||||
}
|
||||
if (fd_out >= 0) {
|
||||
if (FD_ISSET(fd_out, &rds))
|
||||
return 2;
|
||||
}
|
||||
if (fd_in >= 0) {
|
||||
if (FD_ISSET(fd_in, &exs))
|
||||
return -1;
|
||||
}
|
||||
if (fd_out >= 0) {
|
||||
if (FD_ISSET(fd_out, &exs))
|
||||
return -2;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif /* Libisofs_external_filters_selecT */
|
||||
|
||||
|
||||
static
|
||||
int extf_stream_read(IsoStream *stream, void *buf, size_t desired)
|
||||
{
|
||||
int ret, blocking = 0;
|
||||
ExternalFilterStreamData *data;
|
||||
ExternalFilterRuntime *running;
|
||||
size_t fill = 0;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
running= data->running;
|
||||
if (running == NULL) {
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
if (running->out_eof) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (running->in_eof && !blocking) {
|
||||
/* Make filter outlet blocking */
|
||||
ret = fcntl(running->recv_fd, F_GETFL);
|
||||
if (ret != -1) {
|
||||
ret &= ~O_NONBLOCK;
|
||||
fcntl(running->recv_fd, F_SETFL, ret);
|
||||
}
|
||||
blocking = 1;
|
||||
}
|
||||
|
||||
/* Try to read desired amount from filter */;
|
||||
while (1) {
|
||||
ret = read(running->recv_fd, ((char *) buf) + fill,
|
||||
desired - fill);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN)
|
||||
break;
|
||||
return ISO_FILE_READ_ERROR;
|
||||
}
|
||||
fill += ret;
|
||||
if (ret == 0) {
|
||||
running->out_eof = 1;
|
||||
}
|
||||
if (ret == 0 || fill >= desired) {
|
||||
running->out_counter += fill;
|
||||
return fill;
|
||||
}
|
||||
}
|
||||
|
||||
if (running->in_eof) {
|
||||
usleep(1000); /* just in case it is still non-blocking */
|
||||
continue;
|
||||
}
|
||||
if (running->pipebuf_fill) {
|
||||
ret = running->pipebuf_fill;
|
||||
running->pipebuf_fill = 0;
|
||||
} else {
|
||||
ret = iso_stream_read(data->orig, running->pipebuf,
|
||||
sizeof(running->pipebuf));
|
||||
if (ret > 0)
|
||||
running->in_counter += ret;
|
||||
}
|
||||
if (ret < 0) {
|
||||
running->in_eof = 1;
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0) {
|
||||
|
||||
/* <<< */
|
||||
if (print_fd) {
|
||||
fprintf(stderr,
|
||||
"libisofs_DEBUG: filter close out = %d , ic= %.f\n",
|
||||
running->send_fd, (double) running->in_counter);
|
||||
}
|
||||
|
||||
running->in_eof = 1;
|
||||
close(running->send_fd); /* Tell the filter: it is over */
|
||||
running->send_fd = -1;
|
||||
} else {
|
||||
running->pipebuf_fill = ret;
|
||||
ret = write(running->send_fd, running->pipebuf,
|
||||
running->pipebuf_fill);
|
||||
if (ret == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
|
||||
#ifdef Libisofs_external_filters_selecT
|
||||
|
||||
/* This select() based waiting saves 10 % CPU load but
|
||||
needs 50 % more real time */
|
||||
|
||||
ret = extf_wait_for_io(running->recv_fd, running->send_fd,
|
||||
100000, 0);
|
||||
if (ret < 0)
|
||||
usleep(1000); /* To make sure sufficient laziness */
|
||||
|
||||
#else
|
||||
|
||||
/* No sleeping needs 90 % more CPU and saves 6 % time */
|
||||
usleep(1000); /* go lazy because the filter is slow */
|
||||
|
||||
#endif /* ! Libisofs_external_filters_selecT */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* From the view of the caller it _is_ a read error */
|
||||
running->in_eof = 1;
|
||||
return ISO_FILE_READ_ERROR;
|
||||
}
|
||||
running->pipebuf_fill = 0;
|
||||
}
|
||||
}
|
||||
return ISO_FILE_READ_ERROR; /* should never be hit */
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
off_t extf_stream_get_size(IsoStream *stream)
|
||||
{
|
||||
int ret, ret_close;
|
||||
off_t count = 0;
|
||||
ExternalFilterStreamData *data;
|
||||
char buf[64 * 1024];
|
||||
size_t bufsize = 64 * 1024;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
if (data->size >= 0) {
|
||||
return data->size;
|
||||
}
|
||||
|
||||
/* Run filter command and count output bytes */
|
||||
ret = extf_stream_open_flag(stream, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
while (1) {
|
||||
ret = extf_stream_read(stream, buf, bufsize);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
count += ret;
|
||||
}
|
||||
ret_close = extf_stream_close(stream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret_close < 0)
|
||||
return ret_close;
|
||||
|
||||
data->size = count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int extf_stream_is_repeatable(IsoStream *stream)
|
||||
{
|
||||
/* Only repeatable streams are accepted as orig */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void extf_stream_get_id(IsoStream *stream, unsigned int *fs_id,
|
||||
dev_t *dev_id, ino_t *ino_id)
|
||||
{
|
||||
ExternalFilterStreamData *data;
|
||||
|
||||
data = stream->data;
|
||||
*fs_id = ISO_FILTER_FS_ID;
|
||||
*dev_id = ISO_FILTER_EXTERNAL_DEV_ID;
|
||||
*ino_id = data->id;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void extf_stream_free(IsoStream *stream)
|
||||
{
|
||||
ExternalFilterStreamData *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return;
|
||||
}
|
||||
data = stream->data;
|
||||
if (data->running != NULL) {
|
||||
extf_stream_close(stream);
|
||||
}
|
||||
iso_stream_unref(data->orig);
|
||||
if (data->cmd->refcount > 0)
|
||||
data->cmd->refcount--;
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int extf_update_size(IsoStream *stream)
|
||||
{
|
||||
/* By principle size is determined only once */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
IsoStream *extf_get_input_stream(IsoStream *stream, int flag)
|
||||
{
|
||||
ExternalFilterStreamData *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = stream->data;
|
||||
return data->orig;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int extf_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
/* Function is defined after definition of extf_stream_class */
|
||||
|
||||
|
||||
IsoStreamIface extf_stream_class = {
|
||||
3,
|
||||
"extf",
|
||||
extf_stream_open,
|
||||
extf_stream_close,
|
||||
extf_stream_get_size,
|
||||
extf_stream_read,
|
||||
extf_stream_is_repeatable,
|
||||
extf_stream_get_id,
|
||||
extf_stream_free,
|
||||
extf_update_size,
|
||||
extf_get_input_stream,
|
||||
extf_cmp_ino
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
int extf_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
ExternalFilterStreamData *data1, *data2;
|
||||
|
||||
if (s1->class != &extf_stream_class || s2->class != &extf_stream_class)
|
||||
return iso_stream_cmp_ino(s1, s2, 1);
|
||||
data1 = (ExternalFilterStreamData*) s1->data;
|
||||
data2 = (ExternalFilterStreamData*) s2->data;
|
||||
if (data1->cmd != data2->cmd)
|
||||
return (data1->cmd < data2->cmd ? -1 : 1);
|
||||
return iso_stream_cmp_ino(data1->orig, data2->orig, 0);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static
|
||||
void extf_filter_free(FilterContext *filter)
|
||||
{
|
||||
/* no data are allocated */;
|
||||
}
|
||||
|
||||
|
||||
/* To be called by iso_file_add_filter().
|
||||
* The FilterContext input parameter is not furtherly needed for the
|
||||
* emerging IsoStream.
|
||||
*/
|
||||
static
|
||||
int extf_filter_get_filter(FilterContext *filter, IsoStream *original,
|
||||
IsoStream **filtered)
|
||||
{
|
||||
IsoStream *str;
|
||||
ExternalFilterStreamData *data;
|
||||
IsoExternalFilterCommand *cmd;
|
||||
|
||||
if (filter == NULL || original == NULL || filtered == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
cmd = (IsoExternalFilterCommand *) filter->data;
|
||||
if (cmd->refcount + 1 <= 0) {
|
||||
return ISO_EXTF_TOO_OFTEN;
|
||||
}
|
||||
|
||||
str = malloc(sizeof(IsoStream));
|
||||
if (str == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(ExternalFilterStreamData));
|
||||
if (data == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
/* These data items are not owned by this filter object */
|
||||
data->id = ++extf_ino_id;
|
||||
data->orig = original;
|
||||
data->cmd = cmd;
|
||||
data->size = -1;
|
||||
data->running = NULL;
|
||||
|
||||
/* get reference to the source */
|
||||
iso_stream_ref(data->orig);
|
||||
|
||||
str->refcount = 1;
|
||||
str->data = data;
|
||||
str->class = &extf_stream_class;
|
||||
|
||||
*filtered = str;
|
||||
|
||||
cmd->refcount++;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Produce a parameter object suitable for iso_file_add_filter().
|
||||
* It may be disposed by free() after all those calls are made.
|
||||
*
|
||||
* This is an internal call of libisofs to be used by an API call that
|
||||
* attaches an IsoExternalFilterCommand to one or more IsoFile objects.
|
||||
* See libisofs.h for IsoExternalFilterCommand.
|
||||
*/
|
||||
static
|
||||
int extf_create_context(IsoExternalFilterCommand *cmd,
|
||||
FilterContext **filter, int flag)
|
||||
{
|
||||
FilterContext *f;
|
||||
|
||||
*filter = f = calloc(1, sizeof(FilterContext));
|
||||
if (f == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
f->refcount = 1;
|
||||
f->version = 0;
|
||||
f->data = cmd;
|
||||
f->free = extf_filter_free;
|
||||
f->get_filter = extf_filter_get_filter;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A function which adds a filter to an IsoFile shall create a temporary
|
||||
* FilterContext by iso_extf_create_context(), use it in one or more calls
|
||||
* of filter.c:iso_file_add_filter() and finally dispose it by free().
|
||||
*/
|
||||
|
||||
int iso_file_add_external_filter(IsoFile *file, IsoExternalFilterCommand *cmd,
|
||||
int flag)
|
||||
{
|
||||
int ret;
|
||||
FilterContext *f = NULL;
|
||||
IsoStream *stream;
|
||||
off_t original_size = 0, filtered_size = 0;
|
||||
|
||||
if (cmd->behavior & (1 | 2 | 4)) {
|
||||
original_size = iso_file_get_size(file);
|
||||
if (original_size <= 0 ||
|
||||
((cmd->behavior & 4) && original_size <= 2048)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
ret = extf_create_context(cmd, &f, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = iso_file_add_filter(file, f, 0);
|
||||
free(f);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
/* Run a full filter process getsize so that the size is cached */
|
||||
stream = iso_file_get_stream(file);
|
||||
filtered_size = iso_stream_get_size(stream);
|
||||
if (filtered_size < 0) {
|
||||
iso_file_remove_filter(file, 0);
|
||||
return filtered_size;
|
||||
}
|
||||
if (((cmd->behavior & 2) && filtered_size >= original_size) ||
|
||||
((cmd->behavior & 4) && filtered_size / 2048 >= original_size / 2048)){
|
||||
ret = iso_file_remove_filter(file, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int iso_stream_get_external_filter(IsoStream *stream,
|
||||
IsoExternalFilterCommand **cmd, int flag)
|
||||
{
|
||||
ExternalFilterStreamData *data;
|
||||
|
||||
if (stream->class != &extf_stream_class)
|
||||
return 0;
|
||||
data = stream->data;
|
||||
*cmd = data->cmd;
|
||||
return 1;
|
||||
}
|
||||
|
750
libisofs/filters/gzip.c
Normal file
750
libisofs/filters/gzip.c
Normal file
@ -0,0 +1,750 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*
|
||||
* It implements a filter facility which can pipe a IsoStream into gzip
|
||||
* compression resp. uncompression, read its output and forward it as IsoStream
|
||||
* output to an IsoFile.
|
||||
* The gzip compression is done via zlib by Jean-loup Gailly and Mark Adler
|
||||
* who state in <zlib.h>:
|
||||
* "The data format used by the zlib library is described by RFCs (Request for
|
||||
* Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
|
||||
* (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format)."
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../libisofs.h"
|
||||
#include "../filter.h"
|
||||
#include "../fsource.h"
|
||||
#include "../util.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
#include <zlib.h>
|
||||
#else
|
||||
/* If zlib is not available then this code is a dummy */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* A filter that encodes or decodes the content of gzip compressed files.
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------- GzipFilterRuntime ------------------------- */
|
||||
|
||||
|
||||
/* Individual runtime properties exist only as long as the stream is opened.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
z_stream strm; /* The zlib processing context */
|
||||
|
||||
#endif
|
||||
|
||||
char *in_buffer;
|
||||
char *out_buffer;
|
||||
int in_buffer_size;
|
||||
int out_buffer_size;
|
||||
char *rpt; /* out_buffer + read_bytes */
|
||||
|
||||
off_t in_counter;
|
||||
off_t out_counter;
|
||||
|
||||
int do_flush; /* flush mode for deflate() changes at end of input */
|
||||
|
||||
int error_ret;
|
||||
|
||||
} GzipFilterRuntime;
|
||||
|
||||
|
||||
static
|
||||
int gzip_running_destroy(GzipFilterRuntime **running, int flag)
|
||||
{
|
||||
GzipFilterRuntime *o= *running;
|
||||
if (o == NULL)
|
||||
return 0;
|
||||
if (o->in_buffer != NULL)
|
||||
free(o->in_buffer);
|
||||
if (o->out_buffer != NULL)
|
||||
free(o->out_buffer);
|
||||
free((char *) o);
|
||||
*running = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_running_new(GzipFilterRuntime **running, int flag)
|
||||
{
|
||||
GzipFilterRuntime *o;
|
||||
|
||||
*running = o = calloc(sizeof(GzipFilterRuntime), 1);
|
||||
if (o == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
#ifdef Libisofs_with_zliB
|
||||
memset(&(o->strm), 0, sizeof(o->strm));
|
||||
#endif
|
||||
o->in_buffer = NULL;
|
||||
o->out_buffer = NULL;
|
||||
o->in_buffer_size = 0;
|
||||
o->out_buffer_size = 0;
|
||||
o->rpt = NULL;
|
||||
o->in_counter = 0;
|
||||
o->out_counter = 0;
|
||||
#ifdef Libisofs_with_zliB
|
||||
o->do_flush = Z_NO_FLUSH;
|
||||
#endif
|
||||
o->error_ret = 1;
|
||||
|
||||
o->in_buffer_size= 2048;
|
||||
o->out_buffer_size= 2048;
|
||||
o->in_buffer = calloc(o->in_buffer_size, 1);
|
||||
o->out_buffer = calloc(o->out_buffer_size, 1);
|
||||
if (o->in_buffer == NULL || o->out_buffer == NULL)
|
||||
goto failed;
|
||||
o->rpt = o->out_buffer;
|
||||
return 1;
|
||||
failed:
|
||||
gzip_running_destroy(running, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------- GzipFilterStreamData --------------------- */
|
||||
|
||||
|
||||
/* Counts the number of active compression filters */
|
||||
static off_t gzip_ref_count = 0;
|
||||
|
||||
/* Counts the number of active uncompression filters */
|
||||
static off_t gunzip_ref_count = 0;
|
||||
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
/* Parameter for deflateInit2() , see <zlib.h> */
|
||||
|
||||
/* ??? get this from zisofs.c ziso_compression_level ?
|
||||
* ??? have an own global parameter API ?
|
||||
* For now level 6 seems to be a fine compromise between speed and size.
|
||||
*/
|
||||
static int gzip_compression_level = 6;
|
||||
|
||||
#endif /* Libisofs_with_zliB */
|
||||
|
||||
|
||||
/*
|
||||
* The data payload of an individual Gzip Filter IsoStream
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
IsoStream *orig;
|
||||
|
||||
off_t size; /* -1 means that the size is unknown yet */
|
||||
|
||||
GzipFilterRuntime *running; /* is non-NULL when open */
|
||||
|
||||
ino_t id;
|
||||
|
||||
} GzipFilterStreamData;
|
||||
|
||||
|
||||
|
||||
/* Each individual GzipFilterStreamData needs a unique id number. */
|
||||
/* >>> This is very suboptimal:
|
||||
The counter can rollover.
|
||||
*/
|
||||
static ino_t gzip_ino_id = 0;
|
||||
|
||||
static
|
||||
int gzip_stream_uncompress(IsoStream *stream, void *buf, size_t desired);
|
||||
|
||||
|
||||
/*
|
||||
* Methods for the IsoStreamIface of a Gzip Filter object.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @param flag bit0= original stream is not open
|
||||
*/
|
||||
static
|
||||
int gzip_stream_close_flag(IsoStream *stream, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
GzipFilterStreamData *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
if (data->running == NULL) {
|
||||
return 1;
|
||||
}
|
||||
if (stream->class->read == &gzip_stream_uncompress) {
|
||||
inflateEnd(&(data->running->strm));
|
||||
} else {
|
||||
deflateEnd(&(data->running->strm));
|
||||
}
|
||||
gzip_running_destroy(&(data->running), 0);
|
||||
|
||||
if (flag & 1)
|
||||
return 1;
|
||||
return iso_stream_close(data->orig);
|
||||
|
||||
#else
|
||||
|
||||
return ISO_ZLIB_NOT_ENABLED;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_stream_close(IsoStream *stream)
|
||||
{
|
||||
return gzip_stream_close_flag(stream, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit0= do not run .get_size() if size is < 0
|
||||
*/
|
||||
static
|
||||
int gzip_stream_open_flag(IsoStream *stream, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
GzipFilterStreamData *data;
|
||||
GzipFilterRuntime *running = NULL;
|
||||
int ret;
|
||||
z_stream *strm;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = (GzipFilterStreamData*) stream->data;
|
||||
if (data->running != NULL) {
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
if (data->size < 0 && !(flag & 1)) {
|
||||
/* Do the size determination run now, so that the size gets cached
|
||||
and .get_size() will not fail on an opened stream.
|
||||
*/
|
||||
stream->class->get_size(stream);
|
||||
}
|
||||
|
||||
ret = gzip_running_new(&running,
|
||||
stream->class->read == &gzip_stream_uncompress);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
data->running = running;
|
||||
|
||||
/* Start up zlib compression context */
|
||||
strm = &(running->strm);
|
||||
strm->zalloc = Z_NULL;
|
||||
strm->zfree = Z_NULL;
|
||||
strm->opaque = Z_NULL;
|
||||
if (stream->class->read == &gzip_stream_uncompress) {
|
||||
ret = inflateInit2(strm, 15 | 16);
|
||||
} else {
|
||||
ret = deflateInit2(strm, gzip_compression_level, Z_DEFLATED,
|
||||
15 | 16, 8, Z_DEFAULT_STRATEGY);
|
||||
}
|
||||
if (ret != Z_OK)
|
||||
return ISO_ZLIB_COMPR_ERR;
|
||||
strm->next_out = (Bytef *) running->out_buffer;
|
||||
strm->avail_out = running->out_buffer_size;
|
||||
|
||||
/* Open input stream */
|
||||
ret = iso_stream_open(data->orig);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
#else
|
||||
|
||||
return ISO_ZLIB_NOT_ENABLED;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_stream_open(IsoStream *stream)
|
||||
{
|
||||
return gzip_stream_open_flag(stream, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit1= uncompress rather than compress
|
||||
*/
|
||||
static
|
||||
int gzip_stream_convert(IsoStream *stream, void *buf, size_t desired, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
int ret, todo, cnv_ret, c_bytes;
|
||||
GzipFilterStreamData *data;
|
||||
GzipFilterRuntime *rng;
|
||||
size_t fill = 0;
|
||||
z_stream *strm;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
rng= data->running;
|
||||
if (rng == NULL) {
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
strm = &(rng->strm);
|
||||
if (rng->error_ret < 0) {
|
||||
return rng->error_ret;
|
||||
} else if (rng->error_ret == 0) {
|
||||
if (rng->out_buffer_size - strm->avail_out
|
||||
- (rng->rpt - rng->out_buffer) <= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Transfer eventual converted bytes from strm to buf */
|
||||
c_bytes = rng->out_buffer_size - strm->avail_out
|
||||
- (rng->rpt - rng->out_buffer);
|
||||
if (c_bytes > 0) {
|
||||
todo = desired - fill;
|
||||
if (todo > c_bytes)
|
||||
todo = c_bytes;
|
||||
memcpy(((char *) buf) + fill, rng->rpt, todo);
|
||||
rng->rpt += todo;
|
||||
fill += todo;
|
||||
rng->out_counter += todo;
|
||||
}
|
||||
|
||||
if (fill >= desired || rng->error_ret == 0)
|
||||
return fill;
|
||||
|
||||
/* All buffered out data are consumed now */
|
||||
rng->rpt = rng->out_buffer;
|
||||
strm->next_out = (Bytef *) rng->out_buffer;
|
||||
strm->avail_out = rng->out_buffer_size;
|
||||
|
||||
if (strm->avail_in == 0) {
|
||||
/* All pending input is consumed. Get new input. */
|
||||
ret = iso_stream_read(data->orig, rng->in_buffer,
|
||||
rng->in_buffer_size);
|
||||
if (ret < 0)
|
||||
return (rng->error_ret = ret);
|
||||
if (ret == 0) {
|
||||
if (flag & 2) {
|
||||
/* Early input EOF */
|
||||
return (rng->error_ret = ISO_ZLIB_EARLY_EOF);
|
||||
} else {
|
||||
/* Tell zlib by the next call that it is over */
|
||||
rng->do_flush = Z_FINISH;
|
||||
}
|
||||
}
|
||||
strm->next_in = (Bytef *) rng->in_buffer;
|
||||
strm->avail_in = ret;
|
||||
rng->in_counter += ret;
|
||||
}
|
||||
|
||||
/* Submit input and fetch output until input is consumed */
|
||||
while (1) {
|
||||
if (flag & 2) {
|
||||
cnv_ret = inflate(strm, rng->do_flush);
|
||||
} else {
|
||||
cnv_ret = deflate(strm, rng->do_flush);
|
||||
}
|
||||
if (cnv_ret == Z_STREAM_ERROR || cnv_ret == Z_BUF_ERROR) {
|
||||
return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
|
||||
}
|
||||
if (strm->avail_out < rng->out_buffer_size)
|
||||
break; /* output is available */
|
||||
if (strm->avail_in == 0) /* all pending input consumed */
|
||||
break;
|
||||
}
|
||||
if (cnv_ret == Z_STREAM_END)
|
||||
rng->error_ret = 0;
|
||||
}
|
||||
return fill;
|
||||
|
||||
#else
|
||||
|
||||
return ISO_ZLIB_NOT_ENABLED;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
int gzip_stream_compress(IsoStream *stream, void *buf, size_t desired)
|
||||
{
|
||||
return gzip_stream_convert(stream, buf, desired, 0);
|
||||
}
|
||||
|
||||
static
|
||||
int gzip_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
|
||||
{
|
||||
return gzip_stream_convert(stream, buf, desired, 2);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
off_t gzip_stream_get_size(IsoStream *stream)
|
||||
{
|
||||
int ret, ret_close;
|
||||
off_t count = 0;
|
||||
GzipFilterStreamData *data;
|
||||
char buf[64 * 1024];
|
||||
size_t bufsize = 64 * 1024;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
if (data->size >= 0) {
|
||||
return data->size;
|
||||
}
|
||||
|
||||
/* Run filter command and count output bytes */
|
||||
ret = gzip_stream_open_flag(stream, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
while (1) {
|
||||
ret = stream->class->read(stream, buf, bufsize);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
count += ret;
|
||||
}
|
||||
ret_close = gzip_stream_close(stream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret_close < 0)
|
||||
return ret_close;
|
||||
|
||||
data->size = count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_stream_is_repeatable(IsoStream *stream)
|
||||
{
|
||||
/* Only repeatable streams are accepted as orig */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void gzip_stream_get_id(IsoStream *stream, unsigned int *fs_id,
|
||||
dev_t *dev_id, ino_t *ino_id)
|
||||
{
|
||||
GzipFilterStreamData *data;
|
||||
|
||||
data = stream->data;
|
||||
*fs_id = ISO_FILTER_FS_ID;
|
||||
*dev_id = ISO_FILTER_GZIP_DEV_ID;
|
||||
*ino_id = data->id;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void gzip_stream_free(IsoStream *stream)
|
||||
{
|
||||
GzipFilterStreamData *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return;
|
||||
}
|
||||
data = stream->data;
|
||||
if (data->running != NULL) {
|
||||
gzip_stream_close(stream);
|
||||
}
|
||||
if (stream->class->read == &gzip_stream_uncompress) {
|
||||
if (--gunzip_ref_count < 0)
|
||||
gunzip_ref_count = 0;
|
||||
} else {
|
||||
if (--gzip_ref_count < 0)
|
||||
gzip_ref_count = 0;
|
||||
}
|
||||
iso_stream_unref(data->orig);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_update_size(IsoStream *stream)
|
||||
{
|
||||
/* By principle size is determined only once */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
IsoStream *gzip_get_input_stream(IsoStream *stream, int flag)
|
||||
{
|
||||
GzipFilterStreamData *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = stream->data;
|
||||
return data->orig;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
|
||||
|
||||
IsoStreamIface gzip_stream_compress_class = {
|
||||
3,
|
||||
"gzip",
|
||||
gzip_stream_open,
|
||||
gzip_stream_close,
|
||||
gzip_stream_get_size,
|
||||
gzip_stream_compress,
|
||||
gzip_stream_is_repeatable,
|
||||
gzip_stream_get_id,
|
||||
gzip_stream_free,
|
||||
gzip_update_size,
|
||||
gzip_get_input_stream,
|
||||
gzip_cmp_ino
|
||||
};
|
||||
|
||||
|
||||
IsoStreamIface gzip_stream_uncompress_class = {
|
||||
3,
|
||||
"pizg",
|
||||
gzip_stream_open,
|
||||
gzip_stream_close,
|
||||
gzip_stream_get_size,
|
||||
gzip_stream_uncompress,
|
||||
gzip_stream_is_repeatable,
|
||||
gzip_stream_get_id,
|
||||
gzip_stream_free,
|
||||
gzip_update_size,
|
||||
gzip_get_input_stream,
|
||||
gzip_cmp_ino
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
if (s1->class != s2->class || (s1->class != &gzip_stream_compress_class &&
|
||||
s2->class != &gzip_stream_compress_class))
|
||||
return iso_stream_cmp_ino(s1, s2, 1);
|
||||
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||
iso_stream_get_input_stream(s2, 0), 0);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
static
|
||||
void gzip_filter_free(FilterContext *filter)
|
||||
{
|
||||
/* no data are allocated */;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit1= Install a decompression filter
|
||||
*/
|
||||
static
|
||||
int gzip_filter_get_filter(FilterContext *filter, IsoStream *original,
|
||||
IsoStream **filtered, int flag)
|
||||
{
|
||||
IsoStream *str;
|
||||
GzipFilterStreamData *data;
|
||||
|
||||
if (filter == NULL || original == NULL || filtered == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
str = calloc(sizeof(IsoStream), 1);
|
||||
if (str == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = calloc(sizeof(GzipFilterStreamData), 1);
|
||||
if (data == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* These data items are not owned by this filter object */
|
||||
data->id = ++gzip_ino_id;
|
||||
data->orig = original;
|
||||
data->size = -1;
|
||||
data->running = NULL;
|
||||
|
||||
/* get reference to the source */
|
||||
iso_stream_ref(data->orig);
|
||||
|
||||
str->refcount = 1;
|
||||
str->data = data;
|
||||
if (flag & 2) {
|
||||
str->class = &gzip_stream_uncompress_class;
|
||||
gunzip_ref_count++;
|
||||
} else {
|
||||
str->class = &gzip_stream_compress_class;
|
||||
gzip_ref_count++;
|
||||
}
|
||||
|
||||
*filtered = str;
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* To be called by iso_file_add_filter().
|
||||
* The FilterContext input parameter is not furtherly needed for the
|
||||
* emerging IsoStream.
|
||||
*/
|
||||
static
|
||||
int gzip_filter_get_compressor(FilterContext *filter, IsoStream *original,
|
||||
IsoStream **filtered)
|
||||
{
|
||||
return gzip_filter_get_filter(filter, original, filtered, 0);
|
||||
}
|
||||
|
||||
static
|
||||
int gzip_filter_get_uncompressor(FilterContext *filter, IsoStream *original,
|
||||
IsoStream **filtered)
|
||||
{
|
||||
return gzip_filter_get_filter(filter, original, filtered, 2);
|
||||
}
|
||||
|
||||
|
||||
/* Produce a parameter object suitable for iso_file_add_filter().
|
||||
* It may be disposed by free() after all those calls are made.
|
||||
*
|
||||
* This is quite a dummy as it does not carry individual data.
|
||||
* @param flag bit1= Install a decompression filter
|
||||
*/
|
||||
static
|
||||
int gzip_create_context(FilterContext **filter, int flag)
|
||||
{
|
||||
FilterContext *f;
|
||||
|
||||
*filter = f = calloc(1, sizeof(FilterContext));
|
||||
if (f == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
f->refcount = 1;
|
||||
f->version = 0;
|
||||
f->data = NULL;
|
||||
f->free = gzip_filter_free;
|
||||
if (flag & 2)
|
||||
f->get_filter = gzip_filter_get_uncompressor;
|
||||
else
|
||||
f->get_filter = gzip_filter_get_compressor;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit0= if_block_reduction rather than if_reduction
|
||||
* bit1= Install a decompression filter
|
||||
* bit2= only inquire availability of gzip filtering
|
||||
* bit3= do not inquire size
|
||||
*/
|
||||
int gzip_add_filter(IsoFile *file, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
int ret;
|
||||
FilterContext *f = NULL;
|
||||
IsoStream *stream;
|
||||
off_t original_size = 0, filtered_size = 0;
|
||||
|
||||
if (flag & 4)
|
||||
return 2;
|
||||
|
||||
original_size = iso_file_get_size(file);
|
||||
|
||||
ret = gzip_create_context(&f, flag & 2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = iso_file_add_filter(file, f, 0);
|
||||
free(f);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (flag & 8) /* size will be filled in by caller */
|
||||
return ISO_SUCCESS;
|
||||
|
||||
/* Run a full filter process getsize so that the size is cached */
|
||||
stream = iso_file_get_stream(file);
|
||||
filtered_size = iso_stream_get_size(stream);
|
||||
if (filtered_size < 0) {
|
||||
iso_file_remove_filter(file, 0);
|
||||
return filtered_size;
|
||||
}
|
||||
if ((filtered_size >= original_size ||
|
||||
((flag & 1) && filtered_size / 2048 >= original_size / 2048))
|
||||
&& !(flag & 2)){
|
||||
ret = iso_file_remove_filter(file, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
|
||||
#else
|
||||
|
||||
return ISO_ZLIB_NOT_ENABLED;
|
||||
|
||||
#endif /* ! Libisofs_with_zliB */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* API function */
|
||||
int iso_file_add_gzip_filter(IsoFile *file, int flag)
|
||||
{
|
||||
return gzip_add_filter(file, flag & ~8);
|
||||
}
|
||||
|
||||
|
||||
/* API function */
|
||||
int iso_gzip_get_refcounts(off_t *gzip_count, off_t *gunzip_count, int flag)
|
||||
{
|
||||
*gzip_count = gzip_ref_count;
|
||||
*gunzip_count = gunzip_ref_count;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
187
libisofs/filters/xor_encrypt.c
Normal file
187
libisofs/filters/xor_encrypt.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "../libisofs.h"
|
||||
#include "../filter.h"
|
||||
#include "../fsource.h"
|
||||
|
||||
/*
|
||||
* A simple Filter implementation for example purposes. It encrypts a file
|
||||
* by XORing each byte by a given key.
|
||||
*/
|
||||
|
||||
static ino_t xor_ino_id = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IsoStream *orig;
|
||||
uint8_t key;
|
||||
ino_t id;
|
||||
} XorEncryptStreamData;
|
||||
|
||||
static
|
||||
int xor_encrypt_stream_open(IsoStream *stream)
|
||||
{
|
||||
XorEncryptStreamData *data;
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = (XorEncryptStreamData*)stream->data;
|
||||
return iso_stream_open(data->orig);
|
||||
}
|
||||
|
||||
static
|
||||
int xor_encrypt_stream_close(IsoStream *stream)
|
||||
{
|
||||
XorEncryptStreamData *data;
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
return iso_stream_close(data->orig);
|
||||
}
|
||||
|
||||
static
|
||||
off_t xor_encrypt_stream_get_size(IsoStream *stream)
|
||||
{
|
||||
XorEncryptStreamData *data;
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
return iso_stream_get_size(data->orig);
|
||||
}
|
||||
|
||||
static
|
||||
int xor_encrypt_stream_read(IsoStream *stream, void *buf, size_t count)
|
||||
{
|
||||
int ret, len;
|
||||
XorEncryptStreamData *data;
|
||||
uint8_t *buffer = buf;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = stream->data;
|
||||
ret = iso_stream_read(data->orig, buf, count);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* xor */
|
||||
for (len = 0; len < ret; ++len) {
|
||||
buffer[len] = buffer[len] ^ data->key;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int xor_encrypt_stream_is_repeatable(IsoStream *stream)
|
||||
{
|
||||
/* the filter can't be created if underlying stream is not repeatable */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
void xor_encrypt_stream_get_id(IsoStream *stream, unsigned int *fs_id,
|
||||
dev_t *dev_id, ino_t *ino_id)
|
||||
{
|
||||
XorEncryptStreamData *data = stream->data;
|
||||
*fs_id = ISO_FILTER_FS_ID;
|
||||
*dev_id = XOR_ENCRYPT_DEV_ID;
|
||||
*ino_id = data->id;
|
||||
}
|
||||
|
||||
static
|
||||
void xor_encrypt_stream_free(IsoStream *stream)
|
||||
{
|
||||
XorEncryptStreamData *data = stream->data;
|
||||
iso_stream_unref(data->orig);
|
||||
free(data);
|
||||
}
|
||||
|
||||
IsoStreamIface xor_encrypt_stream_class = {
|
||||
0,
|
||||
"xorf",
|
||||
xor_encrypt_stream_open,
|
||||
xor_encrypt_stream_close,
|
||||
xor_encrypt_stream_get_size,
|
||||
xor_encrypt_stream_read,
|
||||
xor_encrypt_stream_is_repeatable,
|
||||
xor_encrypt_stream_get_id,
|
||||
xor_encrypt_stream_free
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
void xor_encrypt_filter_free(FilterContext *filter)
|
||||
{
|
||||
free(filter->data);
|
||||
}
|
||||
|
||||
static
|
||||
int xor_encrypt_filter_get_filter(FilterContext *filter, IsoStream *original,
|
||||
IsoStream **filtered)
|
||||
{
|
||||
IsoStream *str;
|
||||
XorEncryptStreamData *data;
|
||||
|
||||
if (filter == NULL || original == NULL || filtered == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
str = malloc(sizeof(IsoStream));
|
||||
if (str == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(XorEncryptStreamData));
|
||||
if (str == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* fill data */
|
||||
data->key = *((uint8_t*)filter->data);
|
||||
data->id = xor_ino_id++;
|
||||
|
||||
/* get reference to the source */
|
||||
data->orig = original;
|
||||
iso_stream_ref(original);
|
||||
|
||||
str->refcount = 1;
|
||||
str->data = data;
|
||||
str->class = &xor_encrypt_stream_class;
|
||||
|
||||
*filtered = str;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int create_xor_encrypt_filter(uint8_t key, FilterContext **filter)
|
||||
{
|
||||
FilterContext *f;
|
||||
uint8_t *data;
|
||||
|
||||
f = calloc(1, sizeof(FilterContext));
|
||||
if (f == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(uint8_t));
|
||||
if (data == NULL) {
|
||||
free(f);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
f->refcount = 1;
|
||||
f->version = 0;
|
||||
*data = key;
|
||||
f->data = data;
|
||||
f->free = xor_encrypt_filter_free;
|
||||
f->get_filter = xor_encrypt_filter_get_filter;
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
1149
libisofs/filters/zisofs.c
Normal file
1149
libisofs/filters/zisofs.c
Normal file
File diff suppressed because it is too large
Load Diff
761
libisofs/find.c
Normal file
761
libisofs/find.c
Normal file
@ -0,0 +1,761 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "node.h"
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <string.h>
|
||||
|
||||
struct iso_find_condition
|
||||
{
|
||||
/*
|
||||
* Check whether the given node matches this condition.
|
||||
*
|
||||
* @param cond
|
||||
* The condition to check
|
||||
* @param node
|
||||
* The node that should be checked
|
||||
* @return
|
||||
* 1 if the node matches the condition, 0 if not
|
||||
*/
|
||||
int (*matches)(IsoFindCondition *cond, IsoNode *node);
|
||||
|
||||
/**
|
||||
* Free condition specific data
|
||||
*/
|
||||
void (*free)(IsoFindCondition*);
|
||||
|
||||
/** condition specific data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct find_iter_data
|
||||
{
|
||||
IsoDir *dir; /**< original dir of the iterator */
|
||||
IsoDirIter *iter;
|
||||
IsoDirIter *itersec; /**< iterator to deal with child dirs */
|
||||
IsoFindCondition *cond;
|
||||
int err; /**< error? */
|
||||
IsoNode *current; /**< node to be returned next */
|
||||
IsoNode *prev; /**< last returned node, needed for removal */
|
||||
int free_cond; /**< whether to free cond on iter_free */
|
||||
};
|
||||
|
||||
static
|
||||
int get_next(struct find_iter_data *iter, IsoNode **n)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (iter->itersec != NULL) {
|
||||
ret = iso_dir_iter_next(iter->itersec, n);
|
||||
if (ret <= 0) {
|
||||
/* secondary item no more needed */
|
||||
iso_dir_iter_free(iter->itersec);
|
||||
iter->itersec = NULL;
|
||||
}
|
||||
if (ret != 0) {
|
||||
/* succes or error */
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* we reach here if:
|
||||
* - no secondary item is present
|
||||
* - secondary item has no more items
|
||||
*/
|
||||
|
||||
while ((ret = iso_dir_iter_next(iter->iter, n)) == 1) {
|
||||
if (iter->cond->matches(iter->cond, *n)) {
|
||||
return ISO_SUCCESS;
|
||||
} else if (ISO_NODE_IS_DIR(*n)) {
|
||||
/* recurse on child dir */
|
||||
struct find_iter_data *data;
|
||||
ret = iso_dir_find_children((IsoDir*)*n, iter->cond,
|
||||
&iter->itersec);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
data = iter->itersec->data;
|
||||
data->free_cond = 0; /* we don't need sec iter to free cond */
|
||||
return get_next(iter, n);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
void update_next(IsoDirIter *iter)
|
||||
{
|
||||
int ret;
|
||||
IsoNode *n;
|
||||
struct find_iter_data *data = iter->data;
|
||||
|
||||
if (data->prev) {
|
||||
iso_node_unref(data->prev);
|
||||
}
|
||||
data->prev = data->current;
|
||||
|
||||
if (data->itersec == NULL && data->current != NULL
|
||||
&& ISO_NODE_IS_DIR(data->current)) {
|
||||
|
||||
/* we need to recurse on child dir */
|
||||
struct find_iter_data *data2;
|
||||
ret = iso_dir_find_children((IsoDir*)data->current, data->cond,
|
||||
&data->itersec);
|
||||
if (ret < 0) {
|
||||
data->current = NULL;
|
||||
data->err = ret;
|
||||
return;
|
||||
}
|
||||
data2 = data->itersec->data;
|
||||
data2->free_cond = 0; /* we don't need sec iter to free cond */
|
||||
}
|
||||
|
||||
ret = get_next(data, &n);
|
||||
iso_node_unref((IsoNode*)iter->dir);
|
||||
if (ret == 1) {
|
||||
data->current = n;
|
||||
iso_node_ref(n);
|
||||
data->err = 0;
|
||||
iter->dir = n->parent;
|
||||
} else {
|
||||
data->current = NULL;
|
||||
data->err = ret;
|
||||
iter->dir = data->dir;
|
||||
}
|
||||
iso_node_ref((IsoNode*)iter->dir);
|
||||
}
|
||||
|
||||
static
|
||||
int find_iter_next(IsoDirIter *iter, IsoNode **node)
|
||||
{
|
||||
struct find_iter_data *data = iter->data;
|
||||
|
||||
if (iter == NULL || node == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (data->err < 0) {
|
||||
return data->err;
|
||||
}
|
||||
*node = data->current;
|
||||
update_next(iter);
|
||||
return (*node == NULL) ? 0 : ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int find_iter_has_next(IsoDirIter *iter)
|
||||
{
|
||||
struct find_iter_data *data = iter->data;
|
||||
|
||||
return (data->current != NULL);
|
||||
}
|
||||
|
||||
static
|
||||
void find_iter_free(IsoDirIter *iter)
|
||||
{
|
||||
struct find_iter_data *data = iter->data;
|
||||
if (data->free_cond) {
|
||||
data->cond->free(data->cond);
|
||||
free(data->cond);
|
||||
}
|
||||
|
||||
iso_node_unref((IsoNode*)data->dir);
|
||||
|
||||
/* free refs to nodes */
|
||||
if (data->prev) {
|
||||
iso_node_unref(data->prev);
|
||||
}
|
||||
if (data->current) {
|
||||
iso_node_unref(data->current);
|
||||
}
|
||||
|
||||
/* free underlying iter */
|
||||
iso_dir_iter_free(data->iter);
|
||||
free(iter->data);
|
||||
}
|
||||
|
||||
static
|
||||
int find_iter_take(IsoDirIter *iter)
|
||||
{
|
||||
struct find_iter_data *data = iter->data;
|
||||
|
||||
if (data->prev == NULL) {
|
||||
return ISO_ERROR; /* next not called or end of dir */
|
||||
}
|
||||
return iso_node_take(data->prev);
|
||||
}
|
||||
|
||||
static
|
||||
int find_iter_remove(IsoDirIter *iter)
|
||||
{
|
||||
struct find_iter_data *data = iter->data;
|
||||
|
||||
if (data->prev == NULL) {
|
||||
return ISO_ERROR; /* next not called or end of dir */
|
||||
}
|
||||
return iso_node_remove(data->prev);
|
||||
}
|
||||
|
||||
void find_notify_child_taken(IsoDirIter *iter, IsoNode *node)
|
||||
{
|
||||
struct find_iter_data *data = iter->data;
|
||||
|
||||
if (data->prev == node) {
|
||||
/* free our ref */
|
||||
iso_node_unref(node);
|
||||
data->prev = NULL;
|
||||
} else if (data->current == node) {
|
||||
iso_node_unref(node);
|
||||
data->current = NULL;
|
||||
update_next(iter);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
struct iso_dir_iter_iface find_iter_class = {
|
||||
find_iter_next,
|
||||
find_iter_has_next,
|
||||
find_iter_free,
|
||||
find_iter_take,
|
||||
find_iter_remove,
|
||||
find_notify_child_taken
|
||||
};
|
||||
|
||||
int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
|
||||
IsoDirIter **iter)
|
||||
{
|
||||
int ret;
|
||||
IsoDirIter *children;
|
||||
IsoDirIter *it;
|
||||
struct find_iter_data *data;
|
||||
|
||||
if (dir == NULL || cond == NULL || iter == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
it = malloc(sizeof(IsoDirIter));
|
||||
if (it == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(struct find_iter_data));
|
||||
if (data == NULL) {
|
||||
free(it);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
ret = iso_dir_get_children(dir, &children);
|
||||
if (ret < 0) {
|
||||
free(it);
|
||||
free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
it->class = &find_iter_class;
|
||||
it->dir = (IsoDir*)dir;
|
||||
data->iter = children;
|
||||
data->itersec = NULL;
|
||||
data->cond = cond;
|
||||
data->free_cond = 1;
|
||||
data->err = 0;
|
||||
data->prev = data->current = NULL;
|
||||
it->data = data;
|
||||
|
||||
if (iso_dir_iter_register(it) < 0) {
|
||||
free(it);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
iso_node_ref((IsoNode*)dir);
|
||||
|
||||
/* take another ref to the original dir */
|
||||
data->dir = (IsoDir*)dir;
|
||||
iso_node_ref((IsoNode*)dir);
|
||||
|
||||
update_next(it);
|
||||
|
||||
*iter = it;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/*************** find by name wildcard condition *****************/
|
||||
|
||||
static
|
||||
int cond_name_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
char *pattern = (char*) cond->data;
|
||||
int ret = fnmatch(pattern, node->name, 0);
|
||||
return ret == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cond_name_free(IsoFindCondition *cond)
|
||||
{
|
||||
free(cond->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks if the node name matches the given
|
||||
* wildcard.
|
||||
*
|
||||
* @param wildcard
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_name(const char *wildcard)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
if (wildcard == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cond->data = strdup(wildcard);
|
||||
cond->free = cond_name_free;
|
||||
cond->matches = cond_name_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/*************** find by mode condition *****************/
|
||||
|
||||
static
|
||||
int cond_mode_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
mode_t *mask = (mode_t*) cond->data;
|
||||
return node->mode & *mask ? 1 : 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cond_mode_free(IsoFindCondition *cond)
|
||||
{
|
||||
free(cond->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks the node mode against a mode mask. It
|
||||
* can be used to check both file type and permissions.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* iso_new_find_conditions_mode(S_IFREG) : search for regular files
|
||||
* iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
|
||||
* devices where owner has write permissions.
|
||||
*
|
||||
* @param mask
|
||||
* Mode mask to AND against node mode.
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_mode(mode_t mask)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
mode_t *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(mode_t));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
*data = mask;
|
||||
cond->data = data;
|
||||
cond->free = cond_mode_free;
|
||||
cond->matches = cond_mode_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/*************** find by gid condition *****************/
|
||||
|
||||
static
|
||||
int cond_gid_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
gid_t *gid = (gid_t*) cond->data;
|
||||
return node->gid == *gid ? 1 : 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cond_gid_free(IsoFindCondition *cond)
|
||||
{
|
||||
free(cond->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks the node gid.
|
||||
*
|
||||
* @param gid
|
||||
* Desired Group Id.
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_gid(gid_t gid)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
gid_t *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(gid_t));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
*data = gid;
|
||||
cond->data = data;
|
||||
cond->free = cond_gid_free;
|
||||
cond->matches = cond_gid_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/*************** find by uid condition *****************/
|
||||
|
||||
static
|
||||
int cond_uid_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
uid_t *uid = (uid_t*) cond->data;
|
||||
return node->uid == *uid ? 1 : 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cond_uid_free(IsoFindCondition *cond)
|
||||
{
|
||||
free(cond->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks the node uid.
|
||||
*
|
||||
* @param uid
|
||||
* Desired User Id.
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_uid(uid_t uid)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
uid_t *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(uid_t));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
*data = uid;
|
||||
cond->data = data;
|
||||
cond->free = cond_uid_free;
|
||||
cond->matches = cond_uid_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/*************** find by timestamps condition *****************/
|
||||
|
||||
struct cond_times
|
||||
{
|
||||
time_t time;
|
||||
int what_time; /* 0 atime, 1 mtime, 2 ctime */
|
||||
enum iso_find_comparisons comparison;
|
||||
};
|
||||
|
||||
static
|
||||
int cond_time_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
time_t node_time;
|
||||
struct cond_times *data = cond->data;
|
||||
|
||||
switch (data->what_time) {
|
||||
case 0: node_time = node->atime; break;
|
||||
case 1: node_time = node->mtime; break;
|
||||
default: node_time = node->ctime; break;
|
||||
}
|
||||
|
||||
switch (data->comparison) {
|
||||
case ISO_FIND_COND_GREATER:
|
||||
return node_time > data->time ? 1 : 0;
|
||||
case ISO_FIND_COND_GREATER_OR_EQUAL:
|
||||
return node_time >= data->time ? 1 : 0;
|
||||
case ISO_FIND_COND_EQUAL:
|
||||
return node_time == data->time ? 1 : 0;
|
||||
case ISO_FIND_COND_LESS:
|
||||
return node_time < data->time ? 1 : 0;
|
||||
case ISO_FIND_COND_LESS_OR_EQUAL:
|
||||
return node_time <= data->time ? 1 : 0;
|
||||
}
|
||||
/* should never happen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cond_time_free(IsoFindCondition *cond)
|
||||
{
|
||||
free(cond->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks the time of last access.
|
||||
*
|
||||
* @param time
|
||||
* Time to compare against IsoNode atime.
|
||||
* @param comparison
|
||||
* Comparison to be done between IsoNode atime and submitted time.
|
||||
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
|
||||
* time is greater than the submitted time.
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_atime(time_t time,
|
||||
enum iso_find_comparisons comparison)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
struct cond_times *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(struct cond_times));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
data->time = time;
|
||||
data->comparison = comparison;
|
||||
data->what_time = 0; /* atime */
|
||||
cond->data = data;
|
||||
cond->free = cond_time_free;
|
||||
cond->matches = cond_time_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks the time of last modification.
|
||||
*
|
||||
* @param time
|
||||
* Time to compare against IsoNode mtime.
|
||||
* @param comparison
|
||||
* Comparison to be done between IsoNode mtime and submitted time.
|
||||
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
|
||||
* time is greater than the submitted time.
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
|
||||
enum iso_find_comparisons comparison)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
struct cond_times *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(struct cond_times));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
data->time = time;
|
||||
data->comparison = comparison;
|
||||
data->what_time = 1; /* mtime */
|
||||
cond->data = data;
|
||||
cond->free = cond_time_free;
|
||||
cond->matches = cond_time_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that checks the time of last status change.
|
||||
*
|
||||
* @param time
|
||||
* Time to compare against IsoNode ctime.
|
||||
* @param comparison
|
||||
* Comparison to be done between IsoNode ctime and submitted time.
|
||||
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
|
||||
* time is greater than the submitted time.
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
|
||||
enum iso_find_comparisons comparison)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
struct cond_times *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(struct cond_times));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
data->time = time;
|
||||
data->comparison = comparison;
|
||||
data->what_time = 2; /* ctime */
|
||||
cond->data = data;
|
||||
cond->free = cond_time_free;
|
||||
cond->matches = cond_time_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
/*************** logical operations on conditions *****************/
|
||||
|
||||
struct logical_binary_conditions {
|
||||
IsoFindCondition *a;
|
||||
IsoFindCondition *b;
|
||||
};
|
||||
|
||||
static
|
||||
void cond_logical_binary_free(IsoFindCondition *cond)
|
||||
{
|
||||
struct logical_binary_conditions *data;
|
||||
data = cond->data;
|
||||
data->a->free(data->a);
|
||||
free(data->a);
|
||||
data->b->free(data->b);
|
||||
free(data->b);
|
||||
free(cond->data);
|
||||
}
|
||||
|
||||
static
|
||||
int cond_logical_and_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
struct logical_binary_conditions *data = cond->data;
|
||||
return data->a->matches(data->a, node) && data->b->matches(data->b, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that check if the two given conditions are
|
||||
* valid.
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
* IsoFindCondition to compare
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
|
||||
IsoFindCondition *b)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
struct logical_binary_conditions *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(struct logical_binary_conditions));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
data->a = a;
|
||||
data->b = b;
|
||||
cond->data = data;
|
||||
cond->free = cond_logical_binary_free;
|
||||
cond->matches = cond_logical_and_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
static
|
||||
int cond_logical_or_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
struct logical_binary_conditions *data = cond->data;
|
||||
return data->a->matches(data->a, node) || data->b->matches(data->b, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that check if at least one the two given conditions
|
||||
* is valid.
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
* IsoFindCondition to compare
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
|
||||
IsoFindCondition *b)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
struct logical_binary_conditions *data;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(sizeof(struct logical_binary_conditions));
|
||||
if (data == NULL) {
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
data->a = a;
|
||||
data->b = b;
|
||||
cond->data = data;
|
||||
cond->free = cond_logical_binary_free;
|
||||
cond->matches = cond_logical_or_matches;
|
||||
return cond;
|
||||
}
|
||||
|
||||
static
|
||||
void cond_not_free(IsoFindCondition *cond)
|
||||
{
|
||||
IsoFindCondition *negate = cond->data;
|
||||
negate->free(negate);
|
||||
free(negate);
|
||||
}
|
||||
|
||||
static
|
||||
int cond_not_matches(IsoFindCondition *cond, IsoNode *node)
|
||||
{
|
||||
IsoFindCondition *negate = cond->data;
|
||||
return !(negate->matches(negate, node));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new condition that check if the given conditions is false.
|
||||
*
|
||||
* @param negate
|
||||
* @result
|
||||
* The created IsoFindCondition, NULL on error.
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate)
|
||||
{
|
||||
IsoFindCondition *cond;
|
||||
cond = malloc(sizeof(IsoFindCondition));
|
||||
if (cond == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cond->data = negate;
|
||||
cond->free = cond_not_free;
|
||||
cond->matches = cond_not_matches;
|
||||
return cond;
|
||||
}
|
||||
|
1528
libisofs/fs_image.c
1528
libisofs/fs_image.c
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
@ -12,6 +13,7 @@
|
||||
|
||||
#include "fsource.h"
|
||||
#include "util.h"
|
||||
#include "aaip_0_2.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
@ -32,6 +34,7 @@ int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
|
||||
*/
|
||||
IsoFilesystem *lfs= NULL;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/** reference to the parent (if root it points to itself) */
|
||||
@ -190,7 +193,7 @@ int lfs_open(IsoFileSource *src)
|
||||
|
||||
data = src->data;
|
||||
if (data->openned) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
/* is a file or a dir ? */
|
||||
@ -251,7 +254,7 @@ int lfs_close(IsoFileSource *src)
|
||||
ret = closedir(data->info.dir) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR;
|
||||
break;
|
||||
default:
|
||||
ret = ISO_FILE_NOT_OPENNED;
|
||||
ret = ISO_FILE_NOT_OPENED;
|
||||
break;
|
||||
}
|
||||
if (ret == ISO_SUCCESS) {
|
||||
@ -300,7 +303,53 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count)
|
||||
case 2: /* directory */
|
||||
return ISO_FILE_IS_DIR;
|
||||
default:
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag)
|
||||
{
|
||||
_LocalFsFileSource *data;
|
||||
int whence;
|
||||
|
||||
if (src == NULL) {
|
||||
return (off_t)ISO_NULL_POINTER;
|
||||
}
|
||||
switch (flag) {
|
||||
case 0:
|
||||
whence = SEEK_SET; break;
|
||||
case 1:
|
||||
whence = SEEK_CUR; break;
|
||||
case 2:
|
||||
whence = SEEK_END; break;
|
||||
default:
|
||||
return (off_t)ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
|
||||
data = src->data;
|
||||
switch (data->openned) {
|
||||
case 1: /* not dir */
|
||||
{
|
||||
off_t ret;
|
||||
ret = lseek(data->info.fd, offset, whence);
|
||||
if (ret < 0) {
|
||||
/* error on read */
|
||||
switch (errno) {
|
||||
case ESPIPE:
|
||||
ret = (off_t)ISO_FILE_ERROR;
|
||||
break;
|
||||
default:
|
||||
ret = (off_t)ISO_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
case 2: /* directory */
|
||||
return (off_t)ISO_FILE_IS_DIR;
|
||||
default:
|
||||
return (off_t)ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,7 +390,7 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,8 +469,60 @@ void lfs_free(IsoFileSource *src)
|
||||
iso_filesystem_unref(lfs);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int lfs_get_aa_string(IsoFileSource *src, unsigned char **aa_string, int flag)
|
||||
{
|
||||
int ret;
|
||||
size_t num_attrs = 0, *value_lengths = NULL, result_len, sret;
|
||||
char *path = NULL, **names = NULL, **values = NULL;
|
||||
unsigned char *result = NULL;
|
||||
_LocalFsFileSource *data;
|
||||
|
||||
data = src->data;
|
||||
|
||||
*aa_string = NULL;
|
||||
|
||||
if ((flag & 3 ) == 3) {
|
||||
ret = 1;
|
||||
goto ex;
|
||||
}
|
||||
/* Obtain EAs and ACLs ("access" and "default"). ACLs encoded according
|
||||
to AAIP ACL representation. Clean out st_mode ACL entries.
|
||||
*/
|
||||
path = iso_file_source_get_path(src);
|
||||
ret = aaip_get_attr_list(path, &num_attrs, &names,
|
||||
&value_lengths, &values,
|
||||
(!(flag & 2)) | 2 | (flag & 4) | 16);
|
||||
if (ret <= 0) {
|
||||
ret = ISO_FILE_ERROR;
|
||||
goto ex;
|
||||
}
|
||||
if (num_attrs == 0)
|
||||
result = NULL;
|
||||
else {
|
||||
sret = aaip_encode(num_attrs, names,
|
||||
value_lengths, values, &result_len, &result, 0);
|
||||
if (sret == 0) {
|
||||
ret = ISO_OUT_OF_MEM;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
*aa_string = result;
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (path != NULL)
|
||||
free(path);
|
||||
if (names != NULL || value_lengths != NULL || values != NULL)
|
||||
aaip_get_attr_list(path, &num_attrs, &names, &value_lengths, &values,
|
||||
1 << 15); /* free memory */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
IsoFileSourceIface lfs_class = {
|
||||
0, /* version */
|
||||
|
||||
1, /* version */
|
||||
lfs_get_path,
|
||||
lfs_get_name,
|
||||
lfs_lstat,
|
||||
@ -433,9 +534,13 @@ IsoFileSourceIface lfs_class = {
|
||||
lfs_readdir,
|
||||
lfs_readlink,
|
||||
lfs_get_filesystem,
|
||||
lfs_free
|
||||
lfs_free,
|
||||
lfs_lseek,
|
||||
lfs_get_aa_string
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
@ -643,3 +748,78 @@ int iso_local_filesystem_new(IsoFilesystem **fs)
|
||||
*fs = lfs;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int iso_local_get_acl_text(char *disk_path, char **text, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aaip_get_acl_text(disk_path, text, flag & (1 | 16 | 32 | (1 << 15)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int iso_local_set_acl_text(char *disk_path, char *text, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aaip_set_acl_text(disk_path, text, flag & (1 | 32));
|
||||
if (ret < 0)
|
||||
return ISO_AAIP_NO_SET_LOCAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int iso_local_get_attrs(char *disk_path, size_t *num_attrs, char ***names,
|
||||
size_t **value_lengths, char ***values, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aaip_get_attr_list(disk_path,
|
||||
num_attrs, names, value_lengths, values,
|
||||
(flag & (1 | 4 | 8 | 32 | (1 << 15))) | 2 | 16);
|
||||
if (ret <= 0)
|
||||
return ISO_AAIP_NO_GET_LOCAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int iso_local_set_attrs(char *disk_path, size_t num_attrs, char **names,
|
||||
size_t *value_lengths, char **values, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aaip_set_attr_list(disk_path, num_attrs, names, value_lengths,
|
||||
values, (flag & (8 | 32)) | !(flag & 1));
|
||||
if (ret <= 0) {
|
||||
if (ret == -1)
|
||||
return ISO_OUT_OF_MEM;
|
||||
if (ret == -2)
|
||||
return ISO_AAIP_BAD_AASTRING;
|
||||
return ISO_AAIP_NO_SET_LOCAL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int iso_local_get_perms_wo_acl(char *disk_path, mode_t *st_mode, int flag)
|
||||
{
|
||||
struct stat stbuf;
|
||||
int ret;
|
||||
char *a_text = NULL;
|
||||
|
||||
if (flag & 32)
|
||||
ret = stat(disk_path, &stbuf);
|
||||
else
|
||||
ret = lstat(disk_path, &stbuf);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
*st_mode = stbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
ret = iso_local_get_acl_text(disk_path, &a_text, 16 | (flag & 32));
|
||||
if (a_text != NULL) {
|
||||
aaip_cleanout_st_mode(a_text, st_mode, 4 | 16);
|
||||
iso_local_get_acl_text(disk_path, &a_text, 1 << 15); /* free a_text */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
|
||||
return src->class->read(src, buf, count);
|
||||
}
|
||||
|
||||
inline
|
||||
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag)
|
||||
{
|
||||
return src->class->lseek(src, offset, flag);
|
||||
}
|
||||
|
||||
inline
|
||||
int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||
{
|
||||
@ -109,3 +115,16 @@ IsoFilesystem* iso_file_source_get_filesystem(IsoFileSource *src)
|
||||
{
|
||||
return src->class->get_filesystem(src);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
int iso_file_source_get_aa_string(IsoFileSource *src,
|
||||
unsigned char **aa_string, int flag)
|
||||
{
|
||||
if (src->class->version < 1) {
|
||||
*aa_string = NULL;
|
||||
return 1;
|
||||
}
|
||||
return src->class->get_aa_string(src, aa_string, flag);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
@ -20,6 +21,7 @@
|
||||
#define ISO_IMAGE_FS_ID 2
|
||||
#define ISO_ELTORITO_FS_ID 3
|
||||
#define ISO_MEM_FS_ID 4
|
||||
#define ISO_FILTER_FS_ID 5
|
||||
|
||||
/**
|
||||
* Create a new IsoFilesystem to deal with local filesystem.
|
||||
@ -29,4 +31,10 @@
|
||||
*/
|
||||
int iso_local_filesystem_new(IsoFilesystem **fs);
|
||||
|
||||
|
||||
/* Rank two IsoFileSource by their eventual old image LBAs.
|
||||
Other IsoFileSource classes will be ranked only roughly.
|
||||
*/
|
||||
int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int flag);
|
||||
|
||||
#endif /*LIBISO_FSOURCE_H_*/
|
||||
|
272
libisofs/image.c
272
libisofs/image.c
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -14,12 +15,13 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* Create a new image, empty.
|
||||
*
|
||||
*
|
||||
* The image will be owned by you and should be unref() when no more needed.
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* Name of the image. This will be used as volset_id and volume_id.
|
||||
* @param image
|
||||
@ -71,6 +73,11 @@ int iso_image_new(const char *name, IsoImage **image)
|
||||
img->volset_id = strdup(name);
|
||||
img->volume_id = strdup(name);
|
||||
}
|
||||
img->builder_ignore_acl = 1;
|
||||
img->builder_ignore_ea = 1;
|
||||
img->inode_counter = 0;
|
||||
img->used_inodes = NULL;
|
||||
img->used_inodes_start = 0;
|
||||
*image = img;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
@ -85,7 +92,7 @@ void iso_image_ref(IsoImage *image)
|
||||
|
||||
/**
|
||||
* Decrements the reference couting of the given image.
|
||||
* If it reaches 0, the image is free, together with its tree nodes (whether
|
||||
* If it reaches 0, the image is free, together with its tree nodes (whether
|
||||
* their refcount reach 0 too, of course).
|
||||
*/
|
||||
void iso_image_unref(IsoImage *image)
|
||||
@ -117,6 +124,8 @@ void iso_image_unref(IsoImage *image)
|
||||
free(image->copyright_file_id);
|
||||
free(image->abstract_file_id);
|
||||
free(image->biblio_file_id);
|
||||
if (image->used_inodes != NULL)
|
||||
free(image->used_inodes);
|
||||
free(image);
|
||||
}
|
||||
}
|
||||
@ -125,7 +134,7 @@ void iso_image_unref(IsoImage *image)
|
||||
* Attach user defined data to the image. Use this if your application needs
|
||||
* to store addition info together with the IsoImage. If the image already
|
||||
* has data attached, the old data will be freed.
|
||||
*
|
||||
*
|
||||
* @param data
|
||||
* Pointer to application defined data that will be attached to the
|
||||
* image. You can pass NULL to remove any already attached data.
|
||||
@ -139,7 +148,7 @@ int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
|
||||
if (image == NULL || (data != NULL && free == NULL)) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
|
||||
if (image->user_data != NULL) {
|
||||
/* free previously attached data */
|
||||
if (image->user_data_free) {
|
||||
@ -148,7 +157,7 @@ int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
|
||||
image->user_data = NULL;
|
||||
image->user_data_free = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (data != NULL) {
|
||||
image->user_data = data;
|
||||
image->user_data_free = give_up;
|
||||
@ -275,3 +284,248 @@ int iso_image_get_msg_id(IsoImage *image)
|
||||
{
|
||||
return image->id;
|
||||
}
|
||||
|
||||
static
|
||||
int dir_update_size(IsoImage *image, IsoDir *dir)
|
||||
{
|
||||
IsoNode *pos;
|
||||
pos = dir->children;
|
||||
while (pos) {
|
||||
int ret = 1;
|
||||
if (pos->type == LIBISO_FILE) {
|
||||
ret = iso_stream_update_size(ISO_FILE(pos)->stream);
|
||||
} else if (pos->type == LIBISO_DIR) {
|
||||
/* recurse */
|
||||
ret = dir_update_size(image, ISO_DIR(pos));
|
||||
}
|
||||
if (ret < 0) {
|
||||
ret = iso_msg_submit(image->id, ret, 0, NULL);
|
||||
if (ret < 0) {
|
||||
return ret; /* cancel due error threshold */
|
||||
}
|
||||
}
|
||||
pos = pos->next;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_image_update_sizes(IsoImage *image)
|
||||
{
|
||||
if (image == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
return dir_update_size(image, image->root);
|
||||
}
|
||||
|
||||
|
||||
void iso_image_set_ignore_aclea(IsoImage *image, int what)
|
||||
{
|
||||
image->builder_ignore_acl = (what & 1);
|
||||
image->builder_ignore_ea = !!(what & 2);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int img_register_ino(IsoImage *image, IsoNode *node, int flag)
|
||||
{
|
||||
int ret;
|
||||
ino_t ino;
|
||||
unsigned int fs_id;
|
||||
dev_t dev_id;
|
||||
|
||||
ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0 && ino >= image->used_inodes_start &&
|
||||
ino <= image->used_inodes_start + (ISO_USED_INODE_RANGE - 1)) {
|
||||
/* without -1 : rollover hazard on 32 bit */
|
||||
image->used_inodes[(ino - image->used_inodes_start) / 8]
|
||||
|= (1 << (ino % 8));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Collect the bitmap of used inode numbers in the range of
|
||||
_ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE
|
||||
@param flag bit0= recursion is active
|
||||
*/
|
||||
int img_collect_inos(IsoImage *image, IsoDir *dir, int flag)
|
||||
{
|
||||
int ret, register_dir = 1;
|
||||
IsoDirIter *iter = NULL;
|
||||
IsoNode *node;
|
||||
IsoDir *subdir;
|
||||
|
||||
if (dir == NULL)
|
||||
dir = image->root;
|
||||
if (image->used_inodes == NULL) {
|
||||
image->used_inodes = calloc(ISO_USED_INODE_RANGE / 8, 1);
|
||||
if (image->used_inodes == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
} else if(!(flag & 1)) {
|
||||
memset(image->used_inodes, 0, ISO_USED_INODE_RANGE / 8);
|
||||
} else {
|
||||
register_dir = 0;
|
||||
}
|
||||
if (register_dir) {
|
||||
node = (IsoNode *) dir;
|
||||
ret = img_register_ino(image, node, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iso_dir_get_children(dir, &iter);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
while (iso_dir_iter_next(iter, &node) == 1 ) {
|
||||
ret = img_register_ino(image, node, 0);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
if (iso_node_get_type(node) == LIBISO_DIR) {
|
||||
subdir = (IsoDir *) node;
|
||||
ret = img_collect_inos(image, subdir, flag | 1);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (iter != NULL)
|
||||
iso_dir_iter_free(iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A global counter for inode numbers for the ISO image filesystem.
|
||||
* On image import it gets maxed by the eventual inode numbers from PX
|
||||
* entries. Up to the first 32 bit rollover it simply increments the counter.
|
||||
* After the first rollover it uses a look ahead bitmap which gets filled
|
||||
* by a full tree traversal. It covers the next inode numbers to come
|
||||
* (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many)
|
||||
* and advances when being exhausted.
|
||||
* @param image The image where the number shall be used
|
||||
* @param flag bit0= reset count (Caution: image must get new inos then)
|
||||
* @return
|
||||
* Since ino_t 0 is used as default and considered self-unique,
|
||||
* the value 0 should only be returned in case of error.
|
||||
*/
|
||||
ino_t img_give_ino_number(IsoImage *image, int flag)
|
||||
{
|
||||
int ret;
|
||||
ino_t new_ino, ino_idx;
|
||||
static uint64_t limit = 0xffffffff;
|
||||
|
||||
if (flag & 1) {
|
||||
image->inode_counter = 0;
|
||||
if (image->used_inodes != NULL)
|
||||
free(image->used_inodes);
|
||||
image->used_inodes = NULL;
|
||||
image->used_inodes_start = 0;
|
||||
}
|
||||
new_ino = image->inode_counter + 1;
|
||||
if (image->used_inodes == NULL) {
|
||||
if (new_ino > 0 && new_ino <= limit) {
|
||||
image->inode_counter = new_ino;
|
||||
return image->inode_counter;
|
||||
}
|
||||
}
|
||||
/* Look for free number in used territory */
|
||||
while (1) {
|
||||
if (new_ino <= 0 || new_ino > limit ||
|
||||
new_ino >= image->used_inodes_start + ISO_USED_INODE_RANGE ) {
|
||||
|
||||
/* Collect a bitmap of used inode numbers ahead */
|
||||
|
||||
image->used_inodes_start += ISO_USED_INODE_RANGE;
|
||||
if (image->used_inodes_start > 0xffffffff ||
|
||||
image->used_inodes_start <= 0)
|
||||
image->used_inodes_start = 0;
|
||||
ret = img_collect_inos(image, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto return_result; /* >>> need error return value */
|
||||
|
||||
new_ino = image->used_inodes_start + !image->used_inodes_start;
|
||||
}
|
||||
ino_idx = (new_ino - image->used_inodes_start) / 8;
|
||||
if (!(image->used_inodes[ino_idx] & (1 << (new_ino % 8)))) {
|
||||
image->used_inodes[ino_idx] |= (1 << (new_ino % 8));
|
||||
break;
|
||||
}
|
||||
new_ino++;
|
||||
}
|
||||
return_result:;
|
||||
image->inode_counter = new_ino;
|
||||
return image->inode_counter;
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0= overwrite any ino, else only ino == 0
|
||||
bit1= install inode with non-data, non-directory files
|
||||
bit2= install inode with directories
|
||||
*/
|
||||
static
|
||||
int img_update_ino(IsoImage *image, IsoNode *node, int flag)
|
||||
{
|
||||
int ret;
|
||||
ino_t ino;
|
||||
unsigned int fs_id;
|
||||
dev_t dev_id;
|
||||
|
||||
ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
ino = 0;
|
||||
if (((flag & 1) || ino == 0) &&
|
||||
(iso_node_get_type(node) == LIBISO_FILE || (flag & (2 | 4))) &&
|
||||
((flag & 4) || iso_node_get_type(node) != LIBISO_DIR)) {
|
||||
ret = iso_node_set_unique_id(node, image, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0= overwrite any ino, else only ino == 0
|
||||
bit1= install inode with non-data, non-directory files
|
||||
bit2= install inode with directories
|
||||
bit3= with bit2: install inode on parameter dir
|
||||
*/
|
||||
int img_make_inos(IsoImage *image, IsoDir *dir, int flag)
|
||||
{
|
||||
int ret;
|
||||
IsoDirIter *iter = NULL;
|
||||
IsoNode *node;
|
||||
IsoDir *subdir;
|
||||
|
||||
if (flag & 8) {
|
||||
node = (IsoNode *) dir;
|
||||
ret = img_update_ino(image, node, flag & 7);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
}
|
||||
ret = iso_dir_get_children(dir, &iter);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
while (iso_dir_iter_next(iter, &node) == 1) {
|
||||
ret = img_update_ino(image, node, flag & 7);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
if (iso_node_get_type(node) == LIBISO_DIR) {
|
||||
subdir = (IsoDir *) node;
|
||||
ret = img_make_inos(image, subdir, flag & ~8);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (iter != NULL)
|
||||
iso_dir_iter_free(iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
@ -13,6 +14,14 @@
|
||||
#include "fsource.h"
|
||||
#include "builder.h"
|
||||
|
||||
/* Size of a inode recycling window. Each new window causes a tree traversal.
|
||||
Window memory consumption is ISO_USED_INODE_RANGE / 8.
|
||||
This must be a power of 2 smaller than 30 bit and larger than 8 bit.
|
||||
Here: 32 kB memory for 256k inodes.
|
||||
*/
|
||||
#define ISO_USED_INODE_RANGE (1 << 18)
|
||||
|
||||
|
||||
/*
|
||||
* Image is a context for image manipulation.
|
||||
* Global objects such as the message_queues must belogn to that
|
||||
@ -76,6 +85,20 @@ struct Iso_Image
|
||||
*/
|
||||
int ignore_special;
|
||||
|
||||
/**
|
||||
* Whether to ignore ACL when inserting nodes into the image.
|
||||
* Not in effect with loading a complete ISO image but only with image
|
||||
* manipulation.
|
||||
*/
|
||||
unsigned int builder_ignore_acl : 1;
|
||||
|
||||
/**
|
||||
* Whether to ignore EAs when inserting nodes into the image.
|
||||
* Not in effect with loading a complete ISO image but only with image
|
||||
* manipulation. ACL does not count as EA.
|
||||
*/
|
||||
unsigned int builder_ignore_ea : 1;
|
||||
|
||||
/**
|
||||
* Files to exclude. Wildcard support is included.
|
||||
*/
|
||||
@ -107,6 +130,55 @@ struct Iso_Image
|
||||
*/
|
||||
void *user_data;
|
||||
void (*user_data_free)(void *ptr);
|
||||
|
||||
/**
|
||||
* Inode number management. inode_counter is taken over from
|
||||
* IsoImageFilesystem._ImageFsData after image import.
|
||||
* It is to be used with img_give_ino_number()
|
||||
*/
|
||||
ino_t inode_counter;
|
||||
/*
|
||||
* A bitmap of used inode numbers in an interval beginning at
|
||||
* used_inodes_start and holding ISO_USED_INODE_RANGE bits.
|
||||
* If a bit is set, then the corresponding inode number is occupied.
|
||||
* This interval is kept around inode_counter and eventually gets
|
||||
* advanced by ISO_USED_INODE_RANGE numbers in a tree traversal
|
||||
* done by img_collect_inos().
|
||||
*/
|
||||
uint8_t *used_inodes;
|
||||
ino_t used_inodes_start;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Collect the bitmap of used inode numbers in the range of
|
||||
_ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE
|
||||
@param flag bit0= recursion is active
|
||||
*/
|
||||
int img_collect_inos(IsoImage *image, IsoDir *dir, int flag);
|
||||
|
||||
/**
|
||||
* A global counter for inode numbers for the ISO image filesystem.
|
||||
* On image import it gets maxed by the eventual inode numbers from PX
|
||||
* entries. Up to the first 32 bit rollover it simply increments the counter.
|
||||
* After the first rollover it uses a look ahead bitmap which gets filled
|
||||
* by a full tree traversal. It covers the next inode numbers to come
|
||||
* (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many)
|
||||
* and advances when being exhausted.
|
||||
* @param image The image where the number shall be used
|
||||
* @param flag bit0= reset count (Caution: image must get new inos then)
|
||||
* @return
|
||||
* Since ino_t 0 is used as default and considered self-unique,
|
||||
* the value 0 should only be returned in case of error.
|
||||
*/
|
||||
ino_t img_give_ino_number(IsoImage *image, int flag);
|
||||
|
||||
/* @param flag bit0= overwrite any ino, else only ino == 0
|
||||
bit1= install inode with non-data, non-directory files
|
||||
bit2= install inode with directories
|
||||
bit3= with bit2: install inode on parameter dir
|
||||
*/
|
||||
int img_make_inos(IsoImage *image, IsoDir *dir, int flag);
|
||||
|
||||
#endif /*LIBISO_IMAGE_H_*/
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -32,7 +32,7 @@ int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
|
||||
*fname = NULL;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
if (!strcmp(t->input_charset, t->output_charset)) {
|
||||
/* no conversion needed */
|
||||
name = strdup(str);
|
||||
@ -50,14 +50,14 @@ int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
|
||||
name = strdup(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ISO 9660:1999 7.5.1 */
|
||||
if (strlen(name) > 207) {
|
||||
name[207] = '\0';
|
||||
}
|
||||
|
||||
|
||||
*fname = name;
|
||||
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -117,12 +117,14 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
|
||||
IsoFile *file = (IsoFile*) iso;
|
||||
|
||||
size = iso_stream_get_size(file->stream);
|
||||
if (size > (off_t)0xffffffff) {
|
||||
free(n);
|
||||
return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) {
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
"File \"%s\" can't be added to image because is "
|
||||
"greater than 4GB", iso->name);
|
||||
return 0;
|
||||
"greater than 4GB", ipath);
|
||||
free(n);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iso_file_src_create(t, file, &src);
|
||||
@ -159,7 +161,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
|
||||
|
||||
/**
|
||||
* Create the low level ISO 9660:1999 tree from the high level ISO tree.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 success, 0 file ignored, < 0 error
|
||||
*/
|
||||
@ -185,10 +187,13 @@ int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
|
||||
|
||||
max_path = pathlen + 1 + (iso_name ? strlen(iso_name): 0);
|
||||
if (!t->allow_longer_paths && max_path > 255) {
|
||||
free(iso_name);
|
||||
return iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
"File \"%s\" can't be added to ISO 9660:1999 tree, "
|
||||
"because its path length is larger than 255", iso->name);
|
||||
"because its path length is larger than 255", ipath);
|
||||
free(iso_name);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (iso->type) {
|
||||
@ -230,16 +235,19 @@ int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
|
||||
} else {
|
||||
/* log and ignore */
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
|
||||
"El-Torito catalog found on a image without El-Torito.",
|
||||
iso->name);
|
||||
"El-Torito catalog found on a image without El-Torito.");
|
||||
}
|
||||
break;
|
||||
case LIBISO_SYMLINK:
|
||||
case LIBISO_SPECIAL:
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
|
||||
{
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
|
||||
"Can't add %s to ISO 9660:1999 tree. This kind of files "
|
||||
"can only be added to a Rock Ridget tree. Skipping.",
|
||||
iso->name);
|
||||
"can only be added to a Rock Ridget tree. Skipping.",
|
||||
ipath);
|
||||
free(ipath);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
@ -269,15 +277,15 @@ cmp_node(const void *f1, const void *f2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the entries inside an ISO 9660:1999 directory, according to
|
||||
* ISO 9660:1999, 9.3
|
||||
* Sort the entries inside an ISO 9660:1999 directory, according to
|
||||
* ISO 9660:1999, 9.3
|
||||
*/
|
||||
static
|
||||
static
|
||||
void sort_tree(Iso1999Node *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
qsort(root->info.dir->children, root->info.dir->nchildren,
|
||||
qsort(root->info.dir->children, root->info.dir->nchildren,
|
||||
sizeof(void*), cmp_node);
|
||||
for (i = 0; i < root->info.dir->nchildren; i++) {
|
||||
Iso1999Node *child = root->info.dir->children[i];
|
||||
@ -297,9 +305,9 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
|
||||
nchildren = dir->info.dir->nchildren;
|
||||
children = dir->info.dir->children;
|
||||
|
||||
|
||||
/* a hash table will temporary hold the names, for fast searching */
|
||||
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||
(compare_function_t)strcmp, &table);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -320,7 +328,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
int digits = 1; /* characters to change per name */
|
||||
|
||||
/* first, find all child with same name */
|
||||
while (j + 1 < nchildren &&
|
||||
while (j + 1 < nchildren &&
|
||||
!cmp_node(children + i, children + j + 1)) {
|
||||
++j;
|
||||
}
|
||||
@ -330,7 +338,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
}
|
||||
|
||||
/*
|
||||
* A max of 7 characters is good enought, it allows handling up to
|
||||
* A max of 7 characters is good enought, it allows handling up to
|
||||
* 9,999,999 files with same name.
|
||||
*/
|
||||
while (digits < 8) {
|
||||
@ -345,7 +353,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
dot = strrchr(full_name, '.');
|
||||
if (dot != NULL && children[i]->type != ISO1999_DIR) {
|
||||
|
||||
/*
|
||||
/*
|
||||
* File (not dir) with extension.
|
||||
*/
|
||||
int extlen;
|
||||
@ -358,17 +366,17 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
if (max <= 0) {
|
||||
/* this can happen if extension is too long */
|
||||
if (extlen + max > 3) {
|
||||
/*
|
||||
/*
|
||||
* reduce extension len, to give name an extra char
|
||||
* note that max is negative or 0
|
||||
* note that max is negative or 0
|
||||
*/
|
||||
extlen = extlen + max - 1;
|
||||
ext[extlen] = '\0';
|
||||
max = 207 - extlen - 1 - digits;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* error, we don't support extensions < 3
|
||||
* This can't happen with current limit of digits.
|
||||
* This can't happen with current limit of digits.
|
||||
*/
|
||||
ret = ISO_ERROR;
|
||||
goto mangle_cleanup;
|
||||
@ -428,7 +436,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
children[k]->name = new;
|
||||
iso_htable_add(table, new, new);
|
||||
|
||||
/*
|
||||
/*
|
||||
* if we change a name we need to sort again children
|
||||
* at the end
|
||||
*/
|
||||
@ -459,7 +467,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
|
||||
|
||||
mangle_cleanup : ;
|
||||
iso_htable_destroy(table, NULL);
|
||||
return ret;
|
||||
@ -494,7 +502,7 @@ int iso1999_tree_create(Ecma119Image *t)
|
||||
{
|
||||
int ret;
|
||||
Iso1999Node *root;
|
||||
|
||||
|
||||
if (t == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
@ -507,7 +515,7 @@ int iso1999_tree_create(Ecma119Image *t)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* the ISO 9660:1999 tree is stored in Ecma119Image target */
|
||||
t->iso1999_root = root;
|
||||
|
||||
@ -549,20 +557,25 @@ size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||
size_t remaining;
|
||||
int section, nsections;
|
||||
Iso1999Node *child = dir->info.dir->children[i];
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
|
||||
nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The size of a dir is always a multiple of block size, as we must add
|
||||
* the size of the unused space after the last directory record
|
||||
* The size of a dir is always a multiple of block size, as we must add
|
||||
* the size of the unused space after the last directory record
|
||||
* (ISO 9660:1999, 6.8.1.3)
|
||||
*/
|
||||
len = ROUND_UP(len, BLOCK_SIZE);
|
||||
@ -626,7 +639,7 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
t = writer->target;
|
||||
|
||||
/* compute position of directories */
|
||||
iso_msg_debug(t->image->id,
|
||||
iso_msg_debug(t->image->id,
|
||||
"Computing position of ISO 9660:1999 dir structure");
|
||||
t->iso1999_ndirs = 0;
|
||||
calc_dir_pos(t, t->iso1999_root);
|
||||
@ -647,7 +660,7 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
|
||||
/**
|
||||
* Write a single directory record (ISO 9660:1999, 9.1).
|
||||
*
|
||||
*
|
||||
* @param file_id
|
||||
* if >= 0, we use it instead of the filename (for "." and ".." entries).
|
||||
* @param len_fi
|
||||
@ -655,11 +668,12 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
*/
|
||||
static
|
||||
void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
|
||||
uint8_t *buf, size_t len_fi)
|
||||
uint8_t *buf, size_t len_fi, int extent)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr; /*< size of dir entry */
|
||||
int multi_extend = 0;
|
||||
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
|
||||
: (uint8_t*)node->name;
|
||||
|
||||
@ -674,12 +688,13 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
|
||||
len = node->info.dir->len;
|
||||
block = node->info.dir->block;
|
||||
} else if (node->type == ISO1999_FILE) {
|
||||
len = iso_file_src_get_size(node->info.file);
|
||||
block = node->info.file->block;
|
||||
block = node->info.file->sections[extent].block;
|
||||
len = node->info.file->sections[extent].size;
|
||||
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
|
||||
} else {
|
||||
/*
|
||||
* for nodes other than files and dirs, we set both
|
||||
* len and block to 0
|
||||
/*
|
||||
* for nodes other than files and dirs, we set both
|
||||
* len and block to 0
|
||||
*/
|
||||
len = 0;
|
||||
block = 0;
|
||||
@ -695,20 +710,20 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
|
||||
rec->flags[0] = (node->type == ISO1999_DIR) ? 2 : 0;
|
||||
rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
|
||||
* Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
|
||||
*/
|
||||
static
|
||||
int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
{
|
||||
IsoImage *image;
|
||||
Ecma119Image *t;
|
||||
|
||||
|
||||
/* The enhanced volume descriptor is like the sup vol desc */
|
||||
struct ecma119_sup_vol_desc vol;
|
||||
|
||||
@ -741,7 +756,7 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
|
||||
vol.vol_desc_type[0] = 2;
|
||||
memcpy(vol.std_identifier, "CD001", 5);
|
||||
|
||||
|
||||
/* descriptor version is 2 (ISO/IEC 9660:1999, 8.5.2) */
|
||||
vol.vol_desc_version[0] = 2;
|
||||
strncpy_pad((char*)vol.volume_id, vol_id, 32);
|
||||
@ -754,12 +769,12 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
iso_lsb(vol.l_path_table_pos, t->iso1999_l_path_table_pos, 4);
|
||||
iso_msb(vol.m_path_table_pos, t->iso1999_m_path_table_pos, 4);
|
||||
|
||||
write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1);
|
||||
write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1, 0);
|
||||
|
||||
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
|
||||
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
|
||||
strncpy_pad((char*)vol.data_prep_id, data_id, 128);
|
||||
|
||||
|
||||
strncpy_pad((char*)vol.system_id, system_id, 32);
|
||||
|
||||
strncpy_pad((char*)vol.application_id, application_id, 128);
|
||||
@ -801,30 +816,34 @@ int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf, 1);
|
||||
write_one_dir_record(t, dir, 0, buf, 1, 0);
|
||||
buf += 34;
|
||||
write_one_dir_record(t, dir, 1, buf, 1);
|
||||
write_one_dir_record(t, dir, 1, buf, 1, 0);
|
||||
buf += 34;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
int section, nsections;
|
||||
Iso1999Node *child = dir->info.dir->children[i];
|
||||
|
||||
/* compute len of directory entry */
|
||||
fi_len = strlen(child->name);
|
||||
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, section);
|
||||
buf += len;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len);
|
||||
buf += len;
|
||||
}
|
||||
|
||||
/* write the last block */
|
||||
@ -1000,7 +1019,7 @@ int iso1999_writer_create(Ecma119Image *target)
|
||||
writer->data = NULL;
|
||||
writer->target = target;
|
||||
|
||||
iso_msg_debug(target->image->id,
|
||||
iso_msg_debug(target->image->id,
|
||||
"Creating low level ISO 9660:1999 tree...");
|
||||
ret = iso1999_tree_create(target);
|
||||
if (ret < 0) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2007 Mario Danic
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
#include "image.h"
|
||||
#include "filesrc.h"
|
||||
#include "eltorito.h"
|
||||
#include "libisofs.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -47,7 +49,7 @@ int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name)
|
||||
*name = jname;
|
||||
return ISO_SUCCESS;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* only possible if mem error, as check for empty names is done
|
||||
* in public tree
|
||||
*/
|
||||
@ -111,11 +113,14 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
|
||||
IsoFile *file = (IsoFile*) iso;
|
||||
|
||||
size = iso_stream_get_size(file->stream);
|
||||
if (size > (off_t)0xffffffff) {
|
||||
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) {
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
free(joliet);
|
||||
return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
"File \"%s\" can't be added to image because is "
|
||||
"greater than 4GB", iso->name);
|
||||
"greater than 4GB", ipath);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iso_file_src_create(t, file, &src);
|
||||
@ -152,7 +157,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
|
||||
|
||||
/**
|
||||
* Create the low level Joliet tree from the high level ISO tree.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 success, 0 file ignored, < 0 error
|
||||
*/
|
||||
@ -177,14 +182,17 @@ int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
|
||||
}
|
||||
max_path = pathlen + 1 + (jname ? ucslen(jname) * 2 : 0);
|
||||
if (!t->joliet_longer_paths && max_path > 240) {
|
||||
free(jname);
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
/*
|
||||
* Wow!! Joliet is even more restrictive than plain ISO-9660,
|
||||
* that allows up to 255 bytes!!
|
||||
*/
|
||||
return iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||
"File \"%s\" can't be added to Joliet tree, because "
|
||||
"its path length is larger than 240", iso->name);
|
||||
"its path length is larger than 240", ipath);
|
||||
free(jname);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (iso->type) {
|
||||
@ -226,15 +234,19 @@ int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
|
||||
} else {
|
||||
/* log and ignore */
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
|
||||
"El-Torito catalog found on a image without El-Torito.",
|
||||
iso->name);
|
||||
"El-Torito catalog found on a image without El-Torito.");
|
||||
}
|
||||
break;
|
||||
case LIBISO_SYMLINK:
|
||||
case LIBISO_SPECIAL:
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
|
||||
"Can't add %s to Joliet tree. This kind of files can only"
|
||||
" be added to a Rock Ridget tree. Skipping.", iso->name);
|
||||
{
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
|
||||
"Can't add %s to Joliet tree. %s can only be added to a "
|
||||
"Rock Ridget tree.", ipath, (iso->type == LIBISO_SYMLINK ?
|
||||
"Symlinks" : "Special files"));
|
||||
free(ipath);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
@ -257,12 +269,12 @@ cmp_node(const void *f1, const void *f2)
|
||||
return ucscmp(f->name, g->name);
|
||||
}
|
||||
|
||||
static
|
||||
static
|
||||
void sort_tree(JolietNode *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
qsort(root->info.dir->children, root->info.dir->nchildren,
|
||||
qsort(root->info.dir->children, root->info.dir->nchildren,
|
||||
sizeof(void*), cmp_node);
|
||||
for (i = 0; i < root->info.dir->nchildren; i++) {
|
||||
JolietNode *child = root->info.dir->children[i];
|
||||
@ -286,24 +298,25 @@ int joliet_create_mangled_name(uint16_t *dest, uint16_t *src, int digits,
|
||||
int ret, pos;
|
||||
uint16_t *ucsnumber;
|
||||
char fmt[16];
|
||||
char *nstr = alloca(digits + 1);
|
||||
|
||||
char nstr[72]; /* The only caller of this function allocates dest with 66
|
||||
elements and limits digits to < 8 */
|
||||
|
||||
sprintf(fmt, "%%0%dd", digits);
|
||||
sprintf(nstr, fmt, number);
|
||||
|
||||
|
||||
ret = str2ucs("ASCII", nstr, &ucsnumber);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* copy name */
|
||||
pos = ucslen(src);
|
||||
ucsncpy(dest, src, pos);
|
||||
|
||||
|
||||
/* copy number */
|
||||
ucsncpy(dest + pos, ucsnumber, digits);
|
||||
pos += digits;
|
||||
|
||||
|
||||
if (ext[0] != (uint16_t)0) {
|
||||
size_t extlen = ucslen(ext);
|
||||
dest[pos++] = (uint16_t)0x2E00; /* '.' in big endian UCS */
|
||||
@ -326,9 +339,9 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
|
||||
nchildren = dir->info.dir->nchildren;
|
||||
children = dir->info.dir->children;
|
||||
|
||||
|
||||
/* a hash table will temporary hold the names, for fast searching */
|
||||
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||
(compare_function_t)ucscmp, &table);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -349,7 +362,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
int digits = 1; /* characters to change per name */
|
||||
|
||||
/* first, find all child with same name */
|
||||
while (j + 1 < nchildren &&
|
||||
while (j + 1 < nchildren &&
|
||||
!cmp_node_name(children + i, children + j + 1)) {
|
||||
++j;
|
||||
}
|
||||
@ -359,9 +372,11 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
}
|
||||
|
||||
/*
|
||||
* A max of 7 characters is good enought, it allows handling up to
|
||||
* A max of 7 characters is good enought, it allows handling up to
|
||||
* 9,999,999 files with same name.
|
||||
*/
|
||||
/* Important: joliet_create_mangled_name() relies on digits < 72 */
|
||||
|
||||
while (digits < 8) {
|
||||
int ok, k;
|
||||
uint16_t *dot;
|
||||
@ -374,7 +389,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
dot = ucsrchr(full_name, '.');
|
||||
if (dot != NULL && children[i]->type != JOLIET_DIR) {
|
||||
|
||||
/*
|
||||
/*
|
||||
* File (not dir) with extension
|
||||
*/
|
||||
int extlen;
|
||||
@ -387,17 +402,17 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
if (max <= 0) {
|
||||
/* this can happen if extension is too long */
|
||||
if (extlen + max > 3) {
|
||||
/*
|
||||
/*
|
||||
* reduce extension len, to give name an extra char
|
||||
* note that max is negative or 0
|
||||
* note that max is negative or 0
|
||||
*/
|
||||
extlen = extlen + max - 1;
|
||||
ext[extlen] = 0;
|
||||
max = 66 - extlen - 1 - digits;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* error, we don't support extensions < 3
|
||||
* This can't happen with current limit of digits.
|
||||
* This can't happen with current limit of digits.
|
||||
*/
|
||||
ret = ISO_ERROR;
|
||||
goto mangle_cleanup;
|
||||
@ -455,7 +470,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
children[k]->name = new;
|
||||
iso_htable_add(table, new, new);
|
||||
|
||||
/*
|
||||
/*
|
||||
* if we change a name we need to sort again children
|
||||
* at the end
|
||||
*/
|
||||
@ -486,7 +501,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
|
||||
|
||||
mangle_cleanup : ;
|
||||
iso_htable_destroy(table, NULL);
|
||||
return ret;
|
||||
@ -521,7 +536,7 @@ int joliet_tree_create(Ecma119Image *t)
|
||||
{
|
||||
int ret;
|
||||
JolietNode *root;
|
||||
|
||||
|
||||
if (t == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
@ -534,7 +549,7 @@ int joliet_tree_create(Ecma119Image *t)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* the Joliet tree is stored in Ecma119Image target */
|
||||
t->joliet_root = root;
|
||||
|
||||
@ -580,20 +595,25 @@ size_t calc_dir_size(Ecma119Image *t, JolietNode *dir)
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||
size_t remaining;
|
||||
int section, nsections;
|
||||
JolietNode *child = dir->info.dir->children[i];
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
|
||||
nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The size of a dir is always a multiple of block size, as we must add
|
||||
* the size of the unused space after the last directory record
|
||||
* The size of a dir is always a multiple of block size, as we must add
|
||||
* the size of the unused space after the last directory record
|
||||
* (ECMA-119, 6.8.1.3)
|
||||
*/
|
||||
len = ROUND_UP(len, BLOCK_SIZE);
|
||||
@ -677,7 +697,7 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
/**
|
||||
* Write a single directory record for Joliet. It is like (ECMA-119, 9.1),
|
||||
* but file identifier is stored in UCS.
|
||||
*
|
||||
*
|
||||
* @param file_id
|
||||
* if >= 0, we use it instead of the filename (for "." and ".." entries).
|
||||
* @param len_fi
|
||||
@ -686,11 +706,12 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
*/
|
||||
static
|
||||
void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
|
||||
uint8_t *buf, size_t len_fi)
|
||||
uint8_t *buf, size_t len_fi, int extent)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr; /*< size of dir entry */
|
||||
int multi_extend = 0;
|
||||
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
|
||||
: (uint8_t*)node->name;
|
||||
|
||||
@ -713,12 +734,13 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
|
||||
len = node->info.dir->len;
|
||||
block = node->info.dir->block;
|
||||
} else if (node->type == JOLIET_FILE) {
|
||||
len = iso_file_src_get_size(node->info.file);
|
||||
block = node->info.file->block;
|
||||
block = node->info.file->sections[extent].block;
|
||||
len = node->info.file->sections[extent].size;
|
||||
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
|
||||
} else {
|
||||
/*
|
||||
* for nodes other than files and dirs, we set both
|
||||
* len and block to 0
|
||||
/*
|
||||
* for nodes other than files and dirs, we set both
|
||||
* len and block to 0
|
||||
*/
|
||||
len = 0;
|
||||
block = 0;
|
||||
@ -734,7 +756,7 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
|
||||
rec->flags[0] = (node->type == JOLIET_DIR) ? 2 : 0;
|
||||
rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
}
|
||||
@ -748,19 +770,19 @@ void ucsncpy_pad(uint16_t *dest, const uint16_t *src, size_t max)
|
||||
{
|
||||
char *cdest, *csrc;
|
||||
size_t len, i;
|
||||
|
||||
|
||||
cdest = (char*)dest;
|
||||
csrc = (char*)src;
|
||||
|
||||
|
||||
if (src != NULL) {
|
||||
len = MIN(ucslen(src) * 2, max);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
cdest[i] = csrc[i];
|
||||
|
||||
|
||||
for (i = len; i < max; i += 2) {
|
||||
cdest[i] = '\0';
|
||||
cdest[i + 1] = ' ';
|
||||
@ -805,7 +827,7 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
memcpy(vol.std_identifier, "CD001", 5);
|
||||
vol.vol_desc_version[0] = 1;
|
||||
ucsncpy_pad((uint16_t*)vol.volume_id, vol_id, 32);
|
||||
|
||||
|
||||
/* make use of UCS-2 Level 3 */
|
||||
memcpy(vol.esc_sequences, "%/E", 3);
|
||||
|
||||
@ -817,12 +839,12 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4);
|
||||
iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4);
|
||||
|
||||
write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1);
|
||||
write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0);
|
||||
|
||||
ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128);
|
||||
ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128);
|
||||
ucsncpy_pad((uint16_t*)vol.data_prep_id, data_id, 128);
|
||||
|
||||
|
||||
ucsncpy_pad((uint16_t*)vol.system_id, system_id, 32);
|
||||
|
||||
ucsncpy_pad((uint16_t*)vol.application_id, application_id, 128);
|
||||
@ -864,12 +886,13 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir)
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf, 1);
|
||||
write_one_dir_record(t, dir, 0, buf, 1, 0);
|
||||
buf += 34;
|
||||
write_one_dir_record(t, dir, 1, buf, 1);
|
||||
write_one_dir_record(t, dir, 1, buf, 1, 0);
|
||||
buf += 34;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
int section, nsections;
|
||||
JolietNode *child = dir->info.dir->children[i];
|
||||
|
||||
/* compute len of directory entry */
|
||||
@ -879,18 +902,23 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir)
|
||||
len += 4;
|
||||
}
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
|
||||
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, section);
|
||||
buf += len;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len);
|
||||
buf += len;
|
||||
}
|
||||
|
||||
/* write the last block */
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
/* libiso_msgs (generated from libdax_msgs : Qua Fev 13 14:58:12 CET 2008)
|
||||
/* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
|
||||
Message handling facility of libisofs.
|
||||
Copyright (C) 2006 - 2008 Thomas Schmitt <scdbackup@gmx.net>,
|
||||
provided under GPL version 2
|
||||
@ -268,10 +268,12 @@ int libiso_msgs__text_to_sev(char *severity_name, int *severity,
|
||||
*severity= LIBISO_MSGS_SEV_UPDATE;
|
||||
else if(strncmp(severity_name,"DEBUG",5)==0)
|
||||
*severity= LIBISO_MSGS_SEV_DEBUG;
|
||||
else if(strncmp(severity_name,"ERRFILE",7)==0)
|
||||
*severity= LIBISO_MSGS_SEV_ERRFILE;
|
||||
else if(strncmp(severity_name,"ALL",3)==0)
|
||||
*severity= LIBISO_MSGS_SEV_ALL;
|
||||
else {
|
||||
*severity= LIBISO_MSGS_SEV_NEVER;
|
||||
*severity= LIBISO_MSGS_SEV_ALL;
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
@ -282,7 +284,7 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
|
||||
int flag)
|
||||
{
|
||||
if(flag&1) {
|
||||
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
|
||||
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
|
||||
return(1);
|
||||
}
|
||||
*severity_name= "";
|
||||
@ -308,6 +310,8 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
|
||||
*severity_name= "UPDATE";
|
||||
else if(severity>=LIBISO_MSGS_SEV_DEBUG)
|
||||
*severity_name= "DEBUG";
|
||||
else if(severity>=LIBISO_MSGS_SEV_ERRFILE)
|
||||
*severity_name= "ERRFILE";
|
||||
else if(severity>=LIBISO_MSGS_SEV_ALL)
|
||||
*severity_name= "ALL";
|
||||
else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
/* libiso_msgs (generated from libdax_msgs : Qua Fev 13 14:58:12 CET 2008)
|
||||
/* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
|
||||
Message handling facility of libisofs.
|
||||
Copyright (C) 2006-2008 Thomas Schmitt <scdbackup@gmx.net>,
|
||||
provided under GPL version 2
|
||||
@ -120,6 +120,19 @@ struct libiso_msgs_item;
|
||||
*/
|
||||
#define LIBISO_MSGS_SEV_ALL 0x00000000
|
||||
|
||||
|
||||
/** Messages of this severity shall transport plain disk file paths
|
||||
whenever an event of severity SORRY or above is related with an
|
||||
individual disk file.
|
||||
No message text shall be added to the file path. The ERRFILE message
|
||||
shall be issued before the human readable message which carries the
|
||||
true event severity. That message should contain the file path so it
|
||||
can be found by strstr(message, path)!=NULL.
|
||||
The error code shall be the same as with the human readable message.
|
||||
*/
|
||||
#define LIBISO_MSGS_SEV_ERRFILE 0x08000000
|
||||
|
||||
|
||||
/** Debugging messages not to be visible to normal users by default
|
||||
*/
|
||||
#define LIBISO_MSGS_SEV_DEBUG 0x10000000
|
||||
@ -149,7 +162,7 @@ struct libiso_msgs_item;
|
||||
like ISO image generation. A precondition for such a severity ease is
|
||||
that the action can be continued after the incident.
|
||||
See below MISHAP for what xorriso would need instead of this kind of SORRY
|
||||
an generates for itself in case of libisofs image generation.
|
||||
and generates for itself in case of libisofs image generation.
|
||||
|
||||
E.g.: A pattern yields no result.
|
||||
A speed setting cannot be made.
|
||||
@ -610,6 +623,7 @@ Range "application" : 0x00040000 to 0x0004ffff
|
||||
0x00040005 (NOTE,HIGH) : Application supplied message
|
||||
0x00040006 (UPDATE,HIGH) : Application supplied message
|
||||
0x00040007 (DEBUG,HIGH) : Application supplied message
|
||||
0x00040008 (*,HIGH) : Application supplied message
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
3388
libisofs/libisofs.h
3388
libisofs/libisofs.h
File diff suppressed because it is too large
Load Diff
229
libisofs/make_isohybrid_mbr.c
Normal file
229
libisofs/make_isohybrid_mbr.c
Normal file
@ -0,0 +1,229 @@
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* for gettimeofday() */
|
||||
#include <sys/time.h>
|
||||
|
||||
/* This code stems from syslinux-3.72/utils/isohybrid, a perl script
|
||||
under GPL which is Copyright 2002-2008 H. Peter Anvin.
|
||||
|
||||
Line numbers in comments refer to the lines of that script.
|
||||
It has been analyzed and re-written in C language 2008 by Thomas Schmitt,
|
||||
and is now under the licenses to which H.Peter Anvin agreed:
|
||||
|
||||
http://syslinux.zytor.com/archives/2008-November/011105.html
|
||||
Date: Mon, 10 Nov 2008 08:36:46 -0800
|
||||
From: H. Peter Anvin <hpa@zytor.com>
|
||||
I hereby give permission for this code, translated to the C language, to
|
||||
be released under either the LGPL or the MIT/ISC/2-clause BSD licenses
|
||||
or both, at your option.
|
||||
Sincerely, H. Peter Anvin
|
||||
|
||||
In the context of libisofs this code derives its matching open source
|
||||
license from above stem licenses, typically from LGPL.
|
||||
In case its generosity is needed, here is the 2-clause BSD license:
|
||||
|
||||
make_isohybrid_mbr.c is copyright 2002-2008 H. Peter Anvin
|
||||
and 2008 libburnia project.
|
||||
|
||||
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.
|
||||
THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
THE PROVIDER 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.
|
||||
|
||||
*/
|
||||
|
||||
/* A helper function. One could replace it by one or two macros. */
|
||||
static int lsb_to_buf(char **wpt, int value, int bits, int flag)
|
||||
{
|
||||
int b;
|
||||
|
||||
for (b = 0; b < bits; b += 8)
|
||||
*((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
|
||||
*
|
||||
* It is assumed that the caller has verified the readiness of the boot image
|
||||
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
|
||||
*
|
||||
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
|
||||
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
|
||||
* It will get rounded up to full MBs and that many blocks
|
||||
* must really be written as ISO 9660 image.
|
||||
* @param mbr A buffer of at least 512 bytes to take the result which is
|
||||
* to be written as the very beginning of the ISO.
|
||||
* @param flag unused yet, submit 0
|
||||
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
|
||||
*/
|
||||
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag)
|
||||
{
|
||||
/* According to H. Peter Anvin this binary code stems from
|
||||
syslinux-3.72/mbr/isohdpfx.S
|
||||
*/
|
||||
static int mbr_code_size = 271;
|
||||
static unsigned char mbr_code[271] = { 0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e,
|
||||
0xd0, 0xbc, 0x00, 0x7c, 0x89, 0xe6, 0x06, 0x57, 0x52, 0x8e, 0xc0,
|
||||
0xfb, 0xfc, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xea,
|
||||
0x20, 0x06, 0x00, 0x00, 0x52, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0x31,
|
||||
0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, 0x14, 0x81, 0xfb, 0x55,
|
||||
0xaa, 0x75, 0x0e, 0x83, 0xe1, 0x01, 0x74, 0x09, 0x66, 0xc7, 0x06,
|
||||
0xb4, 0x06, 0xb4, 0x42, 0xeb, 0x15, 0x5a, 0x51, 0xb4, 0x08, 0xcd,
|
||||
0x13, 0x83, 0xe1, 0x3f, 0x51, 0x0f, 0xb6, 0xc6,
|
||||
|
||||
0x40, 0x50, 0xf7, 0xe1, 0x52, 0x50, 0xbb, 0x00, 0x7c, 0xb9, 0x04,
|
||||
0x00, 0x66, 0xa1, 0xb0, 0x07, 0xe8, 0x40, 0x00, 0x72, 0x74, 0x66,
|
||||
0x40, 0x80, 0xc7, 0x02, 0xe2, 0xf4, 0x66, 0x81, 0x3e, 0x40, 0x7c,
|
||||
0xfb, 0xc0, 0x78, 0x70, 0x75, 0x07, 0xfa, 0xbc, 0xf4, 0x7b, 0xe9,
|
||||
0xc6, 0x75, 0xe8, 0x79, 0x00, 0x69, 0x73, 0x6f, 0x6c, 0x69, 0x6e,
|
||||
0x75, 0x78, 0x2e, 0x62, 0x69, 0x6e, 0x20, 0x6d, 0x69, 0x73, 0x73,
|
||||
0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72,
|
||||
0x75, 0x70, 0x74,
|
||||
|
||||
0x2e, 0x0d, 0x0a, 0x66, 0x60, 0x66, 0x31, 0xd2, 0x66, 0x52, 0x66,
|
||||
0x50, 0x06, 0x53, 0x6a, 0x01, 0x6a, 0x10, 0x89, 0xe6, 0x66, 0xf7,
|
||||
0x36, 0xf0, 0x7b, 0xc0, 0xe4, 0x06, 0x88, 0xe1, 0x88, 0xc5, 0x92,
|
||||
0xf6, 0x36, 0xf6, 0x7b, 0x88, 0xc6, 0x08, 0xe1, 0x41, 0xb8, 0x01,
|
||||
0x02, 0x8a, 0x16, 0xfa, 0x7b, 0xcd, 0x13, 0x8d, 0x64, 0x10, 0x66,
|
||||
0x61, 0xc3, 0xe8, 0x1e, 0x00, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
|
||||
0x6c, 0x6f, 0x61,
|
||||
|
||||
0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x0d, 0x0a, 0x5e,
|
||||
0xac, 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, 0xcd, 0x10,
|
||||
0x3c, 0x0a, 0x75, 0xf1, 0xcd, 0x18, 0xf4, 0xeb, 0xfd };
|
||||
|
||||
static int h = 64, s = 32;
|
||||
|
||||
int i, warn_size = 0, id;
|
||||
char *wpt;
|
||||
off_t imgsize, cylsize, frac, padding, c, cc;
|
||||
|
||||
/* For generating a weak random number */
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
if (bin_lba < 0 || bin_lba >= (1 << 29))
|
||||
return (0); /* 1 TB limit of signed 32 bit addressing of 512 byte blocks */
|
||||
|
||||
/*
|
||||
84: Gets size of image in bytes.
|
||||
89:
|
||||
*/
|
||||
imgsize = ((off_t) *img_blocks) * (off_t) 2048;
|
||||
|
||||
/*
|
||||
90: Computes $padding, size of padded image and number $c of
|
||||
pseudo-cylinders ($h and $s are constants set in line 24).
|
||||
102: $cc is $c curbed to 1024.
|
||||
*/
|
||||
cylsize = h * s * 512;
|
||||
frac = imgsize % cylsize;
|
||||
padding = (frac > 0 ? cylsize - frac : 0);
|
||||
imgsize += padding;
|
||||
*img_blocks = imgsize / (off_t) 2048;
|
||||
c = imgsize / cylsize;
|
||||
if (c > 1024) {
|
||||
warn_size = 1;
|
||||
cc = 1024;
|
||||
} else
|
||||
cc = c;
|
||||
|
||||
/*
|
||||
107: Brings the hex-encoded bytes from the file __END__ into
|
||||
113: the MBR buffer. (This function holds them in mbr_code[].)
|
||||
*/
|
||||
for (i = 0; i < mbr_code_size; i++)
|
||||
mbr[i] = mbr_code[i];
|
||||
|
||||
/*
|
||||
118: Pads up to 432
|
||||
*/
|
||||
for (i = mbr_code_size; i < 432; i++)
|
||||
mbr[i] = 0;
|
||||
|
||||
/* From here on use write cursor wpt */
|
||||
wpt = mbr + 432;
|
||||
|
||||
/*
|
||||
120: Converts LBA of isolinux.bin to blocksize 512 and writes
|
||||
to buffer. Appends 4 zero bytes.
|
||||
*/
|
||||
lsb_to_buf(&wpt, bin_lba * 4, 32, 0);
|
||||
lsb_to_buf(&wpt, 0, 32, 0);
|
||||
|
||||
/*
|
||||
121: I do not understand where $id should eventually come
|
||||
from. An environment variable ?
|
||||
125: Whatever, i use some 32-bit random value with no crypto strength.
|
||||
*/
|
||||
gettimeofday(&tv, &tz);
|
||||
id = 0xffffffff & (tv.tv_sec ^ (tv.tv_usec * 2000));
|
||||
|
||||
/*
|
||||
126: Adds 4 id bytes and 2 zero bytes.
|
||||
*/
|
||||
lsb_to_buf(&wpt, id, 32, 0);
|
||||
lsb_to_buf(&wpt, 0, 16, 0);
|
||||
|
||||
/*
|
||||
129: Composes 16 byte record from the parameters determined
|
||||
147: so far. Appends it to buffer and add 48 zero bytes.
|
||||
*/
|
||||
/* There are 4 "partition slots". Only the first is non-zero here.
|
||||
In the perl script, the fields are set in variables and then
|
||||
written to buffer. I omit the variables.
|
||||
*/
|
||||
/* 0x80 */
|
||||
lsb_to_buf(&wpt, 0x80, 8, 0);
|
||||
/* bhead */
|
||||
lsb_to_buf(&wpt, 0, 8, 0);
|
||||
/* bsect */
|
||||
lsb_to_buf(&wpt, 1, 8, 0);
|
||||
/* bcyl */
|
||||
lsb_to_buf(&wpt, 0, 8, 0);
|
||||
/* fstype */
|
||||
lsb_to_buf(&wpt, 0x83, 8, 0);
|
||||
/* ehead */
|
||||
lsb_to_buf(&wpt, h - 1, 8, 0);
|
||||
/* esect */
|
||||
lsb_to_buf(&wpt, s + (((cc - 1) & 0x300) >> 2), 8, 0);
|
||||
/* ecyl */
|
||||
lsb_to_buf(&wpt, (cc - 1) & 0xff, 8, 0);
|
||||
/* 0 */
|
||||
lsb_to_buf(&wpt, 0, 32, 0);
|
||||
/* psize */
|
||||
lsb_to_buf(&wpt, c * h * s, 32, 0);
|
||||
|
||||
/* Fill the other three slots with zeros */
|
||||
for (i = 0; i < 3 * 4; i++)
|
||||
lsb_to_buf(&wpt, 0, 32, 0);
|
||||
|
||||
/*
|
||||
148: Appends bytes 0x55 , 0xAA.
|
||||
*/
|
||||
lsb_to_buf(&wpt, 0x55, 8, 0);
|
||||
lsb_to_buf(&wpt, 0xaa, 8, 0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
@ -14,9 +15,12 @@
|
||||
#include "libisofs.h"
|
||||
#include "messages.h"
|
||||
|
||||
/*
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/*
|
||||
* error codes are 32 bit numbers, that follow the following conventions:
|
||||
*
|
||||
*
|
||||
* bit 31 (MSB) -> 1 (to make the value always negative)
|
||||
* bits 30-24 -> Encoded severity (Use ISO_ERR_SEV to translate an error code
|
||||
* to a LIBISO_MSGS_SEV_* constant)
|
||||
@ -40,7 +44,7 @@
|
||||
* bits 15-0 -> Error code
|
||||
*/
|
||||
#define ISO_ERR_SEV(e) (e & 0x7F000000)
|
||||
#define ISO_ERR_PRIO(e) ((e & 0x00F00000) << 8)
|
||||
#define ISO_ERR_PRIO(e) ((e & 0x00700000) << 8)
|
||||
#define ISO_ERR_CODE(e) ((e & 0x0000FFFF) | 0x00030000)
|
||||
|
||||
int iso_message_id = LIBISO_MSGS_ORIGIN_IMAGE_BASE;
|
||||
@ -54,8 +58,16 @@ int abort_threshold = LIBISO_MSGS_SEV_FAILURE;
|
||||
|
||||
struct libiso_msgs *libiso_msgr = NULL;
|
||||
|
||||
int iso_init()
|
||||
|
||||
/*
|
||||
@param flag bit0= do not set up locale by LC_* environment variables
|
||||
*/
|
||||
int iso_init_with_flag(int flag)
|
||||
{
|
||||
|
||||
if (! (flag & 1)) {
|
||||
iso_init_locale(0);
|
||||
}
|
||||
if (libiso_msgr == NULL) {
|
||||
if (libiso_msgs_new(&libiso_msgr, 0) <= 0)
|
||||
return ISO_FATAL_ERROR;
|
||||
@ -65,6 +77,12 @@ int iso_init()
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int iso_init()
|
||||
{
|
||||
return iso_init_with_flag(0);
|
||||
}
|
||||
|
||||
void iso_finish()
|
||||
{
|
||||
libiso_msgs_destroy(&libiso_msgr, 0);
|
||||
@ -77,7 +95,7 @@ int iso_set_abort_severity(char *severity)
|
||||
ret = libiso_msgs__text_to_sev(severity, &sevno, 0);
|
||||
if (ret <= 0)
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
if (sevno > LIBISO_MSGS_SEV_FAILURE || sevno < LIBISO_MSGS_SEV_NOTE)
|
||||
if (sevno > LIBISO_MSGS_SEV_FAILURE || sevno < LIBISO_MSGS_SEV_NOTE)
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
ret = abort_threshold;
|
||||
abort_threshold = sevno;
|
||||
@ -100,110 +118,148 @@ void iso_msg_debug(int imgid, const char *fmt, ...)
|
||||
const char *iso_error_to_msg(int errcode)
|
||||
{
|
||||
switch(errcode) {
|
||||
case ISO_CANCELED:
|
||||
case ISO_CANCELED:
|
||||
return "Operation canceled";
|
||||
case ISO_FATAL_ERROR:
|
||||
case ISO_FATAL_ERROR:
|
||||
return "Unknown or unexpected fatal error";
|
||||
case ISO_ERROR:
|
||||
case ISO_ERROR:
|
||||
return "Unknown or unexpected error";
|
||||
case ISO_ASSERT_FAILURE:
|
||||
case ISO_ASSERT_FAILURE:
|
||||
return "Internal programming error. Please report this bug";
|
||||
case ISO_NULL_POINTER:
|
||||
return "NULL pointer as value for an arg. that doesn't allow NULL";
|
||||
case ISO_OUT_OF_MEM:
|
||||
case ISO_NULL_POINTER:
|
||||
return "NULL pointer as value for an arg. that does not allow NULL";
|
||||
case ISO_OUT_OF_MEM:
|
||||
return "Memory allocation error";
|
||||
case ISO_INTERRUPTED:
|
||||
case ISO_INTERRUPTED:
|
||||
return "Interrupted by a signal";
|
||||
case ISO_WRONG_ARG_VALUE:
|
||||
case ISO_WRONG_ARG_VALUE:
|
||||
return "Invalid parameter value";
|
||||
case ISO_THREAD_ERROR:
|
||||
return "Can't create a needed thread";
|
||||
case ISO_WRITE_ERROR:
|
||||
case ISO_THREAD_ERROR:
|
||||
return "Cannot create a needed thread";
|
||||
case ISO_WRITE_ERROR:
|
||||
return "Write error";
|
||||
case ISO_BUF_READ_ERROR:
|
||||
case ISO_BUF_READ_ERROR:
|
||||
return "Buffer read error";
|
||||
case ISO_NODE_ALREADY_ADDED:
|
||||
case ISO_NODE_ALREADY_ADDED:
|
||||
return "Trying to add to a dir a node already added to a dir";
|
||||
case ISO_NODE_NAME_NOT_UNIQUE:
|
||||
case ISO_NODE_NAME_NOT_UNIQUE:
|
||||
return "Node with same name already exists";
|
||||
case ISO_NODE_NOT_ADDED_TO_DIR:
|
||||
case ISO_NODE_NOT_ADDED_TO_DIR:
|
||||
return "Trying to remove a node that was not added to dir";
|
||||
case ISO_NODE_DOESNT_EXIST:
|
||||
case ISO_NODE_DOESNT_EXIST:
|
||||
return "A requested node does not exist";
|
||||
case ISO_IMAGE_ALREADY_BOOTABLE:
|
||||
case ISO_IMAGE_ALREADY_BOOTABLE:
|
||||
return "Try to set the boot image of an already bootable image";
|
||||
case ISO_BOOT_IMAGE_NOT_VALID:
|
||||
case ISO_BOOT_IMAGE_NOT_VALID:
|
||||
return "Trying to use an invalid file as boot image";
|
||||
case ISO_FILE_ERROR:
|
||||
case ISO_FILE_ERROR:
|
||||
return "Error on file operation";
|
||||
case ISO_FILE_ALREADY_OPENNED:
|
||||
return "Trying to open an already openned file";
|
||||
case ISO_FILE_ACCESS_DENIED:
|
||||
case ISO_FILE_ALREADY_OPENED:
|
||||
return "Trying to open an already opened file";
|
||||
case ISO_FILE_ACCESS_DENIED:
|
||||
return "Access to file is not allowed";
|
||||
case ISO_FILE_BAD_PATH:
|
||||
case ISO_FILE_BAD_PATH:
|
||||
return "Incorrect path to file";
|
||||
case ISO_FILE_DOESNT_EXIST:
|
||||
case ISO_FILE_DOESNT_EXIST:
|
||||
return "The file does not exist in the filesystem";
|
||||
case ISO_FILE_NOT_OPENNED:
|
||||
return "Trying to read or close a file not openned";
|
||||
case ISO_FILE_IS_DIR:
|
||||
case ISO_FILE_NOT_OPENED:
|
||||
return "Trying to read or close a file not opened";
|
||||
case ISO_FILE_IS_DIR:
|
||||
return "Directory used where no dir is expected";
|
||||
case ISO_FILE_READ_ERROR:
|
||||
case ISO_FILE_READ_ERROR:
|
||||
return "Read error";
|
||||
case ISO_FILE_IS_NOT_DIR:
|
||||
case ISO_FILE_IS_NOT_DIR:
|
||||
return "Not dir used where a dir is expected";
|
||||
case ISO_FILE_IS_NOT_SYMLINK:
|
||||
case ISO_FILE_IS_NOT_SYMLINK:
|
||||
return "Not symlink used where a symlink is expected";
|
||||
case ISO_FILE_SEEK_ERROR:
|
||||
return "Can't seek to specified location";
|
||||
case ISO_FILE_IGNORED:
|
||||
case ISO_FILE_SEEK_ERROR:
|
||||
return "Cannot seek to specified location";
|
||||
case ISO_FILE_IGNORED:
|
||||
return "File not supported in ECMA-119 tree and thus ignored";
|
||||
case ISO_FILE_TOO_BIG:
|
||||
case ISO_FILE_TOO_BIG:
|
||||
return "A file is bigger than supported by used standard";
|
||||
case ISO_FILE_CANT_WRITE:
|
||||
case ISO_FILE_CANT_WRITE:
|
||||
return "File read error during image creation";
|
||||
case ISO_FILENAME_WRONG_CHARSET:
|
||||
return "Can't convert filename to requested charset";
|
||||
case ISO_FILE_CANT_ADD:
|
||||
return "File can't be added to the tree";
|
||||
case ISO_FILE_IMGPATH_WRONG:
|
||||
case ISO_FILENAME_WRONG_CHARSET:
|
||||
case ISO_FILENAME_WRONG_CHARSET_OLD:
|
||||
return "Cannot convert filename to requested charset";
|
||||
case ISO_FILE_CANT_ADD:
|
||||
return "File cannot be added to the tree";
|
||||
case ISO_FILE_IMGPATH_WRONG:
|
||||
return "File path break specification constraints and will be ignored";
|
||||
case ISO_CHARSET_CONV_ERROR:
|
||||
case ISO_CHARSET_CONV_ERROR:
|
||||
return "Charset conversion error";
|
||||
case ISO_MANGLE_TOO_MUCH_FILES:
|
||||
return "Too much files to mangle, can't guarantee unique file names";
|
||||
case ISO_WRONG_PVD:
|
||||
case ISO_MANGLE_TOO_MUCH_FILES:
|
||||
return "Too much files to mangle, cannot guarantee unique file names";
|
||||
case ISO_WRONG_PVD:
|
||||
return "Wrong or damaged Primary Volume Descriptor";
|
||||
case ISO_WRONG_RR:
|
||||
case ISO_WRONG_RR:
|
||||
return "Wrong or damaged RR entry";
|
||||
case ISO_UNSUPPORTED_RR:
|
||||
case ISO_UNSUPPORTED_RR:
|
||||
return "Unsupported RR feature";
|
||||
case ISO_WRONG_ECMA119:
|
||||
case ISO_WRONG_ECMA119:
|
||||
return "Wrong or damaged ECMA-119";
|
||||
case ISO_UNSUPPORTED_ECMA119:
|
||||
case ISO_UNSUPPORTED_ECMA119:
|
||||
return "Unsupported ECMA-119 feature";
|
||||
case ISO_WRONG_EL_TORITO:
|
||||
case ISO_WRONG_EL_TORITO:
|
||||
return "Wrong or damaged El-Torito catalog";
|
||||
case ISO_UNSUPPORTED_EL_TORITO:
|
||||
case ISO_UNSUPPORTED_EL_TORITO:
|
||||
return "Unsupported El-Torito feature";
|
||||
case ISO_ISOLINUX_CANT_PATCH:
|
||||
return "Can't patch isolinux boot image";
|
||||
case ISO_UNSUPPORTED_SUSP:
|
||||
case ISO_ISOLINUX_CANT_PATCH:
|
||||
return "Cannot patch isolinux boot image";
|
||||
case ISO_UNSUPPORTED_SUSP:
|
||||
return "Unsupported SUSP feature";
|
||||
case ISO_WRONG_RR_WARN:
|
||||
case ISO_WRONG_RR_WARN:
|
||||
return "Error on a RR entry that can be ignored";
|
||||
case ISO_SUSP_UNHANDLED:
|
||||
case ISO_SUSP_UNHANDLED:
|
||||
return "Error on a RR entry that can be ignored";
|
||||
case ISO_SUSP_MULTIPLE_ER:
|
||||
case ISO_SUSP_MULTIPLE_ER:
|
||||
return "Multiple ER SUSP entries found";
|
||||
case ISO_UNSUPPORTED_VD:
|
||||
case ISO_UNSUPPORTED_VD:
|
||||
return "Unsupported volume descriptor found";
|
||||
case ISO_EL_TORITO_WARN:
|
||||
case ISO_EL_TORITO_WARN:
|
||||
return "El-Torito related warning";
|
||||
case ISO_IMAGE_WRITE_CANCELED:
|
||||
case ISO_IMAGE_WRITE_CANCELED:
|
||||
return "Image write cancelled";
|
||||
case ISO_EL_TORITO_HIDDEN:
|
||||
case ISO_EL_TORITO_HIDDEN:
|
||||
return "El-Torito image is hidden";
|
||||
case ISO_DATA_SOURCE_SORRY:
|
||||
case ISO_DATA_SOURCE_MISHAP:
|
||||
case ISO_DATA_SOURCE_FAILURE:
|
||||
case ISO_DATA_SOURCE_FATAL:
|
||||
return "Read error occured with IsoDataSource";
|
||||
case ISO_AAIP_IGNORED:
|
||||
return "AAIP info with ACL or xattr in ISO image will be ignored";
|
||||
case ISO_AAIP_BAD_ACL:
|
||||
return "Error with decoding ACL from AAIP info";
|
||||
case ISO_AAIP_BAD_ACL_TEXT:
|
||||
return "Error with encoding ACL for AAIP";
|
||||
case ISO_AAIP_NOT_ENABLED:
|
||||
return "AAIP processing for ACL or xattr not enabled at compile time";
|
||||
case ISO_AAIP_BAD_AASTRING:
|
||||
return "Error with decoding AAIP info for ACL or xattr";
|
||||
case ISO_AAIP_NO_GET_LOCAL:
|
||||
return "Error with reading ACL or xattr from local file";
|
||||
case ISO_AAIP_NO_SET_LOCAL:
|
||||
return "Error with attaching ACL or xattr to local file";
|
||||
case ISO_AAIP_NON_USER_NAME:
|
||||
return "Unallowed attempt to set an xattr with non-userspace name";
|
||||
case ISO_EXTF_TOO_OFTEN:
|
||||
return "Too many references on a single external filter command";
|
||||
case ISO_ZLIB_NOT_ENABLED:
|
||||
return "Use of zlib was not enabled at compile time";
|
||||
case ISO_ZISOFS_TOO_LARGE:
|
||||
return "Cannot apply zisofs filter to file >= 4 GiB";
|
||||
case ISO_FILTER_WRONG_INPUT:
|
||||
return "Filter input differs from previous run";
|
||||
case ISO_ZLIB_COMPR_ERR:
|
||||
return "zlib compression/decompression error";
|
||||
case ISO_ZISOFS_WRONG_INPUT:
|
||||
return "Input stream is not in zisofs format";
|
||||
case ISO_ZISOFS_PARAM_LOCK:
|
||||
return "Cannot set global zisofs parameters while filters exist";
|
||||
case ISO_ZLIB_EARLY_EOF:
|
||||
return "Premature EOF of zlib input stream";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
@ -213,7 +269,7 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
|
||||
{
|
||||
char msg[MAX_MSG_LEN];
|
||||
va_list ap;
|
||||
|
||||
|
||||
/* when called with ISO_CANCELED, we don't need to submit any message */
|
||||
if (errcode == ISO_CANCELED && fmt == NULL) {
|
||||
return ISO_CANCELED;
|
||||
@ -227,12 +283,12 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
|
||||
strncpy(msg, iso_error_to_msg(errcode), MAX_MSG_LEN);
|
||||
}
|
||||
|
||||
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(errcode),
|
||||
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(errcode),
|
||||
ISO_ERR_SEV(errcode), ISO_ERR_PRIO(errcode), msg, 0, 0);
|
||||
if (causedby != 0) {
|
||||
snprintf(msg, MAX_MSG_LEN, " > Caused by: %s",
|
||||
snprintf(msg, MAX_MSG_LEN, " > Caused by: %s",
|
||||
iso_error_to_msg(causedby));
|
||||
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(causedby),
|
||||
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(causedby),
|
||||
LIBISO_MSGS_SEV_NOTE, LIBISO_MSGS_PRIO_LOW, msg, 0, 0);
|
||||
if (ISO_ERR_SEV(causedby) == LIBISO_MSGS_SEV_FATAL) {
|
||||
return ISO_CANCELED;
|
||||
@ -246,11 +302,11 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Control queueing and stderr printing of messages from libisofs.
|
||||
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
* "NOTE", "UPDATE", "DEBUG", "ALL".
|
||||
*
|
||||
*
|
||||
* @param queue_severity Gives the minimum limit for messages to be queued.
|
||||
* Default: "NEVER". If you queue messages then you
|
||||
* must consume them by iso_msgs_obtain().
|
||||
@ -259,7 +315,7 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
|
||||
* @param print_id A text prefix to be printed before the message.
|
||||
* @return >0 for success, <=0 for error
|
||||
*/
|
||||
int iso_set_msgs_severities(char *queue_severity, char *print_severity,
|
||||
int iso_set_msgs_severities(char *queue_severity, char *print_severity,
|
||||
char *print_id)
|
||||
{
|
||||
int ret, queue_sevno, print_sevno;
|
||||
@ -277,15 +333,15 @@ int iso_set_msgs_severities(char *queue_severity, char *print_severity,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Obtain the oldest pending libisofs message from the queue which has at
|
||||
* least the given minimum_severity. This message and any older message of
|
||||
* lower severity will get discarded from the queue and is then lost forever.
|
||||
*
|
||||
*
|
||||
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
* "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
|
||||
* will discard the whole queue.
|
||||
*
|
||||
*
|
||||
* @param error_code Will become a unique error code as listed in messages.h
|
||||
* @param imgid Id of the image that was issued the message.
|
||||
* @param msg_text Must provide at least ISO_MSGS_MESSAGE_LEN bytes.
|
||||
@ -305,7 +361,7 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
|
||||
ret = libiso_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
ret = libiso_msgs_obtain(libiso_msgr, &item, minimum_sevno,
|
||||
ret = libiso_msgs_obtain(libiso_msgr, &item, minimum_sevno,
|
||||
LIBISO_MSGS_PRIO_ZERO, 0);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
@ -319,7 +375,7 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
|
||||
ret = libiso_msgs_item_get_origin(item, ×tamp, &pid, imgid, 0);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
|
||||
|
||||
severity[0]= 0;
|
||||
ret = libiso_msgs_item_get_rank(item, &sevno, &priority, 0);
|
||||
if (ret <= 0)
|
||||
@ -335,12 +391,66 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A80222 : derived from libburn/init.c:burn_msgs_submit()
|
||||
*/
|
||||
int iso_msgs_submit(int error_code, char msg_text[], int os_errno,
|
||||
char severity[], int origin)
|
||||
{
|
||||
int ret, sevno;
|
||||
|
||||
ret = libiso_msgs__text_to_sev(severity, &sevno, 0);
|
||||
if (ret <= 0)
|
||||
sevno = LIBISO_MSGS_SEV_ALL;
|
||||
if (error_code <= 0) {
|
||||
switch(sevno) {
|
||||
case LIBISO_MSGS_SEV_ABORT: error_code = 0x00040000;
|
||||
break; case LIBISO_MSGS_SEV_FATAL: error_code = 0x00040001;
|
||||
break; case LIBISO_MSGS_SEV_SORRY: error_code = 0x00040002;
|
||||
break; case LIBISO_MSGS_SEV_WARNING: error_code = 0x00040003;
|
||||
break; case LIBISO_MSGS_SEV_HINT: error_code = 0x00040004;
|
||||
break; case LIBISO_MSGS_SEV_NOTE: error_code = 0x00040005;
|
||||
break; case LIBISO_MSGS_SEV_UPDATE: error_code = 0x00040006;
|
||||
break; case LIBISO_MSGS_SEV_DEBUG: error_code = 0x00040007;
|
||||
break; default: error_code = 0x00040008;
|
||||
}
|
||||
}
|
||||
ret = libiso_msgs_submit(libiso_msgr, origin, error_code,
|
||||
sevno, LIBISO_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A80222 : derived from libburn/init.c:burn_text_to_sev()
|
||||
*/
|
||||
int iso_text_to_sev(char *severity_name, int *sevno)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libiso_msgs__text_to_sev(severity_name, sevno, 0);
|
||||
if (ret <= 0)
|
||||
*sevno = LIBISO_MSGS_SEV_FATAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A80222 : derived from libburn/init.c:burn_sev_to_text()
|
||||
*/
|
||||
int iso_sev_to_text(int severity_number, char **severity_name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libiso_msgs__sev_to_text(severity_number, severity_name, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the messenger object handle used by libisofs. This handle
|
||||
* may be used by related libraries to their own compatible
|
||||
* messenger objects and thus to direct their messages to the libisofs
|
||||
* message queue. See also: libburn, API function burn_set_messenger().
|
||||
*
|
||||
*
|
||||
* @return the handle. Do only use with compatible
|
||||
*/
|
||||
void *iso_get_messenger()
|
||||
@ -362,3 +472,13 @@ int iso_error_get_code(int e)
|
||||
{
|
||||
return ISO_ERR_CODE(e);
|
||||
}
|
||||
|
||||
|
||||
/* ts A80222 */
|
||||
int iso_report_errfile(char *path, int error_code, int os_errno, int flag)
|
||||
{
|
||||
libiso_msgs_submit(libiso_msgr, 0, error_code,
|
||||
LIBISO_MSGS_SEV_ERRFILE, LIBISO_MSGS_PRIO_HIGH,
|
||||
path, os_errno, 0);
|
||||
return(1);
|
||||
}
|
||||
|
@ -37,4 +37,13 @@ void iso_msg_debug(int imgid, const char *fmt, ...);
|
||||
*/
|
||||
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...);
|
||||
|
||||
|
||||
/* ts A80222 */
|
||||
/* To be called with events which report incidents with individual input
|
||||
files from the local filesystem. Not with image nodes, files containing an
|
||||
image or similar file-like objects.
|
||||
*/
|
||||
int iso_report_errfile(char *path, int error_code, int os_errno, int flag);
|
||||
|
||||
|
||||
#endif /*MESSAGES_H_*/
|
||||
|
1957
libisofs/node.c
1957
libisofs/node.c
File diff suppressed because it is too large
Load Diff
270
libisofs/node.h
270
libisofs/node.h
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_NODE_H_
|
||||
@ -20,17 +21,14 @@
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* #define LIBISO_EXTENDED_INFORMATION */
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
|
||||
/**
|
||||
* The extended information is a way to attach additional information to each
|
||||
* IsoNode. External applications may want to use this extension system to
|
||||
* IsoNode. External applications may want to use this extension system to
|
||||
* store application speficic information related to each node. On the other
|
||||
* side, libisofs may make use of this struct to attach information to nodes in
|
||||
* some particular, uncommon, cases, without incrementing the size of the
|
||||
* IsoNode struct.
|
||||
*
|
||||
*
|
||||
* It is implemented like a chained list.
|
||||
*/
|
||||
typedef struct iso_extended_info IsoExtendedInfo;
|
||||
@ -40,41 +38,39 @@ struct iso_extended_info {
|
||||
* Next struct in the chain. NULL if it is the last item
|
||||
*/
|
||||
IsoExtendedInfo *next;
|
||||
|
||||
|
||||
/**
|
||||
* Function to handle this particular extended information. The function
|
||||
* pointer acts as an identifier for the type of the information. Structs
|
||||
* with same information type must use the same function.
|
||||
*
|
||||
*
|
||||
* @param data
|
||||
* Attached data
|
||||
* @param flag
|
||||
* What to do with the data. At this time the following values are
|
||||
* What to do with the data. At this time the following values are
|
||||
* defined:
|
||||
* -> 1 the data must be freed
|
||||
* @return
|
||||
* 1
|
||||
*/
|
||||
int (*process)(void *data, int flag);
|
||||
|
||||
iso_node_xinfo_func process;
|
||||
|
||||
/**
|
||||
* Pointer to information specific data.
|
||||
*/
|
||||
void *data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct Iso_Node
|
||||
{
|
||||
/*
|
||||
* Initilized to 1, originally owned by user, until added to another node.
|
||||
* Then it is owned by the parent node, so the user must take his own ref
|
||||
* Then it is owned by the parent node, so the user must take his own ref
|
||||
* if needed. With the exception of the creation functions, none of the
|
||||
* other libisofs functions that return an IsoNode increment its
|
||||
* other libisofs functions that return an IsoNode increment its
|
||||
* refcount. This is responsablity of the client, if (s)he needs it.
|
||||
*/
|
||||
int refcount;
|
||||
@ -102,12 +98,10 @@ struct Iso_Node
|
||||
*/
|
||||
IsoNode *next;
|
||||
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
/**
|
||||
* Extended information for the node.
|
||||
*/
|
||||
IsoExtendedInfo *xinfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Iso_Dir
|
||||
@ -122,17 +116,14 @@ struct Iso_File
|
||||
{
|
||||
IsoNode node;
|
||||
|
||||
/**
|
||||
* Location of a file extent in a ms disc, 0 for newly added file
|
||||
*/
|
||||
uint32_t msblock;
|
||||
unsigned int from_old_session : 1;
|
||||
|
||||
/**
|
||||
/**
|
||||
* It sorts the order in which the file data is written to the CD image.
|
||||
* Higher weighting files are written at the beginning of image
|
||||
* Higher weighting files are written at the beginning of image
|
||||
*/
|
||||
int sort_weight;
|
||||
IsoStream *stream;
|
||||
IsoStream *stream; /* Knows fs_id, st_dev, and st_ino */
|
||||
};
|
||||
|
||||
struct Iso_Symlink
|
||||
@ -140,12 +131,54 @@ struct Iso_Symlink
|
||||
IsoNode node;
|
||||
|
||||
char *dest;
|
||||
|
||||
#ifdef Libisofs_hardlink_matcheR
|
||||
/* If the IsoNode represents an object in an existing filesystem then
|
||||
the following three numbers should unique identify it.
|
||||
(0,0,0) will always be taken as unique.
|
||||
*/
|
||||
unsigned int fs_id;
|
||||
dev_t st_dev;
|
||||
ino_t st_ino;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct Iso_Special
|
||||
{
|
||||
IsoNode node;
|
||||
dev_t dev;
|
||||
|
||||
#ifdef Libisofs_hardlink_matcheR
|
||||
/* If the IsoNode represents an object in an existing filesystem then
|
||||
the following three numbers should unique identify it.
|
||||
(0,0,0) will always be taken as unique.
|
||||
*/
|
||||
unsigned int fs_id;
|
||||
dev_t st_dev;
|
||||
ino_t st_ino;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct iso_dir_iter_iface
|
||||
{
|
||||
|
||||
int (*next)(IsoDirIter *iter, IsoNode **node);
|
||||
|
||||
int (*has_next)(IsoDirIter *iter);
|
||||
|
||||
void (*free)(IsoDirIter *iter);
|
||||
|
||||
int (*take)(IsoDirIter *iter);
|
||||
|
||||
int (*remove)(IsoDirIter *iter);
|
||||
|
||||
/**
|
||||
* This is called just before remove a node from a directory. The iterator
|
||||
* may want to update its internal state according to this.
|
||||
*/
|
||||
void (*notify_child_taken)(IsoDirIter *iter, IsoNode *node);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -153,34 +186,38 @@ struct Iso_Special
|
||||
*/
|
||||
struct Iso_Dir_Iter
|
||||
{
|
||||
const IsoDir *dir;
|
||||
IsoNode *pos;
|
||||
struct iso_dir_iter_iface *class;
|
||||
|
||||
/* the directory this iterator iterates over */
|
||||
IsoDir *dir;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
int iso_node_new_root(IsoDir **root);
|
||||
|
||||
/**
|
||||
* Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to
|
||||
* Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to
|
||||
* default (0) values. You must set them.
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* Name for the node. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* Name for the node. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* allowed.
|
||||
* @param dir
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 on success, < 0 on error.
|
||||
*/
|
||||
int iso_node_new_dir(char *name, IsoDir **dir);
|
||||
|
||||
/**
|
||||
* Create a new file node. Attributes, uid/gid, timestamps, etc are set to
|
||||
* Create a new file node. Attributes, uid/gid, timestamps, etc are set to
|
||||
* default (0) values. You must set them.
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* Name for the node. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* Name for the node. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* allowed.
|
||||
* @param stream
|
||||
* Source for file contents. The reference is taken by the node,
|
||||
@ -193,14 +230,14 @@ int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file);
|
||||
/**
|
||||
* Creates a new IsoSymlink node. Attributes, uid/gid, timestamps, etc are set
|
||||
* to default (0) values. You must set them.
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* name for the new symlink. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* name for the new symlink. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* allowed.
|
||||
* @param dest
|
||||
* destination of the link. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* destination of the link. It is not strdup() so you shouldn't use this
|
||||
* reference when this function returns successfully. NULL is not
|
||||
* allowed.
|
||||
* @param link
|
||||
* place where to store a pointer to the newly created link.
|
||||
@ -214,22 +251,22 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link);
|
||||
* an special file is a block device, a character device, a FIFO (named pipe)
|
||||
* or a socket. You can choose the specific kind of file you want to add
|
||||
* by setting mode propertly (see man 2 stat).
|
||||
*
|
||||
* Note that special files are only written to image when Rock Ridge
|
||||
*
|
||||
* Note that special files are only written to image when Rock Ridge
|
||||
* extensions are enabled. Moreover, a special file is just a directory entry
|
||||
* in the image tree, no data is written beyond that.
|
||||
*
|
||||
* Owner and hidden atts are taken from parent. You can modify any of them
|
||||
*
|
||||
* Owner and hidden atts are taken from parent. You can modify any of them
|
||||
* later.
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* name for the new special file. It is not strdup() so you shouldn't use
|
||||
* this reference when this function returns successfully. NULL is not
|
||||
* name for the new special file. It is not strdup() so you shouldn't use
|
||||
* this reference when this function returns successfully. NULL is not
|
||||
* allowed.
|
||||
* @param mode
|
||||
* file type and permissions for the new node. Note that you can't
|
||||
* specify any kind of file here, only special types are allowed. i.e,
|
||||
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
|
||||
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
|
||||
* S_IFREG and S_IFDIR aren't.
|
||||
* @param dev
|
||||
* device ID, equivalent to the st_rdev field in man 2 stat.
|
||||
@ -238,12 +275,12 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link);
|
||||
* @return
|
||||
* 1 on success, < 0 otherwise
|
||||
*/
|
||||
int iso_node_new_special(char *name, mode_t mode, dev_t dev,
|
||||
int iso_node_new_special(char *name, mode_t mode, dev_t dev,
|
||||
IsoSpecial **special);
|
||||
|
||||
/**
|
||||
* Check if a given name is valid for an iso node.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 if yes, 0 if not
|
||||
*/
|
||||
@ -251,7 +288,7 @@ int iso_node_is_valid_name(const char *name);
|
||||
|
||||
/**
|
||||
* Check if a given path is valid for the destination of a link.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 if yes, 0 if not
|
||||
*/
|
||||
@ -259,7 +296,7 @@ int iso_node_is_valid_link_dest(const char *dest);
|
||||
|
||||
/**
|
||||
* Find the position where to insert a node
|
||||
*
|
||||
*
|
||||
* @param dir
|
||||
* A valid dir. It can't be NULL
|
||||
* @param name
|
||||
@ -271,7 +308,7 @@ void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos);
|
||||
|
||||
/**
|
||||
* Check if a node with the given name exists in a dir.
|
||||
*
|
||||
*
|
||||
* @param dir
|
||||
* A valid dir. It can't be NULL
|
||||
* @param name
|
||||
@ -286,21 +323,132 @@ int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos);
|
||||
|
||||
/**
|
||||
* Inserts a given node in a dir, at the specified position.
|
||||
*
|
||||
*
|
||||
* @param dir
|
||||
* Dir where to insert. It can't be NULL
|
||||
* @param node
|
||||
* The node to insert. It can't be NULL
|
||||
* @param pos
|
||||
* Position where the node will be inserted. It is a pointer previously
|
||||
* obtained with a call to iso_dir_exists() or iso_dir_find().
|
||||
* obtained with a call to iso_dir_exists() or iso_dir_find().
|
||||
* It can't be NULL.
|
||||
* @param replace
|
||||
* @param replace
|
||||
* Whether to replace an old node with the same name with the new node.
|
||||
* @return
|
||||
* If success, number of children in dir. < 0 on error
|
||||
* If success, number of children in dir. < 0 on error
|
||||
*/
|
||||
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
|
||||
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
|
||||
enum iso_replace_mode replace);
|
||||
|
||||
/**
|
||||
* Add a new iterator to the registry. The iterator register keeps track of
|
||||
* all iterators being used, and are notified when directory structure
|
||||
* changes.
|
||||
*/
|
||||
int iso_dir_iter_register(IsoDirIter *iter);
|
||||
|
||||
/**
|
||||
* Unregister a directory iterator.
|
||||
*/
|
||||
void iso_dir_iter_unregister(IsoDirIter *iter);
|
||||
|
||||
void iso_notify_dir_iters(IsoNode *node, int flag);
|
||||
|
||||
|
||||
/**
|
||||
* See API function iso_node_set_permissions()
|
||||
*
|
||||
* @param flag bit0= do not adjust ACL
|
||||
* @return >0 success , <0 error
|
||||
*/
|
||||
int iso_node_set_perms_internal(IsoNode *node, mode_t mode, int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Like iso_node_get_acl_text() with param node replaced by aa_string and
|
||||
* st_mode from where to obtain the ACLs. All other parameter specs apply.
|
||||
*/
|
||||
int iso_aa_get_acl_text(unsigned char *aa_string, mode_t st_mode,
|
||||
char **access_text, char **default_text, int flag);
|
||||
|
||||
/**
|
||||
* Backend of iso_node_get_attrs() with parameter node replaced by the
|
||||
* AAIP string from where to get the attribute list.
|
||||
* All other parameter specs apply.
|
||||
*/
|
||||
int iso_aa_get_attrs(unsigned char *aa_string, size_t *num_attrs,
|
||||
char ***names, size_t **value_lengths, char ***values, int flag);
|
||||
|
||||
/**
|
||||
* Search given name. Eventually calloc() and copy value. Add trailing 0 byte
|
||||
* for caller convenience.
|
||||
*
|
||||
* @return 1= found , 0= not found , <0 error
|
||||
*/
|
||||
int iso_aa_lookup_attr(unsigned char *aa_string, char *name,
|
||||
size_t *value_length, char **value, int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Function to identify and manage ZF parameters which do not stem from ZF
|
||||
* fields (those are known to the FileSource) and do not stem from filters
|
||||
* ("ziso" knows them globally, "osiz" knows them individually) but rather
|
||||
* from an inspection of the file content header for zisofs magic number and
|
||||
* plausible parameters.
|
||||
* The parameters get attached in struct zisofs_zf_info as xinfo to an IsoNode.
|
||||
*/
|
||||
int zisofs_zf_xinfo_func(void *data, int flag);
|
||||
|
||||
/**
|
||||
* Parameter structure which is to be managed by zisofs_zf_xinfo_func.
|
||||
*/
|
||||
struct zisofs_zf_info {
|
||||
uint32_t uncompressed_size;
|
||||
uint8_t header_size_div4;
|
||||
uint8_t block_size_log2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether a file effectively bears a zisofs file header and eventually
|
||||
* marks this by a struct zisofs_zf_info as xinfo of the file node.
|
||||
* @param flag bit0= inquire the most original stream of the file
|
||||
* bit1= permission to overwrite existing zisofs_zf_info
|
||||
* bit2= if no zisofs header is found:
|
||||
create xinfo with parameters which indicate no zisofs
|
||||
* @return 1= zf xinfo added, 0= no zisofs data found ,
|
||||
* 2= found existing zf xinfo and flag bit1 was not set
|
||||
* <0 means error
|
||||
*/
|
||||
int iso_file_zf_by_magic(IsoFile *file, int flag);
|
||||
|
||||
/*
|
||||
* @param flag
|
||||
* bit0= do only retrieve id if node is in imported ISO image
|
||||
* or has an explicit xinfo inode number
|
||||
* @return
|
||||
* 1= reply is valid from stream, 2= reply is valid from xinfo
|
||||
* 0= no id available, <0= error
|
||||
* (fs_id, dev_id, ino_id) will be (0,0,0) in case of return <= 0
|
||||
*/
|
||||
int iso_node_get_id(IsoNode *node, unsigned int *fs_id, dev_t *dev_id,
|
||||
ino_t *ino_id, int flag);
|
||||
|
||||
/* Set a new unique inode ISO image number to the given node.
|
||||
* This number shall eventually persist during image generation.
|
||||
*/
|
||||
int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag);
|
||||
|
||||
/* Use this with extreme care. Duplicate inode numbers will indicate hardlink
|
||||
* relationship between the nodes.
|
||||
*/
|
||||
int iso_node_set_ino(IsoNode *node, ino_t ino, int flag);
|
||||
|
||||
/*
|
||||
* @param flag
|
||||
* bit0= compare stat properties and attributes
|
||||
* bit1= treat all nodes with image ino == 0 as unique
|
||||
* (those with 0,0,0 are treated as unique anyway)
|
||||
*/
|
||||
int iso_node_cmp_flag(IsoNode *n1, IsoNode *n2, int flag);
|
||||
|
||||
#endif /*LIBISO_NODE_H_*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2007 Mario Danic
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
@ -9,18 +10,29 @@
|
||||
|
||||
/**
|
||||
* This header defines the functions and structures needed to add RockRidge
|
||||
* extensions to an ISO image.
|
||||
* extensions to an ISO image. It also handles AAIP and zisofs extensions.
|
||||
*
|
||||
* References:
|
||||
*
|
||||
* - SUSP (IEEE 1281).
|
||||
* System Use Sharing Protocol, draft standard version 1.12.
|
||||
* See ftp://ftp.ymi.com/pub/rockridge/susp112.ps
|
||||
*
|
||||
* - RRIP (IEEE 1282)
|
||||
* Rock Ridge Interchange Protocol, Draft Standard version 1.12.
|
||||
* See ftp://ftp.ymi.com/pub/rockridge/rrip112.ps
|
||||
*
|
||||
* - ECMA-119 (ISO-9660)
|
||||
* Volume and File Structure of CDROM for Information Interchange.
|
||||
* Volume and File Structure of CDROM for Information Interchange. See
|
||||
* http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
|
||||
*
|
||||
* - AAIP
|
||||
* Arbitrary Attribute Interchange Protocol. See doc/susp_aaip_2_0.txt
|
||||
*
|
||||
* - zisofs
|
||||
* Blockwise compression of data file content with transparent read support
|
||||
* in the Linux kernel. See doc/zisofs_format.txt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_ROCKRIDGE_H
|
||||
@ -28,6 +40,7 @@
|
||||
|
||||
#include "ecma119.h"
|
||||
|
||||
|
||||
#define SUSP_SIG(entry, a, b) ((entry->sig[0] == a) && (entry->sig[1] == b))
|
||||
|
||||
/**
|
||||
@ -115,6 +128,28 @@ struct rr_SL {
|
||||
uint8_t comps[1];
|
||||
};
|
||||
|
||||
|
||||
/** Outdated Arbitrary Attribute (AAIP, see doc/susp_aaip_1_0.txt)
|
||||
* It collided with pre-SUSP Apple AA field.
|
||||
*/
|
||||
struct aaip_AA {
|
||||
uint8_t flags[1];
|
||||
uint8_t comps[1];
|
||||
};
|
||||
|
||||
/** Arbitrary Attribute (AAIP, see doc/susp_aaip_2_0.txt) */
|
||||
struct aaip_AL {
|
||||
uint8_t flags[1];
|
||||
uint8_t comps[1];
|
||||
};
|
||||
|
||||
|
||||
/** zisofs entry (see doc/zisofs_format.txt) */
|
||||
struct zisofs_ZF {
|
||||
uint8_t parameters[1]; /* begins with BP 5 */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Struct for a SUSP System User Entry (SUSP, 4.1)
|
||||
*/
|
||||
@ -133,6 +168,9 @@ struct susp_sys_user_entry
|
||||
struct rr_NM NM;
|
||||
struct rr_CL CL;
|
||||
struct rr_SL SL;
|
||||
struct aaip_AA AA;
|
||||
struct aaip_AL AL;
|
||||
struct zisofs_ZF ZF;
|
||||
} data; /* 5 to 4+len_sue */
|
||||
};
|
||||
|
||||
@ -225,7 +263,9 @@ void susp_iter_free(SuspIterator *iter);
|
||||
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
|
||||
*
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
* < 0 on error
|
||||
* 1 on success with no inode number,
|
||||
* 2 on success with inode number,
|
||||
*/
|
||||
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st);
|
||||
|
||||
@ -264,4 +304,45 @@ int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont);
|
||||
*/
|
||||
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st);
|
||||
|
||||
|
||||
/**
|
||||
* Collects the AAIP field string from single AAIP fields.
|
||||
* (see doc/susp_aaip_1_0.txt)
|
||||
* @param aa_string Storage location of the emerging string.
|
||||
* Begin with *aa_string == NULL, or own malloc() storage.
|
||||
* @param aa_size Current allocated size of aa_string.
|
||||
* Begin with *aa_size == 0, or own storage size.
|
||||
* @param aa_len Current occupied size of aa_string.
|
||||
* Begin with *aa_len == 0
|
||||
* @param prev_field Returns the index of start of the previous field
|
||||
* in the string.
|
||||
* @param is_done The current completion state of the AAIP field string.
|
||||
* Fields will be ignored as soon as it is 1.
|
||||
* Begin with *is_done == 0
|
||||
* @param flag Unused yet. Submit 0.
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
*/
|
||||
int read_aaip_AA(struct susp_sys_user_entry *sue,
|
||||
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
|
||||
size_t *prev_field, int *is_done, int flag);
|
||||
|
||||
/**
|
||||
* Collects the AAIP field string from single AL fields.
|
||||
* (see doc/susp_aaip_2_0.txt)
|
||||
*/
|
||||
int read_aaip_AL(struct susp_sys_user_entry *sue,
|
||||
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
|
||||
size_t *prev_field, int *is_done, int flag);
|
||||
|
||||
/**
|
||||
* Reads the zisofs parameters from a ZF field (see doc/zisofs_format.txt).
|
||||
*
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
*/
|
||||
int read_zisofs_ZF(struct susp_sys_user_entry *zf, uint8_t algorithm[2],
|
||||
uint8_t *header_size_div4, uint8_t *block_size_log2,
|
||||
uint32_t *uncompressed_size, int flag);
|
||||
|
||||
#endif /* LIBISO_ROCKRIDGE_H */
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
@ -7,8 +8,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains functions related to the reading of SUSP and
|
||||
* Rock Ridge extensions on an ECMA-119 image.
|
||||
* This file contains functions related to the reading of SUSP,
|
||||
* Rock Ridge and AAIP extensions on an ECMA-119 image.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
@ -168,11 +169,14 @@ int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
|
||||
st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
|
||||
st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
|
||||
st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
|
||||
st->st_ino = 0;
|
||||
if (px->len_sue[0] == 44) {
|
||||
/* this corresponds to RRIP 1.12, so we have inode serial number */
|
||||
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
|
||||
/* Indicate that st_ino is valid */
|
||||
return 2;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,6 +406,8 @@ int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
|
||||
*/
|
||||
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
|
||||
{
|
||||
int high_shift= 0;
|
||||
|
||||
if (pn == NULL || pn == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
@ -413,7 +419,170 @@ int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
|
||||
return ISO_WRONG_RR;
|
||||
}
|
||||
|
||||
/* (dev_t << 32) causes compiler warnings on FreeBSD
|
||||
because sizeof(dev_t) is 4.
|
||||
*/
|
||||
st->st_rdev = (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
|
||||
if (sizeof(st->st_rdev) > 4) {
|
||||
high_shift = 32;
|
||||
st->st_rdev |= (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) <<
|
||||
high_shift);
|
||||
}
|
||||
|
||||
/* was originally:
|
||||
st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
|
||||
|| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
|
||||
| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
|
||||
*/
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* AA is the field signature of AAIP versions < 2.0
|
||||
*/
|
||||
int read_aaip_AA(struct susp_sys_user_entry *sue,
|
||||
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
|
||||
size_t *prev_field, int *is_done, int flag)
|
||||
{
|
||||
unsigned char *aapt;
|
||||
|
||||
if (*is_done) {
|
||||
|
||||
/* To coexist with Apple ISO :
|
||||
Gracefully react on eventually trailing Apple AA
|
||||
*/
|
||||
if (sue->version[0] != 1 || sue->len_sue[0] == 7)
|
||||
return ISO_SUCCESS;
|
||||
|
||||
return ISO_WRONG_RR;
|
||||
}
|
||||
|
||||
|
||||
/* Eventually create or grow storage */
|
||||
if (*aa_size == 0 || *aa_string == NULL) {
|
||||
|
||||
/* Gracefully react on eventually leading Apple AA
|
||||
*/
|
||||
if (sue->version[0] != 1 || sue->len_sue[0] < 9) {
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
*aa_size = *aa_len + sue->len_sue[0];
|
||||
*aa_string = calloc(*aa_size, 1);
|
||||
*aa_len = 0;
|
||||
} else if (*aa_len + sue->len_sue[0] > *aa_size) {
|
||||
|
||||
if (sue->version[0] != 1) {
|
||||
/* Apple ISO within the AAIP field group is not AAIP compliant
|
||||
*/
|
||||
return ISO_WRONG_RR;
|
||||
}
|
||||
|
||||
*aa_size += *aa_len + sue->len_sue[0];
|
||||
*aa_string = realloc(*aa_string, *aa_size);
|
||||
}
|
||||
if (*aa_string == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
|
||||
if (*aa_len > 0) {
|
||||
/* Mark prev_field as being continued */
|
||||
(*aa_string)[*prev_field + 4] = 1;
|
||||
}
|
||||
|
||||
*prev_field = *aa_len;
|
||||
|
||||
/* Compose new SUSP header with signature aa[], cont == 0 */
|
||||
aapt = *aa_string + *aa_len;
|
||||
|
||||
aapt[0] = 'A';
|
||||
aapt[1] = 'L';
|
||||
aapt[2] = sue->len_sue[0];
|
||||
aapt[3] = 1;
|
||||
aapt[4] = 0;
|
||||
|
||||
/* Append sue payload */
|
||||
memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
|
||||
*is_done = !(sue->data.AL.flags[0] & 1);
|
||||
*aa_len += sue->len_sue[0];
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* AL is the obsolete field signature of AAIP versions >= 2.0
|
||||
*/
|
||||
int read_aaip_AL(struct susp_sys_user_entry *sue,
|
||||
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
|
||||
size_t *prev_field, int *is_done, int flag)
|
||||
{
|
||||
unsigned char *aapt;
|
||||
|
||||
if (*is_done)
|
||||
return ISO_WRONG_RR;
|
||||
if (sue->version[0] != 1)
|
||||
return ISO_WRONG_RR;
|
||||
|
||||
/* Eventually create or grow storage */
|
||||
if (*aa_size == 0 || *aa_string == NULL) {
|
||||
*aa_size = *aa_len + sue->len_sue[0];
|
||||
*aa_string = calloc(*aa_size, 1);
|
||||
*aa_len = 0;
|
||||
} else if (*aa_len + sue->len_sue[0] > *aa_size) {
|
||||
*aa_size += *aa_len + sue->len_sue[0];
|
||||
*aa_string = realloc(*aa_string, *aa_size);
|
||||
}
|
||||
if (*aa_string == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
|
||||
if (*aa_len > 0) {
|
||||
/* Mark prev_field as being continued */
|
||||
(*aa_string)[*prev_field + 4] = 1;
|
||||
}
|
||||
|
||||
*prev_field = *aa_len;
|
||||
|
||||
/* Compose new SUSP header with signature aa[], cont == 0 */
|
||||
aapt = *aa_string + *aa_len;
|
||||
|
||||
aapt[0] = 'A';
|
||||
aapt[1] = 'L';
|
||||
aapt[2] = sue->len_sue[0];
|
||||
aapt[3] = 1;
|
||||
aapt[4] = 0;
|
||||
|
||||
/* Append sue payload */
|
||||
memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
|
||||
*is_done = !(sue->data.AL.flags[0] & 1);
|
||||
*aa_len += sue->len_sue[0];
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the zisofs parameters from a ZF field (see doc/zisofs_format.txt).
|
||||
*
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
*/
|
||||
int read_zisofs_ZF(struct susp_sys_user_entry *zf, uint8_t algorithm[2],
|
||||
uint8_t *header_size_div4, uint8_t *block_size_log2,
|
||||
uint32_t *uncompressed_size, int flag)
|
||||
{
|
||||
if (zf == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (zf->sig[0] != 'Z' || zf->sig[1] != 'F') {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
if (zf->len_sue[0] != 16) {
|
||||
return ISO_WRONG_RR;
|
||||
}
|
||||
algorithm[0] = zf->data.ZF.parameters[0];
|
||||
algorithm[1] = zf->data.ZF.parameters[1];
|
||||
*header_size_div4 = zf->data.ZF.parameters[2];
|
||||
*block_size_log2 = zf->data.ZF.parameters[3];
|
||||
*uncompressed_size = iso_read_bb(&(zf->data.ZF.parameters[4]), 4, NULL);
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
@ -13,19 +14,12 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
ino_t serial_id = (ino_t)1;
|
||||
ino_t mem_serial_id = (ino_t)1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IsoFileSource *src;
|
||||
|
||||
/* key for file identification inside filesystem */
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
off_t size; /**< size of this file */
|
||||
} FSrcStreamData;
|
||||
ino_t cut_out_serial_id = (ino_t)1;
|
||||
|
||||
static
|
||||
int fsrc_open(IsoStream *stream)
|
||||
@ -114,7 +108,7 @@ void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
{
|
||||
FSrcStreamData *data;
|
||||
IsoFilesystem *fs;
|
||||
|
||||
|
||||
data = (FSrcStreamData*)stream->data;
|
||||
fs = iso_file_source_get_filesystem(data->src);
|
||||
|
||||
@ -123,14 +117,6 @@ void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
*ino_id = data->ino_id;
|
||||
}
|
||||
|
||||
static
|
||||
char *fsrc_get_name(IsoStream *stream)
|
||||
{
|
||||
FSrcStreamData *data;
|
||||
data = (FSrcStreamData*)stream->data;
|
||||
return iso_file_source_get_path(data->src);
|
||||
}
|
||||
|
||||
static
|
||||
void fsrc_free(IsoStream *stream)
|
||||
{
|
||||
@ -140,15 +126,37 @@ void fsrc_free(IsoStream *stream)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static
|
||||
int fsrc_update_size(IsoStream *stream)
|
||||
{
|
||||
int ret;
|
||||
struct stat info;
|
||||
IsoFileSource *src;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
src = ((FSrcStreamData*)stream->data)->src;
|
||||
ret = iso_file_source_stat(src, &info);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
((FSrcStreamData*)stream->data)->size = info.st_size;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
IsoStreamIface fsrc_stream_class = {
|
||||
1, /* update_size is defined for this stream */
|
||||
"fsrc",
|
||||
fsrc_open,
|
||||
fsrc_close,
|
||||
fsrc_get_size,
|
||||
fsrc_read,
|
||||
fsrc_is_repeatable,
|
||||
fsrc_get_id,
|
||||
fsrc_get_name,
|
||||
fsrc_free
|
||||
fsrc_free,
|
||||
fsrc_update_size
|
||||
};
|
||||
|
||||
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
@ -169,7 +177,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
return ISO_FILE_IS_DIR;
|
||||
}
|
||||
|
||||
|
||||
/* check for read access to contents */
|
||||
r = iso_file_source_access(src);
|
||||
if (r < 0) {
|
||||
@ -181,7 +189,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(FSrcStreamData));
|
||||
if (str == NULL) {
|
||||
if (data == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
@ -189,7 +197,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
/* take the ref to IsoFileSource */
|
||||
data->src = src;
|
||||
data->size = info.st_size;
|
||||
|
||||
|
||||
/* get the id numbers */
|
||||
{
|
||||
IsoFilesystem *fs;
|
||||
@ -198,7 +206,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
|
||||
fs_id = fs->get_id(fs);
|
||||
if (fs_id == 0) {
|
||||
/*
|
||||
/*
|
||||
* the filesystem implementation is unable to provide valid
|
||||
* st_dev and st_ino fields. Use serial_id.
|
||||
*/
|
||||
@ -219,6 +227,220 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
}
|
||||
|
||||
|
||||
int iso_stream_get_src_zf(IsoStream *stream, int *header_size_div4,
|
||||
int *block_size_log2, uint32_t *uncompressed_size,
|
||||
int flag)
|
||||
{
|
||||
int ret;
|
||||
FSrcStreamData *data;
|
||||
IsoFileSource *src;
|
||||
|
||||
/* Intimate friendship with libisofs/fs_image.c */
|
||||
int iso_ifs_source_get_zf(IsoFileSource *src, int *header_size_div4,
|
||||
int *block_size_log2, uint32_t *uncompressed_size, int flag);
|
||||
|
||||
if (stream->class != &fsrc_stream_class)
|
||||
return 0;
|
||||
data = stream->data;
|
||||
src = data->src;
|
||||
|
||||
ret = iso_ifs_source_get_zf(src, header_size_div4, block_size_log2,
|
||||
uncompressed_size, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct cut_out_stream
|
||||
{
|
||||
IsoFileSource *src;
|
||||
|
||||
/* key for file identification inside filesystem */
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
off_t offset; /**< offset where read begins */
|
||||
off_t size; /**< size of this file */
|
||||
off_t pos; /* position on the file for read */
|
||||
};
|
||||
|
||||
static
|
||||
int cut_out_open(IsoStream *stream)
|
||||
{
|
||||
int ret;
|
||||
struct stat info;
|
||||
IsoFileSource *src;
|
||||
struct cut_out_stream *data;
|
||||
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
data = stream->data;
|
||||
src = data->src;
|
||||
ret = iso_file_source_stat(data->src, &info);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = iso_file_source_open(src);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
{
|
||||
off_t ret;
|
||||
if (data->offset > info.st_size) {
|
||||
/* file is smaller than expected */
|
||||
ret = iso_file_source_lseek(src, info.st_size, 0);
|
||||
} else {
|
||||
ret = iso_file_source_lseek(src, data->offset, 0);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return (int) ret;
|
||||
}
|
||||
}
|
||||
data->pos = 0;
|
||||
if (data->offset + data->size > info.st_size) {
|
||||
return 3; /* file smaller than expected */
|
||||
} else {
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_close(IsoStream *stream)
|
||||
{
|
||||
IsoFileSource *src;
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
src = ((struct cut_out_stream*)stream->data)->src;
|
||||
return iso_file_source_close(src);
|
||||
}
|
||||
|
||||
static
|
||||
off_t cut_out_get_size(IsoStream *stream)
|
||||
{
|
||||
struct cut_out_stream *data = stream->data;
|
||||
return data->size;
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_read(IsoStream *stream, void *buf, size_t count)
|
||||
{
|
||||
struct cut_out_stream *data = stream->data;
|
||||
count = (size_t)MIN(data->size - data->pos, count);
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
return iso_file_source_read(data->src, buf, count);
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_is_repeatable(IsoStream *stream)
|
||||
{
|
||||
/* reg files are always repeatable */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
ino_t *ino_id)
|
||||
{
|
||||
FSrcStreamData *data;
|
||||
IsoFilesystem *fs;
|
||||
|
||||
data = (FSrcStreamData*)stream->data;
|
||||
fs = iso_file_source_get_filesystem(data->src);
|
||||
|
||||
*fs_id = fs->get_id(fs);
|
||||
*dev_id = data->dev_id;
|
||||
*ino_id = data->ino_id;
|
||||
}
|
||||
|
||||
static
|
||||
void cut_out_free(IsoStream *stream)
|
||||
{
|
||||
struct cut_out_stream *data = stream->data;
|
||||
iso_file_source_unref(data->src);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO update cut out streams to deal with update_size(). Seems hard.
|
||||
*/
|
||||
IsoStreamIface cut_out_stream_class = {
|
||||
0,
|
||||
"cout",
|
||||
cut_out_open,
|
||||
cut_out_close,
|
||||
cut_out_get_size,
|
||||
cut_out_read,
|
||||
cut_out_is_repeatable,
|
||||
cut_out_get_id,
|
||||
cut_out_free
|
||||
};
|
||||
|
||||
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
|
||||
IsoStream **stream)
|
||||
{
|
||||
int r;
|
||||
struct stat info;
|
||||
IsoStream *str;
|
||||
struct cut_out_stream *data;
|
||||
|
||||
if (src == NULL || stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (size == 0) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
|
||||
r = iso_file_source_stat(src, &info);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
if (offset > info.st_size) {
|
||||
return ISO_FILE_OFFSET_TOO_BIG;
|
||||
}
|
||||
|
||||
/* check for read access to contents */
|
||||
r = iso_file_source_access(src);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
str = malloc(sizeof(IsoStream));
|
||||
if (str == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(struct cut_out_stream));
|
||||
if (data == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* take a new ref to IsoFileSource */
|
||||
data->src = src;
|
||||
iso_file_source_ref(src);
|
||||
|
||||
data->offset = offset;
|
||||
data->size = MIN(info.st_size - offset, size);
|
||||
|
||||
/* get the id numbers */
|
||||
data->dev_id = (dev_t) 0;
|
||||
data->ino_id = cut_out_serial_id++;
|
||||
|
||||
str->refcount = 1;
|
||||
str->data = data;
|
||||
str->class = &cut_out_stream_class;
|
||||
|
||||
*stream = str;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -237,7 +459,7 @@ int mem_open(IsoStream *stream)
|
||||
}
|
||||
data = (MemStreamData*)stream->data;
|
||||
if (data->offset != -1) {
|
||||
return ISO_FILE_ALREADY_OPENNED;
|
||||
return ISO_FILE_ALREADY_OPENED;
|
||||
}
|
||||
data->offset = 0;
|
||||
return ISO_SUCCESS;
|
||||
@ -252,7 +474,7 @@ int mem_close(IsoStream *stream)
|
||||
}
|
||||
data = (MemStreamData*)stream->data;
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
data->offset = -1;
|
||||
return ISO_SUCCESS;
|
||||
@ -279,15 +501,15 @@ int mem_read(IsoStream *stream, void *buf, size_t count)
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
data = stream->data;
|
||||
|
||||
|
||||
if (data->offset == -1) {
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
|
||||
|
||||
if (data->offset >= data->size) {
|
||||
return 0; /* EOF */
|
||||
}
|
||||
|
||||
|
||||
len = MIN(count, data->size - data->offset);
|
||||
memcpy(buf, data->buf + data->offset, len);
|
||||
data->offset += len;
|
||||
@ -311,12 +533,6 @@ void mem_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
*ino_id = data->ino_id;
|
||||
}
|
||||
|
||||
static
|
||||
char *mem_get_name(IsoStream *stream)
|
||||
{
|
||||
return strdup("[MEMORY SOURCE]");
|
||||
}
|
||||
|
||||
static
|
||||
void mem_free(IsoStream *stream)
|
||||
{
|
||||
@ -327,20 +543,21 @@ void mem_free(IsoStream *stream)
|
||||
}
|
||||
|
||||
IsoStreamIface mem_stream_class = {
|
||||
0,
|
||||
"mem ",
|
||||
mem_open,
|
||||
mem_close,
|
||||
mem_get_size,
|
||||
mem_read,
|
||||
mem_is_repeatable,
|
||||
mem_get_id,
|
||||
mem_get_name,
|
||||
mem_free
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a stream for reading from a arbitrary memory buffer.
|
||||
* When the Stream refcount reach 0, the buffer is free(3).
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 sucess, < 0 error
|
||||
*/
|
||||
@ -420,6 +637,13 @@ int iso_stream_is_repeatable(IsoStream *stream)
|
||||
return stream->class->is_repeatable(stream);
|
||||
}
|
||||
|
||||
inline
|
||||
int iso_stream_update_size(IsoStream *stream)
|
||||
{
|
||||
IsoStreamIface* class = stream->class;
|
||||
return (class->version >= 1) ? class->update_size(stream) : 0;
|
||||
}
|
||||
|
||||
inline
|
||||
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
ino_t *ino_id)
|
||||
@ -427,8 +651,182 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
stream->class->get_id(stream, fs_id, dev_id, ino_id);
|
||||
}
|
||||
|
||||
inline
|
||||
char *iso_stream_get_name(IsoStream *stream)
|
||||
void iso_stream_get_file_name(IsoStream *stream, char *name)
|
||||
{
|
||||
return stream->class->get_name(stream);
|
||||
char *type = stream->class->type;
|
||||
|
||||
if (!strncmp(type, "fsrc", 4)) {
|
||||
FSrcStreamData *data = stream->data;
|
||||
char *path = iso_file_source_get_path(data->src);
|
||||
strncpy(name, path, PATH_MAX);
|
||||
free(path);
|
||||
} else if (!strncmp(type, "boot", 4)) {
|
||||
strcpy(name, "BOOT CATALOG");
|
||||
} else if (!strncmp(type, "mem ", 4)) {
|
||||
strcpy(name, "MEM SOURCE");
|
||||
} else if (!strncmp(type, "extf", 4)) {
|
||||
strcpy(name, "EXTERNAL FILTER");
|
||||
} else {
|
||||
strcpy(name, "UNKNOWN SOURCE");
|
||||
}
|
||||
}
|
||||
|
||||
IsoStream *iso_stream_get_input_stream(IsoStream *stream, int flag)
|
||||
{
|
||||
IsoStreamIface* class;
|
||||
|
||||
if (stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
class = stream->class;
|
||||
if (class->version < 2)
|
||||
return NULL;
|
||||
return class->get_input_stream(stream, 0);
|
||||
}
|
||||
|
||||
char *iso_stream_get_source_path(IsoStream *stream, int flag)
|
||||
{
|
||||
char *path = NULL, ivd[80], *raw_path = NULL;
|
||||
|
||||
if (stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (stream->class == &fsrc_stream_class) {
|
||||
FSrcStreamData *fsrc_data = stream->data;
|
||||
|
||||
path = iso_file_source_get_path(fsrc_data->src);
|
||||
} else if (stream->class == &cut_out_stream_class) {
|
||||
struct cut_out_stream *cout_data = stream->data;
|
||||
|
||||
raw_path = iso_file_source_get_path(cout_data->src);
|
||||
sprintf(ivd, " %.f %.f",
|
||||
(double) cout_data->offset, (double) cout_data->size);
|
||||
path= calloc(strlen(raw_path) + strlen(ivd) + 1, 1);
|
||||
if (path == NULL) {
|
||||
goto ex;
|
||||
}
|
||||
strcpy(path, raw_path);
|
||||
strcat(path, ivd);
|
||||
}
|
||||
ex:;
|
||||
if (raw_path != NULL)
|
||||
free(raw_path);
|
||||
return path;
|
||||
}
|
||||
|
||||
/* @return 1 = ok , 0 = not an ISO image stream , <0 = error */
|
||||
int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag)
|
||||
{
|
||||
if (stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (stream->class == &fsrc_stream_class) {
|
||||
FSrcStreamData *fsrc_data = stream->data;
|
||||
fsrc_data->ino_id = ino;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* API */
|
||||
int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
|
||||
{
|
||||
int ret;
|
||||
unsigned int fs_id1, fs_id2;
|
||||
dev_t dev_id1, dev_id2;
|
||||
ino_t ino_id1, ino_id2;
|
||||
off_t size1, size2;
|
||||
FSrcStreamData *fssd1, *fssd2;
|
||||
|
||||
|
||||
/* <<<
|
||||
#define Libisofs_stream_cmp_ino_debuG 1
|
||||
*/
|
||||
#ifdef Libisofs_stream_cmp_ino_debuG
|
||||
static int report_counter = 0;
|
||||
static int debug = 1;
|
||||
#endif /* Libisofs_stream_cmp_ino_debuG */
|
||||
|
||||
if (s1 == s2)
|
||||
return 0;
|
||||
if (s1 == NULL)
|
||||
return -1;
|
||||
if (s2 == NULL)
|
||||
return 1;
|
||||
|
||||
if (s1->class->version >= 3 && !(flag & 1)) {
|
||||
/* Filters may have smarter methods to compare themselves with others */
|
||||
ret = s1->class->cmp_ino(s1, s2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iso_stream_get_id(s1, &fs_id1, &dev_id1, &ino_id1);
|
||||
iso_stream_get_id(s2, &fs_id2, &dev_id2, &ino_id2);
|
||||
if (fs_id1 < fs_id2) {
|
||||
return -1;
|
||||
} else if (fs_id1 > fs_id2) {
|
||||
return 1;
|
||||
}
|
||||
/* files belong to the same fs */
|
||||
if (dev_id1 > dev_id2) {
|
||||
return -1;
|
||||
} else if (dev_id1 < dev_id2) {
|
||||
return 1;
|
||||
} else if (ino_id1 < ino_id2) {
|
||||
return -1;
|
||||
} else if (ino_id1 > ino_id2) {
|
||||
return 1;
|
||||
}
|
||||
size1 = iso_stream_get_size(s1);
|
||||
size2 = iso_stream_get_size(s2);
|
||||
if (size1 < size2) {
|
||||
|
||||
#ifdef Libisofs_stream_cmp_ino_debuG
|
||||
if (debug) {
|
||||
if (report_counter < 5)
|
||||
fprintf(stderr,
|
||||
"\n\nlibisofs_DEBUG : Program error: same ino but differing size\n\n\n");
|
||||
else if (report_counter == 5)
|
||||
fprintf(stderr,
|
||||
"\n\nlibisofs_DEBUG : Inode error: more of same ino but differing size\n\n\n");
|
||||
report_counter++;
|
||||
}
|
||||
#endif /* Libisofs_stream_cmp_ino_debuG */
|
||||
|
||||
return -1;
|
||||
} else if (size1 > size2) {
|
||||
|
||||
#ifdef Libisofs_stream_cmp_ino_debuG
|
||||
if (debug) {
|
||||
if (report_counter < 5)
|
||||
fprintf(stderr,
|
||||
"\n\nlibisofs_DEBUG : Inode error: same ino but differing size\n\n\n");
|
||||
else if (report_counter == 5)
|
||||
fprintf(stderr,
|
||||
"\n\nlibisofs_DEBUG : Program error: more of same ino but differing size\n\n\n");
|
||||
report_counter++;
|
||||
}
|
||||
#endif /* Libisofs_stream_cmp_ino_debuG */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s1->class != s2->class)
|
||||
return (s1->class < s2->class ? -1 : 1);
|
||||
if (s1->class == &fsrc_stream_class) {
|
||||
/* Compare eventual image data section LBA and sizes */
|
||||
fssd1= (FSrcStreamData *) s1->data;
|
||||
fssd2= (FSrcStreamData *) s2->data;
|
||||
ret = iso_ifs_sections_cmp(fssd1->src, fssd2->src, 0);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef Libisofs_hardlink_matcheR
|
||||
if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) {
|
||||
return (s1 < s2 ? -1 : 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* Copyright (c) 2009 Thomas Schmitt
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_STREAM_H_
|
||||
@ -13,133 +14,73 @@
|
||||
*/
|
||||
#include "fsource.h"
|
||||
|
||||
/**
|
||||
* serial number to be used when you can't get a valid id for a Stream by other
|
||||
* means. If you use this, both fs_id and dev_id should be set to 0.
|
||||
* This must be incremented each time you get a reference to it.
|
||||
*/
|
||||
extern ino_t serial_id;
|
||||
|
||||
/*
|
||||
* Some functions here will be moved to libisofs.h when we expose
|
||||
* Streams.
|
||||
*/
|
||||
|
||||
typedef struct Iso_Stream IsoStream;
|
||||
|
||||
typedef struct IsoStream_Iface
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* Opens the stream.
|
||||
*
|
||||
* @return
|
||||
* 1 on success, 2 file greater than expected, 3 file smaller than
|
||||
* expected, < 0 on error
|
||||
*/
|
||||
int (*open)(IsoStream *stream);
|
||||
IsoFileSource *src;
|
||||
|
||||
/**
|
||||
* Close the Stream.
|
||||
* @return 1 on success, < 0 on error
|
||||
*/
|
||||
int (*close)(IsoStream *stream);
|
||||
/* key for file identification inside filesystem */
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
off_t size; /**< size of this file */
|
||||
} FSrcStreamData;
|
||||
|
||||
/**
|
||||
* Get the size (in bytes) of the stream. This function should always
|
||||
* return the same size, even if the underlying source size changes.
|
||||
*/
|
||||
off_t (*get_size)(IsoStream *stream);
|
||||
|
||||
/**
|
||||
* Attempts to read up to count bytes from the given stream into
|
||||
* the buffer starting at buf.
|
||||
*
|
||||
* The stream must be open() before calling this, and close() when no
|
||||
* more needed.
|
||||
*
|
||||
* @return
|
||||
* number of bytes read, 0 if EOF, < 0 on error
|
||||
*/
|
||||
int (*read)(IsoStream *stream, void *buf, size_t count);
|
||||
|
||||
/**
|
||||
* Whether this Stram can be read several times, with the same results.
|
||||
* For example, a regular file is repeatable, you can read it as many
|
||||
* times as you want. However, a pipe isn't.
|
||||
*
|
||||
* This function doesn't take into account if the file has been modified
|
||||
* between the two reads.
|
||||
*
|
||||
* @return
|
||||
* 1 if stream is repeatable, 0 if not, < 0 on error
|
||||
*/
|
||||
int (*is_repeatable)(IsoStream *stream);
|
||||
|
||||
/**
|
||||
* Get an unique identifier for the IsoStream.
|
||||
*/
|
||||
void (*get_id)(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
ino_t *ino_id);
|
||||
|
||||
/**
|
||||
* Get a name that identifies the Stream contents. It is used only for
|
||||
* informational or debug purposes, so you can return anything you
|
||||
* consider suitable for identification of the source, such as the path.
|
||||
*/
|
||||
char *(*get_name)(IsoStream *stream);
|
||||
|
||||
/**
|
||||
* Free implementation specific data. Should never be called by user.
|
||||
* Use iso_stream_unref() instead.
|
||||
*/
|
||||
void (*free)(IsoStream *stream);
|
||||
} IsoStreamIface;
|
||||
|
||||
struct Iso_Stream
|
||||
{
|
||||
IsoStreamIface *class;
|
||||
int refcount;
|
||||
void *data;
|
||||
};
|
||||
|
||||
void iso_stream_ref(IsoStream *stream);
|
||||
void iso_stream_unref(IsoStream *stream);
|
||||
|
||||
int iso_stream_open(IsoStream *stream);
|
||||
|
||||
int iso_stream_close(IsoStream *stream);
|
||||
|
||||
off_t iso_stream_get_size(IsoStream *stream);
|
||||
|
||||
int iso_stream_read(IsoStream *stream, void *buf, size_t count);
|
||||
|
||||
int iso_stream_is_repeatable(IsoStream *stream);
|
||||
|
||||
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||
ino_t *ino_id);
|
||||
|
||||
char *iso_stream_get_name(IsoStream *stream);
|
||||
/**
|
||||
* Get an identifier for the file of the source, for debug purposes
|
||||
* @param name
|
||||
* Should provide at least PATH_MAX bytes
|
||||
*/
|
||||
void iso_stream_get_file_name(IsoStream *stream, char *name);
|
||||
|
||||
/**
|
||||
* Create a stream to read from a IsoFileSource.
|
||||
* The stream will take the ref. to the IsoFileSource, so after a successfully
|
||||
* exectution of this function, you musn't unref() the source, unless you
|
||||
* take an extra ref.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 sucess, < 0 error
|
||||
* Possible errors:
|
||||
*
|
||||
*
|
||||
*/
|
||||
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream);
|
||||
|
||||
/**
|
||||
* Create a new stream to read a chunk of an IsoFileSource..
|
||||
* The stream will add a ref. to the IsoFileSource.
|
||||
*
|
||||
* @return
|
||||
* 1 sucess, < 0 error
|
||||
*/
|
||||
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
|
||||
IsoStream **stream);
|
||||
|
||||
/**
|
||||
* Create a stream for reading from a arbitrary memory buffer.
|
||||
* When the Stream refcount reach 0, the buffer is free(3).
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* 1 sucess, < 0 error
|
||||
*/
|
||||
int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream);
|
||||
|
||||
/**
|
||||
* Obtain eventual zisofs ZF field entry parameters from a file source out
|
||||
* of a loaded ISO image.
|
||||
* To make hope for non-zero reply the stream has to be the original stream
|
||||
* of an IsoFile with .from_old_session==1. The call is safe with any stream
|
||||
* type, though, unless fsrc_stream_class would be used without FSrcStreamData.
|
||||
* @return 1= returned parameters are valid, 0=no ZF info found , <0 error
|
||||
*/
|
||||
int iso_stream_get_src_zf(IsoStream *stream, int *header_size_div4,
|
||||
int *block_size_log2, uint32_t *uncompressed_size,
|
||||
int flag);
|
||||
|
||||
/**
|
||||
* Set the inode number of a stream that is based on FSrcStreamData, i.e.
|
||||
* stems from the imported ISO image.
|
||||
* @return 1 = ok , 0 = not an ISO image stream , <0 = error
|
||||
*/
|
||||
int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag);
|
||||
|
||||
|
||||
#endif /*STREAM_H_*/
|
||||
|
65
libisofs/system_area.c
Normal file
65
libisofs/system_area.c
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "system_area.h"
|
||||
#include "eltorito.h"
|
||||
#include "filesrc.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
|
||||
*
|
||||
* It is assumed that the caller has verified the readiness of the boot image
|
||||
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
|
||||
*
|
||||
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
|
||||
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
|
||||
* It will get rounded up to full MBs and that many blocks
|
||||
* must really be written as ISO 9660 image.
|
||||
* @param mbr A buffer of at least 512 bytes to take the result which is
|
||||
* to be written as the very beginning of the ISO.
|
||||
* @param flag unused yet, submit 0
|
||||
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
|
||||
*/
|
||||
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
|
||||
|
||||
int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
|
||||
{
|
||||
if ((t == NULL) || (buf == NULL)) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
/* set buf to 0s */
|
||||
memset(buf, 0, 16 * BLOCK_SIZE);
|
||||
|
||||
if (t->catalog != NULL && t->catalog->image->isolinux_options & 0x02) {
|
||||
/* We need to write a MBR for an hybrid image */
|
||||
int ret;
|
||||
int img_blocks;
|
||||
|
||||
img_blocks = t->curblock;
|
||||
ret = make_isohybrid_mbr(t->bootimg->sections[0].block, &img_blocks, (char*)buf, 0);
|
||||
|
||||
/*
|
||||
API description of el_torito_set_isolinux_options() prescribes
|
||||
to pad to full MB.
|
||||
So this is not urgent any more :
|
||||
|
||||
// FIXME the new img_blocks size should be taken into account
|
||||
*/
|
||||
|
||||
if (ret != 1) {
|
||||
/* error, it should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
48
libisofs/system_area.h
Normal file
48
libisofs/system_area.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions for dealing with the system area, this is, the first 16 blocks
|
||||
* of the image.
|
||||
*
|
||||
* At this time, this is only used for hybrid boot images with isolinux.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_AREA_H_
|
||||
#define SYSTEM_AREA_H_
|
||||
|
||||
#include "ecma119.h"
|
||||
|
||||
/*
|
||||
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
|
||||
*
|
||||
* It is assumed that the caller has verified the readiness of the boot image
|
||||
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
|
||||
*
|
||||
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
|
||||
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
|
||||
* It will get rounded up to full MBs and that many blocks
|
||||
* must really be written as ISO 9660 image.
|
||||
* @param mbr A buffer of at least 512 bytes to take the result which is
|
||||
* to be written as the very beginning of the ISO.
|
||||
* @param flag unused yet, submit 0
|
||||
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
|
||||
*/
|
||||
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
|
||||
|
||||
/**
|
||||
* Write the system area for the given image to the given buffer.
|
||||
*
|
||||
* @param buf
|
||||
* A buffer with at least 32 K allocated
|
||||
* @return
|
||||
* 1 if success, < 0 on error
|
||||
*/
|
||||
int iso_write_system_area(Ecma119Image *t, uint8_t *buf);
|
||||
|
||||
#endif /* SYSTEM_AREA_H_ */
|
233
libisofs/tree.c
233
libisofs/tree.c
@ -256,6 +256,81 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
|
||||
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new regular file to the iso tree. Permissions are set to 0444,
|
||||
* owner and hidden atts are taken from parent. You can modify any of them
|
||||
* later.
|
||||
*
|
||||
* @param parent
|
||||
* the dir where the new file will be created
|
||||
* @param name
|
||||
* name for the new file. If a node with same name already exists on
|
||||
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
|
||||
* @param stream
|
||||
* IsoStream for the contents of the file
|
||||
* @param file
|
||||
* place where to store a pointer to the newly created file. No extra
|
||||
* ref is addded, so you will need to call iso_node_ref() if you really
|
||||
* need it. You can pass NULL in this parameter if you don't need the
|
||||
* pointer
|
||||
* @return
|
||||
* number of nodes in parent if success, < 0 otherwise
|
||||
* Possible errors:
|
||||
* ISO_NULL_POINTER, if parent, name or dest are NULL
|
||||
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
|
||||
* ISO_OUT_OF_MEM
|
||||
*
|
||||
* @since 0.6.4
|
||||
*/
|
||||
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
|
||||
IsoFile **file)
|
||||
{
|
||||
int ret;
|
||||
char *n;
|
||||
IsoFile *node;
|
||||
IsoNode **pos;
|
||||
time_t now;
|
||||
|
||||
if (parent == NULL || name == NULL || stream == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (file) {
|
||||
*file = NULL;
|
||||
}
|
||||
|
||||
/* find place where to insert */
|
||||
if (iso_dir_exists(parent, name, &pos)) {
|
||||
/* a node with same name already exists */
|
||||
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||
}
|
||||
|
||||
n = strdup(name);
|
||||
ret = iso_node_new_file(n, stream, &node);
|
||||
if (ret < 0) {
|
||||
free(n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* permissions from parent */
|
||||
iso_node_set_permissions((IsoNode*)node, 0444);
|
||||
iso_node_set_uid((IsoNode*)node, parent->node.uid);
|
||||
iso_node_set_gid((IsoNode*)node, parent->node.gid);
|
||||
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
|
||||
|
||||
/* current time */
|
||||
now = time(NULL);
|
||||
iso_node_set_atime((IsoNode*)node, now);
|
||||
iso_node_set_ctime((IsoNode*)node, now);
|
||||
iso_node_set_mtime((IsoNode*)node, now);
|
||||
|
||||
if (file) {
|
||||
*file = node;
|
||||
}
|
||||
|
||||
/* add to dir */
|
||||
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to follow or not symbolic links when added a file from a source
|
||||
* to IsoImage.
|
||||
@ -475,6 +550,139 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
|
||||
return result;
|
||||
}
|
||||
|
||||
int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
|
||||
const char *path, IsoNode **node)
|
||||
{
|
||||
int result;
|
||||
IsoFilesystem *fs;
|
||||
IsoFileSource *file;
|
||||
IsoNode *new;
|
||||
IsoNode **pos;
|
||||
|
||||
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
*node = NULL;
|
||||
}
|
||||
|
||||
fs = image->fs;
|
||||
result = fs->get_by_path(fs, path, &file);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* find place where to insert */
|
||||
result = iso_dir_exists(parent, name, &pos);
|
||||
if (result) {
|
||||
/* a node with same name already exists */
|
||||
iso_file_source_unref(file);
|
||||
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||
}
|
||||
|
||||
result = image->builder->create_node(image->builder, image, file, &new);
|
||||
|
||||
/* free the file */
|
||||
iso_file_source_unref(file);
|
||||
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = iso_node_set_name(new, name);
|
||||
if (result < 0) {
|
||||
iso_node_unref(new);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
*node = new;
|
||||
}
|
||||
|
||||
/* finally, add node to parent */
|
||||
return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
|
||||
}
|
||||
|
||||
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
|
||||
const char *name, const char *path,
|
||||
off_t offset, off_t size,
|
||||
IsoNode **node)
|
||||
{
|
||||
int result;
|
||||
struct stat info;
|
||||
IsoFilesystem *fs;
|
||||
IsoFileSource *src;
|
||||
IsoFile *new;
|
||||
IsoNode **pos;
|
||||
IsoStream *stream;
|
||||
|
||||
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
*node = NULL;
|
||||
}
|
||||
|
||||
/* find place where to insert */
|
||||
result = iso_dir_exists(parent, name, &pos);
|
||||
if (result) {
|
||||
/* a node with same name already exists */
|
||||
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||
}
|
||||
|
||||
fs = image->fs;
|
||||
result = fs->get_by_path(fs, path, &src);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = iso_file_source_stat(src, &info);
|
||||
if (result < 0) {
|
||||
iso_file_source_unref(src);
|
||||
return result;
|
||||
}
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
if (offset >= info.st_size) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
|
||||
/* force regular file */
|
||||
result = image->builder->create_file(image->builder, image, src, &new);
|
||||
|
||||
/* free the file */
|
||||
iso_file_source_unref(src);
|
||||
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* replace file iso stream with a cut-out-stream */
|
||||
result = iso_cut_out_stream_new(src, offset, size, &stream);
|
||||
if (result < 0) {
|
||||
iso_node_unref((IsoNode*)new);
|
||||
return result;
|
||||
}
|
||||
iso_stream_unref(new->stream);
|
||||
new->stream = stream;
|
||||
|
||||
result = iso_node_set_name((IsoNode*)new, name);
|
||||
if (result < 0) {
|
||||
iso_node_unref((IsoNode*)new);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
*node = (IsoNode*)new;
|
||||
}
|
||||
|
||||
/* finally, add node to parent */
|
||||
return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
|
||||
}
|
||||
|
||||
static
|
||||
int check_excludes(IsoImage *image, const char *path)
|
||||
{
|
||||
@ -730,6 +938,7 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
|
||||
while (component) {
|
||||
if (n->type != LIBISO_DIR) {
|
||||
n = NULL;
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
dir = (IsoDir *)n;
|
||||
@ -749,3 +958,27 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *iso_tree_get_node_path(IsoNode *node)
|
||||
{
|
||||
if (node == NULL || node->parent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((IsoNode*)node->parent == node) {
|
||||
return strdup("/");
|
||||
} else {
|
||||
char path[PATH_MAX];
|
||||
char *parent_path = iso_tree_get_node_path((IsoNode*)node->parent);
|
||||
if (parent_path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (strlen(parent_path) == 1) {
|
||||
snprintf(path, PATH_MAX, "/%s", node->name);
|
||||
} else {
|
||||
snprintf(path, PATH_MAX, "%s/%s", parent_path, node->name);
|
||||
}
|
||||
free(parent_path);
|
||||
return strdup(path);
|
||||
}
|
||||
}
|
||||
|
368
libisofs/util.c
368
libisofs/util.c
@ -13,24 +13,132 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <iconv.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <iconv.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
/* if we don't have eaccess, we check file access by openning it */
|
||||
/* if we don't have eaccess, we check file access by opening it */
|
||||
#ifndef HAVE_EACCESS
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Produce possibly inflationary error messages directly to stderr */
|
||||
static int iso_iconv_debug = 0;
|
||||
|
||||
|
||||
struct iso_iconv_handle {
|
||||
int status; /* bit0= open , bit1= identical mapping */
|
||||
iconv_t descr;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
@param flag bit0= shortcut by identical mapping is not allowed
|
||||
*/
|
||||
static
|
||||
int iso_iconv_open(struct iso_iconv_handle *handle,
|
||||
char *tocode, char *fromcode, int flag)
|
||||
{
|
||||
handle->status = 0;
|
||||
handle->descr = (iconv_t) -1;
|
||||
|
||||
if (strcmp(tocode, fromcode) == 0 && !(flag & 1)) {
|
||||
handle->status = 1 | 2;
|
||||
return 1;
|
||||
}
|
||||
handle->descr = iconv_open(tocode, fromcode);
|
||||
if (handle->descr == (iconv_t) -1) {
|
||||
if (strlen(tocode) + strlen(fromcode) <= 160 && iso_iconv_debug)
|
||||
fprintf(stderr,
|
||||
"libisofs_DEBUG: iconv_open(\"%s\", \"%s\") failed: errno= %d %s\n",
|
||||
tocode, fromcode, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
handle->status = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
size_t iso_iconv(struct iso_iconv_handle *handle,
|
||||
char **inbuf, size_t *inbytesleft,
|
||||
char **outbuf, size_t *outbytesleft, int flag)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
if (!(handle->status & 1)) {
|
||||
if (iso_iconv_debug)
|
||||
fprintf(stderr,
|
||||
"libisofs_DEBUG: iso_iconv(): iso_iconv_handle not in open state\n");
|
||||
return (size_t) -1;
|
||||
}
|
||||
if (handle->status & 2) {
|
||||
if (inbuf == NULL || outbuf == NULL) {
|
||||
null_buf:;
|
||||
if (iso_iconv_debug)
|
||||
fprintf(stderr,
|
||||
"libisofs_DEBUG: iso_iconv(): NULL buffers not allowed in shortcut mapping\n");
|
||||
return (size_t) -1;
|
||||
}
|
||||
if (*inbuf == NULL || *outbuf == NULL)
|
||||
goto null_buf;
|
||||
while (*inbytesleft > 0 && *outbytesleft > 0) {
|
||||
*((*outbuf)++) = *((*inbuf)++);
|
||||
(*inbytesleft)--;
|
||||
(*outbytesleft)--;
|
||||
}
|
||||
if (*inbytesleft > 0 && *outbytesleft <= 0)
|
||||
return (size_t) -1;
|
||||
return (size_t) 0;
|
||||
}
|
||||
ret = iconv(handle->descr, inbuf, inbytesleft, outbuf, outbytesleft);
|
||||
if (ret == (size_t) -1) {
|
||||
if (iso_iconv_debug)
|
||||
fprintf(stderr, "libisofs_DEBUG: iconv() failed: errno= %d %s\n",
|
||||
errno, strerror(errno));
|
||||
return (size_t) -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int iso_iconv_close(struct iso_iconv_handle *handle, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!(handle->status & 1)) {
|
||||
if (iso_iconv_debug)
|
||||
fprintf(stderr,
|
||||
"libisofs_DEBUG: iso_iconv_close(): iso_iconv_handle not in open state\n");
|
||||
return -1;
|
||||
}
|
||||
handle->status &= ~1;
|
||||
if (handle->status & 2)
|
||||
return 0;
|
||||
|
||||
ret = iconv_close(handle->descr);
|
||||
if (ret == -1) {
|
||||
if (iso_iconv_debug)
|
||||
fprintf(stderr,
|
||||
"libisofs_DEBUG: iconv_close() failed: errno= %d %s\n",
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int int_pow(int base, int power)
|
||||
{
|
||||
int result = 1;
|
||||
@ -40,46 +148,80 @@ int int_pow(int base, int power)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This static variable can override the locale's charset by its getter
|
||||
function which should be used whenever the local character set name
|
||||
is to be inquired. I.e. instead of calling nl_langinfo(CODESET) directly.
|
||||
If the variable is empty then it forwards nl_langinfo(CODESET).
|
||||
*/
|
||||
static char libisofs_local_charset[4096]= {""};
|
||||
|
||||
/* API function */
|
||||
int iso_set_local_charset(char *name, int flag)
|
||||
{
|
||||
if(strlen(name) >= sizeof(libisofs_local_charset))
|
||||
return(0);
|
||||
strcpy(libisofs_local_charset, name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* API function */
|
||||
char *iso_get_local_charset(int flag)
|
||||
{
|
||||
if(libisofs_local_charset[0])
|
||||
return libisofs_local_charset;
|
||||
return nl_langinfo(CODESET);
|
||||
}
|
||||
|
||||
int strconv(const char *str, const char *icharset, const char *ocharset,
|
||||
char **output)
|
||||
{
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
size_t n;
|
||||
iconv_t conv;
|
||||
char *out;
|
||||
struct iso_iconv_handle conv;
|
||||
int conv_ret;
|
||||
|
||||
char *out = NULL;
|
||||
char *src;
|
||||
char *ret;
|
||||
int retval;
|
||||
|
||||
inbytes = strlen(str);
|
||||
outbytes = (inbytes + 1) * MB_LEN_MAX;
|
||||
out = alloca(outbytes);
|
||||
out = calloc(outbytes, 1);
|
||||
if (out == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
retval = ISO_OUT_OF_MEM;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
conv = iconv_open(ocharset, icharset);
|
||||
if (conv == (iconv_t)(-1)) {
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
|
||||
if (conv_ret <= 0) {
|
||||
retval = ISO_CHARSET_CONV_ERROR;
|
||||
goto ex;
|
||||
}
|
||||
src = (char *)str;
|
||||
ret = (char *)out;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
if (n == -1) {
|
||||
/* error */
|
||||
iconv_close(conv);
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
iso_iconv_close(&conv, 0);
|
||||
retval = ISO_CHARSET_CONV_ERROR;
|
||||
goto ex;
|
||||
}
|
||||
*ret = '\0';
|
||||
iconv_close(conv);
|
||||
iso_iconv_close(&conv, 0);
|
||||
|
||||
*output = malloc(ret - out + 1);
|
||||
if (*output == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
retval = ISO_OUT_OF_MEM;
|
||||
goto ex;
|
||||
}
|
||||
memcpy(*output, out, ret - out + 1);
|
||||
return ISO_SUCCESS;
|
||||
retval = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (out != NULL)
|
||||
free(out);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int strnconv(const char *str, const char *icharset, const char *ocharset,
|
||||
@ -88,40 +230,48 @@ int strnconv(const char *str, const char *icharset, const char *ocharset,
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
size_t n;
|
||||
iconv_t conv;
|
||||
char *out;
|
||||
struct iso_iconv_handle conv;
|
||||
int conv_ret;
|
||||
char *out = NULL;
|
||||
char *src;
|
||||
char *ret;
|
||||
int retval;
|
||||
|
||||
inbytes = len;
|
||||
outbytes = (inbytes + 1) * MB_LEN_MAX;
|
||||
out = alloca(outbytes);
|
||||
out = calloc(outbytes, 1);
|
||||
if (out == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
retval = ISO_OUT_OF_MEM;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
conv = iconv_open(ocharset, icharset);
|
||||
if (conv == (iconv_t)(-1)) {
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
|
||||
if (conv_ret <= 0) {
|
||||
retval = ISO_CHARSET_CONV_ERROR;
|
||||
goto ex;
|
||||
}
|
||||
src = (char *)str;
|
||||
ret = (char *)out;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
if (n == -1) {
|
||||
/* error */
|
||||
iconv_close(conv);
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
iso_iconv_close(&conv, 0);
|
||||
retval = ISO_CHARSET_CONV_ERROR;
|
||||
goto ex;
|
||||
}
|
||||
*ret = '\0';
|
||||
iconv_close(conv);
|
||||
iso_iconv_close(&conv, 0);
|
||||
|
||||
*output = malloc(ret - out + 1);
|
||||
if (*output == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
retval = ISO_OUT_OF_MEM;
|
||||
goto ex;
|
||||
}
|
||||
memcpy(*output, out, ret - out + 1);
|
||||
return ISO_SUCCESS;
|
||||
retval = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (out != NULL)
|
||||
free(out);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,7 +284,12 @@ int strnconv(const char *str, const char *icharset, const char *ocharset,
|
||||
static
|
||||
int str2wchar(const char *icharset, const char *input, wchar_t **output)
|
||||
{
|
||||
iconv_t conv;
|
||||
struct iso_iconv_handle conv;
|
||||
int conv_ret;
|
||||
|
||||
/* That while loop smells like a potential show stopper */
|
||||
size_t loop_counter = 0, loop_limit = 3;
|
||||
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
char *ret;
|
||||
@ -146,12 +301,13 @@ int str2wchar(const char *icharset, const char *input, wchar_t **output)
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
conv = iconv_open("WCHAR_T", icharset);
|
||||
if (conv == (iconv_t)-1) {
|
||||
conv_ret = iso_iconv_open(&conv, "WCHAR_T", (char *) icharset, 0);
|
||||
if (conv_ret <= 0) {
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
}
|
||||
|
||||
inbytes = strlen(input);
|
||||
loop_limit = inbytes + 3;
|
||||
outbytes = (inbytes + 1) * sizeof(wchar_t);
|
||||
|
||||
/* we are sure that numchars <= inbytes */
|
||||
@ -162,14 +318,12 @@ int str2wchar(const char *icharset, const char *input, wchar_t **output)
|
||||
ret = (char *)wstr;
|
||||
src = (char *)input;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
while (n == -1) {
|
||||
|
||||
if (errno == E2BIG) {
|
||||
/* error, should never occur */
|
||||
iconv_close(conv);
|
||||
free(wstr);
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
goto conv_error;
|
||||
} else {
|
||||
wchar_t *wret;
|
||||
|
||||
@ -189,14 +343,23 @@ int str2wchar(const char *icharset, const char *input, wchar_t **output)
|
||||
|
||||
if (!inbytes)
|
||||
break;
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
|
||||
/* Just to appease my remorse about unclear loop ends */
|
||||
loop_counter++;
|
||||
if (loop_counter > loop_limit)
|
||||
goto conv_error;
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
}
|
||||
}
|
||||
iconv_close(conv);
|
||||
|
||||
iso_iconv_close(&conv, 0);
|
||||
*( (wchar_t *)ret )='\0';
|
||||
*output = wstr;
|
||||
return ISO_SUCCESS;
|
||||
|
||||
conv_error:;
|
||||
iso_iconv_close(&conv, 0);
|
||||
free(wstr);
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
}
|
||||
|
||||
int str2ascii(const char *icharset, const char *input, char **output)
|
||||
@ -206,12 +369,21 @@ int str2ascii(const char *icharset, const char *input, char **output)
|
||||
char *ret;
|
||||
char *ret_;
|
||||
char *src;
|
||||
iconv_t conv;
|
||||
struct iso_iconv_handle conv;
|
||||
int conv_ret;
|
||||
|
||||
/* That while loop smells like a potential show stopper */
|
||||
size_t loop_counter = 0, loop_limit = 3;
|
||||
|
||||
/* Fallback in case that iconv() is too demanding for system */
|
||||
unsigned char *cpt;
|
||||
|
||||
size_t numchars;
|
||||
size_t outbytes;
|
||||
size_t inbytes;
|
||||
size_t n;
|
||||
|
||||
|
||||
if (icharset == NULL || input == NULL || output == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
@ -222,12 +394,13 @@ int str2ascii(const char *icharset, const char *input, char **output)
|
||||
*/
|
||||
result = str2wchar(icharset, input, &wsrc_);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
goto fallback;
|
||||
}
|
||||
src = (char *)wsrc_;
|
||||
numchars = wcslen(wsrc_);
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
loop_limit = inbytes + 3;
|
||||
|
||||
ret_ = malloc(numchars + 1);
|
||||
if (ret_ == NULL) {
|
||||
@ -237,14 +410,14 @@ int str2ascii(const char *icharset, const char *input, char **output)
|
||||
ret = ret_;
|
||||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("ASCII", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1) {
|
||||
conv_ret = iso_iconv_open(&conv, "ASCII", "WCHAR_T", 0);
|
||||
if (conv_ret <= 0) {
|
||||
free(wsrc_);
|
||||
free(ret_);
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
while (n == -1) {
|
||||
/* The destination buffer is too small. Stops here. */
|
||||
if (errno == E2BIG)
|
||||
@ -274,16 +447,29 @@ int str2ascii(const char *icharset, const char *input, char **output)
|
||||
if (!inbytes)
|
||||
break;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
/* Just to appease my remorse about unclear loop ends */
|
||||
loop_counter++;
|
||||
if (loop_counter > loop_limit)
|
||||
break;
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
}
|
||||
|
||||
iconv_close(conv);
|
||||
|
||||
iso_iconv_close(&conv, 0);
|
||||
*ret='\0';
|
||||
free(wsrc_);
|
||||
|
||||
*output = ret_;
|
||||
return ISO_SUCCESS;
|
||||
|
||||
fallback:;
|
||||
/* Assume to have a single byte charset with ASCII as core.
|
||||
Anything suspicious will be mapped to '_'.
|
||||
*/
|
||||
*output = strdup(input);
|
||||
for (cpt = (unsigned char *) *output; *cpt; cpt++) {
|
||||
if (*cpt < 32 || *cpt > 126)
|
||||
*cpt = '_';
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
@ -318,7 +504,12 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
|
||||
char *src;
|
||||
char *ret;
|
||||
char *ret_;
|
||||
iconv_t conv;
|
||||
struct iso_iconv_handle conv;
|
||||
int conv_ret;
|
||||
|
||||
/* That while loop smells like a potential show stopper */
|
||||
size_t loop_counter = 0, loop_limit = 3;
|
||||
|
||||
size_t numchars;
|
||||
size_t outbytes;
|
||||
size_t inbytes;
|
||||
@ -340,6 +531,7 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
|
||||
numchars = wcslen(wsrc_);
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
loop_limit = inbytes + 3;
|
||||
|
||||
ret_ = malloc((numchars+1) * sizeof(uint16_t));
|
||||
if (ret_ == NULL) {
|
||||
@ -349,14 +541,14 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
|
||||
ret = ret_;
|
||||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("UCS-2BE", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1) {
|
||||
conv_ret = iso_iconv_open(&conv, "UCS-2BE", "WCHAR_T", 0);
|
||||
if (conv_ret <= 0) {
|
||||
free(wsrc_);
|
||||
free(ret_);
|
||||
return ISO_CHARSET_CONV_ERROR;
|
||||
}
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
while (n == -1) {
|
||||
/* The destination buffer is too small. Stops here. */
|
||||
if (errno == E2BIG)
|
||||
@ -386,10 +578,13 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
|
||||
if (!inbytes)
|
||||
break;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
/* Just to appease my remorse about unclear loop ends */
|
||||
loop_counter++;
|
||||
if (loop_counter > loop_limit)
|
||||
break;
|
||||
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
|
||||
}
|
||||
|
||||
iconv_close(conv);
|
||||
iso_iconv_close(&conv, 0);
|
||||
|
||||
/* close the ucs string */
|
||||
set_ucsbe((uint16_t*) ret, '\0');
|
||||
@ -602,12 +797,16 @@ char *iso_r_dirid(const char *src, int size, int relaxed)
|
||||
*/
|
||||
char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
|
||||
{
|
||||
char *dot;
|
||||
char *dot, *retval = NULL;
|
||||
int lname, lext, lnname, lnext, pos, i;
|
||||
char *dest = alloca(len + 1 + 1);
|
||||
char *dest = NULL;
|
||||
|
||||
dest = calloc(len + 1 + 1, 1);
|
||||
if (dest == NULL)
|
||||
goto ex;
|
||||
|
||||
if (src == NULL) {
|
||||
return NULL;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
dot = strrchr(src, '.');
|
||||
@ -632,7 +831,7 @@ char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
|
||||
}
|
||||
|
||||
if (lnname == 0 && lnext == 0) {
|
||||
return NULL;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
@ -688,7 +887,13 @@ char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
|
||||
}
|
||||
}
|
||||
dest[pos] = '\0';
|
||||
return strdup(dest);
|
||||
|
||||
retval = strdup(dest);
|
||||
|
||||
ex:;
|
||||
if (dest != NULL)
|
||||
free(dest);
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint16_t *iso_j_file_id(const uint16_t *src)
|
||||
@ -1207,8 +1412,9 @@ void strncpy_pad(char *dest, const char *src, size_t max)
|
||||
char *ucs2str(const char *buf, size_t len)
|
||||
{
|
||||
size_t outbytes, inbytes;
|
||||
char *str, *src, *out;
|
||||
iconv_t conv;
|
||||
char *str, *src, *out = NULL, *retval = NULL;
|
||||
struct iso_iconv_handle conv;
|
||||
int conv_ret;
|
||||
size_t n;
|
||||
|
||||
inbytes = len;
|
||||
@ -1216,30 +1422,34 @@ char *ucs2str(const char *buf, size_t len)
|
||||
outbytes = (inbytes+1) * MB_LEN_MAX;
|
||||
|
||||
/* ensure enought space */
|
||||
out = alloca(outbytes);
|
||||
out = calloc(outbytes, 1);
|
||||
|
||||
/* convert to local charset */
|
||||
setlocale(LC_CTYPE, "");
|
||||
conv = iconv_open(nl_langinfo(CODESET), "UCS-2BE");
|
||||
if (conv == (iconv_t)(-1)) {
|
||||
return NULL;
|
||||
conv_ret = iso_iconv_open(&conv, iso_get_local_charset(0), "UCS-2BE", 0);
|
||||
if (conv_ret <= 0) {
|
||||
goto ex;
|
||||
}
|
||||
src = (char *)buf;
|
||||
str = (char *)out;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &str, &outbytes);
|
||||
n = iso_iconv(&conv, &src, &inbytes, &str, &outbytes, 0);
|
||||
iso_iconv_close(&conv, 0);
|
||||
if (n == -1) {
|
||||
/* error */
|
||||
iconv_close(conv);
|
||||
return NULL;
|
||||
goto ex;
|
||||
}
|
||||
iconv_close(conv);
|
||||
*str = '\0';
|
||||
|
||||
/* remove trailing spaces */
|
||||
for (len = strlen(out) - 1; out[len] == ' ' && len > 0; --len)
|
||||
out[len] = '\0';
|
||||
return strdup(out);
|
||||
|
||||
retval = strdup(out);
|
||||
|
||||
ex:;
|
||||
if (out != NULL)
|
||||
free(out);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void iso_lib_version(int *major, int *minor, int *micro)
|
||||
@ -1262,3 +1472,11 @@ int iso_lib_is_compatible(int major, int minor, int micro)
|
||||
&& (cminor > minor
|
||||
|| (cminor == minor && cmicro >= micro)));
|
||||
}
|
||||
|
||||
int iso_init_locale(int flag)
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,6 +25,11 @@
|
||||
|
||||
int int_pow(int base, int power);
|
||||
|
||||
/**
|
||||
* Set up locale by LC_* environment variables.
|
||||
*/
|
||||
int iso_init_locale(int flag);
|
||||
|
||||
/**
|
||||
* Convert the charset encoding of a given string.
|
||||
*
|
||||
|
@ -198,7 +198,11 @@ int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item)
|
||||
}
|
||||
}
|
||||
|
||||
comp = tree->compare(q->data, data);
|
||||
if (q->data == data) {
|
||||
comp = 0;
|
||||
} else {
|
||||
comp = tree->compare(q->data, data);
|
||||
}
|
||||
|
||||
/* Stop if found */
|
||||
if (comp == 0) {
|
||||
|
633
test/test_node.c
633
test/test_node.c
@ -410,6 +410,7 @@ void test_iso_dir_get_node()
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_dir_get_children()
|
||||
{
|
||||
int result;
|
||||
@ -419,11 +420,13 @@ void test_iso_dir_get_children()
|
||||
|
||||
/* init dir with default values, not all field need to be initialized */
|
||||
dir = malloc(sizeof(IsoDir));
|
||||
dir->node.refcount = 1;
|
||||
dir->children = NULL;
|
||||
dir->nchildren = 0;
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->node.refcount, 2);
|
||||
|
||||
/* item should have no items */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
@ -436,6 +439,7 @@ void test_iso_dir_get_children()
|
||||
/* 1st node to be added */
|
||||
node1 = calloc(1, sizeof(IsoNode));
|
||||
node1->name = "Node1";
|
||||
node1->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
@ -461,6 +465,7 @@ void test_iso_dir_get_children()
|
||||
/* add another node */
|
||||
node2 = calloc(1, sizeof(IsoNode));
|
||||
node2->name = "A node to be added first";
|
||||
node2->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
@ -490,6 +495,7 @@ void test_iso_dir_get_children()
|
||||
/* addition of a 3rd node, to be inserted last */
|
||||
node3 = calloc(1, sizeof(IsoNode));
|
||||
node3->name = "This node will be inserted last";
|
||||
node3->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node3, 0);
|
||||
CU_ASSERT_EQUAL(result, 3);
|
||||
|
||||
@ -520,13 +526,446 @@ void test_iso_dir_get_children()
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
CU_ASSERT_EQUAL(dir->node.refcount, 1);
|
||||
|
||||
/* assert correct refcount */
|
||||
CU_ASSERT_EQUAL(node1->refcount, 1);
|
||||
free(node1);
|
||||
CU_ASSERT_EQUAL(node2->refcount, 1);
|
||||
free(node2);
|
||||
CU_ASSERT_EQUAL(node3->refcount, 1);
|
||||
free(node3);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_dir_iter_take()
|
||||
{
|
||||
int result;
|
||||
IsoDirIter *iter;
|
||||
IsoDir *dir;
|
||||
IsoNode *node, *node1, *node2, *node3;
|
||||
|
||||
/* init dir with default values, not all field need to be initialized */
|
||||
dir = malloc(sizeof(IsoDir));
|
||||
dir->node.refcount = 1;
|
||||
dir->children = NULL;
|
||||
dir->nchildren = 0;
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->node.refcount, 2);
|
||||
|
||||
/* remove on empty dir! */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* 1st node to be added */
|
||||
node1 = calloc(1, sizeof(IsoNode));
|
||||
node1->name = "Node1";
|
||||
node1->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
/* test iteration again */
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* remove before iso_dir_iter_next() */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
|
||||
/* this should remove the child */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 0);
|
||||
CU_ASSERT_PTR_NULL(dir->children);
|
||||
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* add two node */
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
node2 = calloc(1, sizeof(IsoNode));
|
||||
node2->name = "A node to be added first";
|
||||
node2->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* remove before iso_dir_iter_next() */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
/* iter should have two items... */
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
/* remove node 2 */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(dir->children, node1);
|
||||
|
||||
/* we can't take two times without next()!! */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
/* next should still work */
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||
|
||||
/* ...and no more */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* now remove only last child */
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||
|
||||
/* take last child */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* Ok, now another situation. Modification of dir during iteration */
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
/* returned dir is node2, it should be the node taken next, but
|
||||
* let's insert a node after node2 and before node1 */
|
||||
node3 = calloc(1, sizeof(IsoNode));
|
||||
node3->name = "A node to be added second";
|
||||
node3->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node3, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 3);
|
||||
|
||||
/* is the node 2 the removed one? */
|
||||
result = iso_dir_iter_take(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 2);
|
||||
CU_ASSERT_PTR_EQUAL(dir->children, node3);
|
||||
CU_ASSERT_PTR_EQUAL(node3->next, node1);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
CU_ASSERT_EQUAL(dir->node.refcount, 1);
|
||||
|
||||
/* assert correct refcount */
|
||||
CU_ASSERT_EQUAL(node1->refcount, 1);
|
||||
free(node1);
|
||||
CU_ASSERT_EQUAL(node2->refcount, 1);
|
||||
free(node2);
|
||||
CU_ASSERT_EQUAL(node3->refcount, 1);
|
||||
free(node3);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_dir_iter_remove()
|
||||
{
|
||||
int result;
|
||||
IsoDirIter *iter;
|
||||
IsoDir *dir;
|
||||
IsoNode *node, *node1, *node2, *node3;
|
||||
|
||||
/* init dir with default values, not all field need to be initialized */
|
||||
dir = malloc(sizeof(IsoDir));
|
||||
dir->node.refcount = 1;
|
||||
dir->children = NULL;
|
||||
dir->nchildren = 0;
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* remove on empty dir! */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* 1st node to be added */
|
||||
node1 = calloc(1, sizeof(IsoNode));
|
||||
node1->name = "Node1";
|
||||
node1->refcount = 2;
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
/* test iteration again */
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* remove before iso_dir_iter_next() */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
|
||||
/* this should remove the child */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 0);
|
||||
CU_ASSERT_PTR_NULL(dir->children);
|
||||
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* add two node */
|
||||
node1->refcount++; /* was removed above */
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
node2 = calloc(1, sizeof(IsoNode));
|
||||
node2->name = "A node to be added first";
|
||||
node2->refcount = 2;
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* remove before iso_dir_iter_next() */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_TRUE(result < 0); /* should fail */
|
||||
|
||||
/* iter should have two items... */
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
/* remove node 2 */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(dir->children, node1);
|
||||
|
||||
/* next should still work */
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||
|
||||
/* ...and no more */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* now remove only last child */
|
||||
node2->refcount++; /* was removed above */
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||
|
||||
/* take last child */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* Ok, now another situation. Modification of dir during iteration */
|
||||
node1->refcount++;
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
/* returned dir is node2, it should be the node taken next, but
|
||||
* let's insert a node after node2 and before node1 */
|
||||
node3 = calloc(1, sizeof(IsoNode));
|
||||
node3->name = "A node to be added second";
|
||||
node3->refcount = 2;
|
||||
result = iso_dir_add_node(dir, node3, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 3);
|
||||
|
||||
/* is the node 2 the removed one? */
|
||||
result = iso_dir_iter_remove(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 2);
|
||||
CU_ASSERT_PTR_EQUAL(dir->children, node3);
|
||||
CU_ASSERT_PTR_EQUAL(node3->next, node1);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* assert correct refcount */
|
||||
CU_ASSERT_EQUAL(node1->refcount, 2); /* node1 is not removed */
|
||||
free(node1);
|
||||
CU_ASSERT_EQUAL(node2->refcount, 1);
|
||||
free(node2);
|
||||
CU_ASSERT_EQUAL(node3->refcount, 2); /* node3 is not removed */
|
||||
free(node3);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_dir_iter_when_external_take()
|
||||
{
|
||||
int result;
|
||||
IsoDirIter *iter;
|
||||
IsoDir *dir;
|
||||
IsoNode *node, *node1, *node2;
|
||||
|
||||
/* init dir with default values, not all field need to be initialized */
|
||||
dir = malloc(sizeof(IsoDir));
|
||||
dir->node.refcount = 1;
|
||||
dir->children = NULL;
|
||||
dir->nchildren = 0;
|
||||
|
||||
/* 1st node to be added */
|
||||
node1 = calloc(1, sizeof(IsoNode));
|
||||
node1->name = "Node1";
|
||||
node1->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
/* test iteration again */
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* take node */
|
||||
result = iso_node_take(node1);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* iter should reflect changes */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* add two nodes */
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||
|
||||
node2 = calloc(1, sizeof(IsoNode));
|
||||
node2->name = "A node to be added first";
|
||||
node2->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* iter should have two items... */
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
/* remove node 1 asynchronously */
|
||||
result = iso_node_take(node1);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* iter should reflect changes */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* now remove iter has itered */
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
CU_ASSERT_EQUAL(dir->nchildren, 2);
|
||||
|
||||
result = iso_dir_get_children(dir, &iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||
|
||||
/* remove node 2 asynchronously */
|
||||
result = iso_node_take(node2);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* iter should reflect changes */
|
||||
result = iso_dir_iter_has_next(iter);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
result = iso_dir_iter_next(iter, &node);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||
|
||||
iso_dir_iter_free(iter);
|
||||
|
||||
/* assert correct refcount */
|
||||
CU_ASSERT_EQUAL(node1->refcount, 1);
|
||||
free(node1);
|
||||
CU_ASSERT_EQUAL(node2->refcount, 1);
|
||||
free(node2);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_node_take()
|
||||
{
|
||||
int result;
|
||||
@ -541,6 +980,7 @@ void test_iso_node_take()
|
||||
/* 1st node to be added */
|
||||
node1 = calloc(1, sizeof(IsoNode));
|
||||
node1->name = "Node1";
|
||||
node1->refcount = 1;
|
||||
|
||||
/* addition of node to an empty dir */
|
||||
result = iso_dir_add_node(dir, node1, 0);
|
||||
@ -561,6 +1001,7 @@ void test_iso_node_take()
|
||||
/* addition of a 2nd node, to be inserted before */
|
||||
node2 = calloc(1, sizeof(IsoNode));
|
||||
node2->name = "A node to be added first";
|
||||
node2->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node2, 0);
|
||||
CU_ASSERT_EQUAL(result, 2);
|
||||
|
||||
@ -595,6 +1036,7 @@ void test_iso_node_take()
|
||||
/* ...and a 3rd child, to be inserted last */
|
||||
node3 = calloc(1, sizeof(IsoNode));
|
||||
node3->name = "This node will be inserted last";
|
||||
node3->refcount = 1;
|
||||
result = iso_dir_add_node(dir, node3, 0);
|
||||
CU_ASSERT_EQUAL(result, 3);
|
||||
|
||||
@ -609,9 +1051,13 @@ void test_iso_node_take()
|
||||
CU_ASSERT_PTR_EQUAL(node3->parent, dir);
|
||||
CU_ASSERT_PTR_NULL(node1->next);
|
||||
CU_ASSERT_PTR_NULL(node1->parent);
|
||||
|
||||
|
||||
/* assert correct refcount */
|
||||
CU_ASSERT_EQUAL(node1->refcount, 1);
|
||||
free(node1);
|
||||
CU_ASSERT_EQUAL(node2->refcount, 1);
|
||||
free(node2);
|
||||
CU_ASSERT_EQUAL(node3->refcount, 1);
|
||||
free(node3);
|
||||
free(dir);
|
||||
}
|
||||
@ -668,6 +1114,183 @@ void test_iso_node_set_name()
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static
|
||||
int xinfo_a(void *data, int flag) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int xinfo_b(void *data, int flag) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_node_add_xinfo()
|
||||
{
|
||||
int result;
|
||||
IsoNode *node;
|
||||
|
||||
/* cretae a node */
|
||||
node = calloc(1, sizeof(IsoNode));
|
||||
|
||||
/* add xinfo data */
|
||||
result = iso_node_add_xinfo(node, xinfo_a, NULL);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* we can't add again the same xinfo type */
|
||||
result = iso_node_add_xinfo(node, xinfo_a, &result);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
result = iso_node_add_xinfo(node, xinfo_b, NULL);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
free(node->xinfo->next);
|
||||
free(node->xinfo);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_node_get_xinfo()
|
||||
{
|
||||
int result;
|
||||
IsoNode *node;
|
||||
char *one_data = "my data";
|
||||
char *another_data = "my data 2";
|
||||
void *data;
|
||||
|
||||
/* cretae a node */
|
||||
node = calloc(1, sizeof(IsoNode));
|
||||
|
||||
/* at the beginning we have no data */
|
||||
result = iso_node_get_xinfo(node, xinfo_b, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* add xinfo data */
|
||||
result = iso_node_add_xinfo(node, xinfo_a, one_data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* we get the correct data */
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
/* we can't add again the same xinfo type */
|
||||
result = iso_node_add_xinfo(node, xinfo_a, &result);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* we get the correct data again */
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
/* xinfo_b has no data */
|
||||
result = iso_node_get_xinfo(node, xinfo_b, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* add another xinfo */
|
||||
result = iso_node_add_xinfo(node, xinfo_b, another_data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* test both data is returned propertly */
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
result = iso_node_get_xinfo(node, xinfo_b, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, another_data);
|
||||
|
||||
free(node->xinfo->next);
|
||||
free(node->xinfo);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static
|
||||
void test_iso_node_remove_xinfo()
|
||||
{
|
||||
int result;
|
||||
IsoNode *node;
|
||||
char *one_data = "my data";
|
||||
char *another_data = "my data 2";
|
||||
void *data;
|
||||
|
||||
/* cretae a node */
|
||||
node = calloc(1, sizeof(IsoNode));
|
||||
|
||||
/* try to remove inexistent data */
|
||||
result = iso_node_remove_xinfo(node, xinfo_b);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
result = iso_node_remove_xinfo(node, xinfo_a);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* add xinfo data */
|
||||
result = iso_node_add_xinfo(node, xinfo_a, one_data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
/* remove it */
|
||||
result = iso_node_remove_xinfo(node, xinfo_b);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
result = iso_node_remove_xinfo(node, xinfo_a);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* add again the same xinfo type */
|
||||
result = iso_node_add_xinfo(node, xinfo_a, one_data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* we get the correct data again */
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
/* add another xinfo */
|
||||
result = iso_node_add_xinfo(node, xinfo_b, another_data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* test both data is returned propertly */
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
result = iso_node_get_xinfo(node, xinfo_b, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, another_data);
|
||||
|
||||
/* remove b */
|
||||
result = iso_node_remove_xinfo(node, xinfo_b);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
/* only a can be get */
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
CU_ASSERT_PTR_EQUAL(data, one_data);
|
||||
|
||||
result = iso_node_get_xinfo(node, xinfo_b, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* try to remove b again */
|
||||
result = iso_node_remove_xinfo(node, xinfo_b);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
/* remove a */
|
||||
result = iso_node_remove_xinfo(node, xinfo_a);
|
||||
CU_ASSERT_EQUAL(result, 1);
|
||||
|
||||
result = iso_node_get_xinfo(node, xinfo_a, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
result = iso_node_get_xinfo(node, xinfo_b, &data);
|
||||
CU_ASSERT_EQUAL(result, 0);
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
void add_node_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL);
|
||||
@ -685,6 +1308,12 @@ void add_node_suite()
|
||||
CU_add_test(pSuite, "iso_dir_add_node()", test_iso_dir_add_node);
|
||||
CU_add_test(pSuite, "iso_dir_get_node()", test_iso_dir_get_node);
|
||||
CU_add_test(pSuite, "iso_dir_get_children()", test_iso_dir_get_children);
|
||||
CU_add_test(pSuite, "iso_dir_iter_take()", test_iso_dir_iter_take);
|
||||
CU_add_test(pSuite, "iso_dir_iter_remove()", test_iso_dir_iter_remove);
|
||||
CU_add_test(pSuite, "iso_node_take()", test_iso_node_take);
|
||||
CU_add_test(pSuite, "iso_node_take() during iteration", test_iso_dir_iter_when_external_take);
|
||||
CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name);
|
||||
CU_add_test(pSuite, "iso_node_add_xinfo()", test_iso_node_add_xinfo);
|
||||
CU_add_test(pSuite, "iso_node_get_xinfo()", test_iso_node_get_xinfo);
|
||||
CU_add_test(pSuite, "iso_node_remove_xinfo()", test_iso_node_remove_xinfo);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Unit test for util.h
|
||||
*
|
||||
*
|
||||
* This test utiliy functions
|
||||
*/
|
||||
#include "test.h"
|
||||
@ -16,51 +16,51 @@ static void test_rrip_calc_len_file()
|
||||
Ecma119Node *node;
|
||||
Ecma119Image t;
|
||||
size_t sua_len = 0, ce_len = 0;
|
||||
|
||||
|
||||
memset(&t, 0, sizeof(Ecma119Image));
|
||||
t.input_charset = "UTF-8";
|
||||
t.output_charset = "UTF-8";
|
||||
|
||||
|
||||
file = malloc(sizeof(IsoFile));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(file);
|
||||
file->msblock = 0;
|
||||
file->from_old_session = 0;
|
||||
file->sort_weight = 0;
|
||||
file->stream = NULL; /* it is not needed here */
|
||||
file->node.type = LIBISO_FILE;
|
||||
|
||||
|
||||
node = malloc(sizeof(Ecma119Node));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(node);
|
||||
node->node = (IsoNode*)file;
|
||||
node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
|
||||
node->info.file = NULL; /* it is not needed here */
|
||||
node->info.file = NULL; /* it is not needed here */
|
||||
node->type = ECMA119_FILE;
|
||||
|
||||
|
||||
/* Case 1. Name fit in System Use field */
|
||||
file->node.name = "a small name.txt";
|
||||
node->iso_name = "A_SMALL_.TXT";
|
||||
|
||||
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 0);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1);
|
||||
|
||||
|
||||
/* Case 2. Name fits exactly */
|
||||
file->node.name = "a big name, with 133 characters, that it is the max "
|
||||
"that fits in System Use field of the directory record "
|
||||
"PADPADPADADPADPADPADPAD.txt";
|
||||
node->iso_name = "A_BIG_NA.TXT";
|
||||
|
||||
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 0);
|
||||
/* note that 254 is the max length of a directory record, as it needs to
|
||||
* be an even number */
|
||||
CU_ASSERT_EQUAL(sua_len, 254 - 46);
|
||||
|
||||
|
||||
/* case 3. A name just 1 character too big to fit in SUA */
|
||||
file->node.name = "a big name, with 133 characters, that it is the max "
|
||||
"that fits in System Use field of the directory record "
|
||||
"PADPADPADADPADPADPADPAD1.txt";
|
||||
node->iso_name = "A_BIG_NA.TXT";
|
||||
|
||||
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
/* 28 (the chars moved to include the CE entry) + 5 (header of NM in CE) +
|
||||
* 1 (the char that originally didn't fit) */
|
||||
@ -68,21 +68,21 @@ static void test_rrip_calc_len_file()
|
||||
/* note that 254 is the max length of a directory record, as it needs to
|
||||
* be an even number */
|
||||
CU_ASSERT_EQUAL(sua_len, 254 - 46);
|
||||
|
||||
|
||||
/* case 4. A 255 characters name */
|
||||
file->node.name = "a big name, with 255 characters, that it is the max "
|
||||
"that a POSIX filename can have. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
|
||||
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
|
||||
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP";
|
||||
node->iso_name = "A_BIG_NA.TXT";
|
||||
|
||||
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
/* 150 + 5 (header + characters that don't fit in sua) */
|
||||
CU_ASSERT_EQUAL(ce_len, 150 + 5);
|
||||
/* note that 254 is the max length of a directory record, as it needs to
|
||||
* be an even number */
|
||||
CU_ASSERT_EQUAL(sua_len, 254 - 46);
|
||||
|
||||
|
||||
free(node);
|
||||
free(file);
|
||||
}
|
||||
@ -93,31 +93,31 @@ static void test_rrip_calc_len_symlink()
|
||||
Ecma119Node *node;
|
||||
Ecma119Image t;
|
||||
size_t sua_len = 0, ce_len = 0;
|
||||
|
||||
|
||||
memset(&t, 0, sizeof(Ecma119Image));
|
||||
t.input_charset = "UTF-8";
|
||||
t.output_charset = "UTF-8";
|
||||
|
||||
|
||||
link = malloc(sizeof(IsoSymlink));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(link);
|
||||
link->node.type = LIBISO_SYMLINK;
|
||||
|
||||
|
||||
node = malloc(sizeof(Ecma119Node));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(node);
|
||||
node->node = (IsoNode*)link;
|
||||
node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
|
||||
node->type = ECMA119_SYMLINK;
|
||||
|
||||
|
||||
/* Case 1. Name and dest fit in System Use field */
|
||||
link->node.name = "a small name.txt";
|
||||
link->dest = "/three/components";
|
||||
node->iso_name = "A_SMALL_.TXT";
|
||||
|
||||
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 0);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1 +
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1 +
|
||||
(5 + 2 + (2+5) + (2+10)) );
|
||||
|
||||
|
||||
/* case 2. name + dest fits exactly */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
"that fits in the SU.txt";
|
||||
@ -136,7 +136,7 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 60);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
|
||||
|
||||
|
||||
/* 3.b extra byte in name */
|
||||
link->node.name = "this name will have 75 characters as it is the max "
|
||||
"that fits in the SUx.txt";
|
||||
@ -145,10 +145,10 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 59);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 75) + (5 + 3*7) + 28);
|
||||
|
||||
/* case 4. name seems to fit, but SL no, and when CE is added NM
|
||||
|
||||
/* case 4. name seems to fit, but SL no, and when CE is added NM
|
||||
* doesn't fit too */
|
||||
/* 4.a it just fits */
|
||||
/* 4.a it just fits */
|
||||
link->node.name = "this name will have 105 characters as it is just the "
|
||||
"max that fits in the SU once we add the CE entry.txt";
|
||||
link->dest = "./and/../a/./big/destination/with/10/components";
|
||||
@ -156,8 +156,8 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 59);
|
||||
CU_ASSERT_EQUAL(sua_len, 254 - 46);
|
||||
|
||||
/* 4.b it just fits, the the component ends in '/' */
|
||||
|
||||
/* 4.b it just fits, the the component ends in '/' */
|
||||
link->node.name = "this name will have 105 characters as it is just the "
|
||||
"max that fits in the SU once we add the CE entry.txt";
|
||||
link->dest = "./and/../a/./big/destination/with/10/components/";
|
||||
@ -165,8 +165,8 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 59);
|
||||
CU_ASSERT_EQUAL(sua_len, 254 - 46);
|
||||
|
||||
/* 4.c extra char in name, that forces it to be divided */
|
||||
|
||||
/* 4.c extra char in name, that forces it to be divided */
|
||||
link->node.name = "this name will have 105 characters as it is just the "
|
||||
"max that fits in the SU once we add the CE entryc.txt";
|
||||
link->dest = "./and/../a/./big/destination/with/10/components";
|
||||
@ -174,7 +174,7 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 59 + 6);
|
||||
CU_ASSERT_EQUAL(sua_len, 254 - 46);
|
||||
|
||||
|
||||
/* 5 max destination length to fit in a single SL entry (250) */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
"that fits in the SU.txt";
|
||||
@ -186,7 +186,7 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 255);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
|
||||
|
||||
|
||||
/* 6 min destination length to need two SL entries (251) */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
"that fits in the SU.txt";
|
||||
@ -198,8 +198,8 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 261);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
|
||||
|
||||
/* 7 destination with big component that need to be splited
|
||||
|
||||
/* 7 destination with big component that need to be splited
|
||||
* in two SL entries */
|
||||
/* 7.a just fits in one */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
@ -213,7 +213,7 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 255);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
|
||||
|
||||
|
||||
/* 7.b doesn't fits by one character */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
"that fits in the SU.txt";
|
||||
@ -226,7 +226,7 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 255 + (5+2+1));
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
|
||||
|
||||
|
||||
/* 7.c several components before, such as it has just the right len
|
||||
* to fit in the SL entry plus another one */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
@ -244,8 +244,8 @@ static void test_rrip_calc_len_symlink()
|
||||
sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
|
||||
CU_ASSERT_EQUAL(ce_len, 255 + 255);
|
||||
CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
|
||||
|
||||
/*
|
||||
|
||||
/*
|
||||
* 7.d several components before, and then a big component that doesn't
|
||||
* fit in the 1st SL entry and another one. That case needs a 3rd SL entry,
|
||||
* but instead of divide the component in 2 entries, we put it in 2,
|
||||
@ -275,12 +275,12 @@ static
|
||||
void susp_info_free(struct susp_info *susp)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
||||
for (i = 0; i < susp->n_susp_fields; ++i) {
|
||||
free(susp->susp_fields[i]);
|
||||
}
|
||||
free(susp->susp_fields);
|
||||
|
||||
|
||||
for (i = 0; i < susp->n_ce_susp_fields; ++i) {
|
||||
free(susp->ce_susp_fields[i]);
|
||||
}
|
||||
@ -296,14 +296,14 @@ void test_rrip_get_susp_fields_file()
|
||||
struct susp_info susp;
|
||||
Ecma119Image t;
|
||||
uint8_t *entry;
|
||||
|
||||
|
||||
memset(&t, 0, sizeof(Ecma119Image));
|
||||
t.input_charset = "UTF-8";
|
||||
t.output_charset = "UTF-8";
|
||||
|
||||
|
||||
file = malloc(sizeof(IsoFile));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(file);
|
||||
file->msblock = 0;
|
||||
file->from_old_session = 0;
|
||||
file->sort_weight = 0;
|
||||
file->stream = NULL; /* it is not needed here */
|
||||
file->node.type = LIBISO_FILE;
|
||||
@ -313,20 +313,20 @@ void test_rrip_get_susp_fields_file()
|
||||
file->node.mtime = 675757578;
|
||||
file->node.atime = 546462546;
|
||||
file->node.ctime = 323245342;
|
||||
|
||||
|
||||
node = malloc(sizeof(Ecma119Node));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(node);
|
||||
node->node = (IsoNode*)file;
|
||||
node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
|
||||
node->info.file = NULL; /* it is not needed here */
|
||||
node->info.file = NULL; /* it is not needed here */
|
||||
node->type = ECMA119_FILE;
|
||||
node->nlink = 1;
|
||||
node->ino = 0x03447892;
|
||||
|
||||
|
||||
/* Case 1. Name fit in System Use field */
|
||||
file->node.name = "a small name.txt";
|
||||
node->iso_name = "A_SMALL_.TXT";
|
||||
|
||||
|
||||
memset(&susp, 0, sizeof(struct susp_info));
|
||||
ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
@ -334,7 +334,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
|
||||
CU_ASSERT_EQUAL(susp.n_susp_fields, 3); /* PX + TF + NM */
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1);
|
||||
|
||||
|
||||
/* PX is the first entry */
|
||||
entry = susp.susp_fields[0];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -352,7 +352,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 32, 4), 654);
|
||||
CU_ASSERT_EQUAL(iso_read_lsb(entry + 36, 4), 0x03447892);
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 40, 4), 0x03447892);
|
||||
|
||||
|
||||
/* TF is the second entry */
|
||||
entry = susp.susp_fields[1];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -364,7 +364,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 5), 675757578);
|
||||
CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 12), 546462546);
|
||||
CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 19), 323245342);
|
||||
|
||||
|
||||
/* NM is the last entry */
|
||||
entry = susp.susp_fields[2];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -374,24 +374,24 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 5, "a small name.txt", 16);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
/* Case 2. Name fits exactly */
|
||||
file->node.name = "a big name, with 133 characters, that it is the max "
|
||||
"that fits in System Use field of the directory record "
|
||||
"PADPADPADADPADPADPADPAD.txt";
|
||||
node->iso_name = "A_BIG_NA.TXT";
|
||||
|
||||
|
||||
memset(&susp, 0, sizeof(struct susp_info));
|
||||
ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
CU_ASSERT_EQUAL(susp.ce_len, 0);
|
||||
CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
|
||||
|
||||
|
||||
CU_ASSERT_EQUAL(susp.n_susp_fields, 3); /* PX + TF + NM */
|
||||
|
||||
|
||||
/* NM is the last entry */
|
||||
entry = susp.susp_fields[2];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -403,24 +403,24 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 133 characters, that "
|
||||
"it is the max that fits in System Use field of the "
|
||||
"directory record PADPADPADADPADPADPADPAD.txt", 133);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
/* case 3. A name just 1 character too big to fit in SUA */
|
||||
file->node.name = "a big name, with 133 characters, that it is the max "
|
||||
"that fits in System Use field of the directory record "
|
||||
"PADPADPADADPADPADPADPAD1.txt";
|
||||
node->iso_name = "A_BIG_NA.TXT";
|
||||
|
||||
|
||||
memset(&susp, 0, sizeof(struct susp_info));
|
||||
ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
CU_ASSERT_EQUAL(susp.ce_len, 28 + 5 + 1);
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
|
||||
|
||||
|
||||
CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
|
||||
CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* NM */
|
||||
|
||||
|
||||
/* test NM entry */
|
||||
entry = susp.susp_fields[2];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -432,7 +432,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 133 characters, that "
|
||||
"it is the max that fits in System Use field of the "
|
||||
"directory record", 105);
|
||||
|
||||
|
||||
/* and CE entry */
|
||||
entry = susp.susp_fields[3];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -446,7 +446,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
|
||||
CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 34);
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 34);
|
||||
|
||||
|
||||
/* and check Continuation area */
|
||||
entry = susp.ce_susp_fields[0];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -456,16 +456,16 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 5, " PADPADPADADPADPADPADPAD1.txt", 29);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
/* case 4. A 255 characters name */
|
||||
file->node.name = "a big name, with 255 characters, that it is the max "
|
||||
"that a POSIX filename can have. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
|
||||
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
|
||||
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP";
|
||||
node->iso_name = "A_BIG_NA.TXT";
|
||||
|
||||
|
||||
memset(&susp, 0, sizeof(struct susp_info));
|
||||
susp.ce_block = 12;
|
||||
susp.ce_len = 456;
|
||||
@ -473,7 +473,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
CU_ASSERT_EQUAL(susp.ce_len, 150 + 5 + 456);
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
|
||||
|
||||
|
||||
CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
|
||||
CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* NM */
|
||||
|
||||
@ -488,7 +488,7 @@ void test_rrip_get_susp_fields_file()
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 255 characters, that "
|
||||
"it is the max that a POSIX filename can have. PPP"
|
||||
"PPPPPPPPPPPPPPPPPP", 105);
|
||||
|
||||
|
||||
/* and CE entry */
|
||||
entry = susp.susp_fields[3];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -517,9 +517,9 @@ void test_rrip_get_susp_fields_file()
|
||||
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
|
||||
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
|
||||
"PPPPPPPPPPPPPP", 150);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
free(node);
|
||||
free(file);
|
||||
}
|
||||
@ -532,11 +532,11 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
int ret;
|
||||
struct susp_info susp;
|
||||
uint8_t *entry;
|
||||
|
||||
|
||||
memset(&t, 0, sizeof(Ecma119Image));
|
||||
t.input_charset = "UTF-8";
|
||||
t.output_charset = "UTF-8";
|
||||
|
||||
|
||||
link = malloc(sizeof(IsoSymlink));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(link);
|
||||
link->node.type = LIBISO_SYMLINK;
|
||||
@ -546,7 +546,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
link->node.mtime = 675757578;
|
||||
link->node.atime = 546462546;
|
||||
link->node.ctime = 323245342;
|
||||
|
||||
|
||||
node = malloc(sizeof(Ecma119Node));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(node);
|
||||
node->node = (IsoNode*)link;
|
||||
@ -554,21 +554,21 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
node->type = ECMA119_SYMLINK;
|
||||
node->nlink = 1;
|
||||
node->ino = 0x03447892;
|
||||
|
||||
|
||||
/* Case 1. Name and dest fit in System Use field */
|
||||
link->node.name = "a small name.txt";
|
||||
link->dest = "/three/components";
|
||||
node->iso_name = "A_SMALL_.TXT";
|
||||
|
||||
|
||||
memset(&susp, 0, sizeof(struct susp_info));
|
||||
ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
CU_ASSERT_EQUAL(susp.ce_len, 0);
|
||||
CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
|
||||
CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + SL */
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1
|
||||
+ (5 + 2 + (2 + 5) + (2 + 10)));
|
||||
|
||||
|
||||
/* PX is the first entry */
|
||||
entry = susp.susp_fields[0];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -586,7 +586,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 32, 4), 654);
|
||||
CU_ASSERT_EQUAL(iso_read_lsb(entry + 36, 4), 0x03447892);
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 40, 4), 0x03447892);
|
||||
|
||||
|
||||
/* TF is the second entry */
|
||||
entry = susp.susp_fields[1];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -598,7 +598,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 5), 675757578);
|
||||
CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 12), 546462546);
|
||||
CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 19), 323245342);
|
||||
|
||||
|
||||
/* NM is the 3rd entry */
|
||||
entry = susp.susp_fields[2];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -617,7 +617,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 5 + 2 + (2 + 5) + (2 + 10));
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x8); /* root */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -626,14 +626,14 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 5);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "three", 5);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 10);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 16, "components", 10);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
/* case 2. name + dest fits exactly */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
"that fits in the SU.txt";
|
||||
@ -647,7 +647,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
|
||||
CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + SL */
|
||||
CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
|
||||
|
||||
|
||||
/* NM is the 3rd entry */
|
||||
entry = susp.susp_fields[2];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -667,7 +667,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 5 + 2 + 5 + 2 + 3 + 2 + 5 + 13 + 6 + 4 + 12);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -676,7 +676,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -685,7 +685,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -716,7 +716,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
/* case 3. name fits, dest is one byte larger to fit */
|
||||
/* 3.a extra byte in dest */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
@ -738,7 +738,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[0], 'P');
|
||||
CU_ASSERT_EQUAL(entry[1], 'X');
|
||||
CU_ASSERT_EQUAL(entry[2], 44);
|
||||
|
||||
|
||||
/* TF is the second entry */
|
||||
entry = susp.susp_fields[1];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -770,7 +770,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
|
||||
CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 60);
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 60);
|
||||
|
||||
|
||||
|
||||
/* finally, SL is the single entry in CE */
|
||||
entry = susp.ce_susp_fields[0];
|
||||
@ -780,7 +780,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 60);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -789,7 +789,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -798,7 +798,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -827,7 +827,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[47], 0);
|
||||
CU_ASSERT_EQUAL(entry[48], 11);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 49, "componentsk", 11);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
/* 3.b extra byte in name */
|
||||
@ -868,7 +868,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
|
||||
CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 59);
|
||||
CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 59);
|
||||
|
||||
|
||||
|
||||
/* finally, SL is the single entry in CE */
|
||||
entry = susp.ce_susp_fields[0];
|
||||
@ -878,7 +878,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 59);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -887,7 +887,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -896,7 +896,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -925,12 +925,12 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[47], 0);
|
||||
CU_ASSERT_EQUAL(entry[48], 10);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
/* case 4. name seems to fit, but SL no, and when CE is added NM
|
||||
|
||||
/* case 4. name seems to fit, but SL no, and when CE is added NM
|
||||
* doesn't fit too */
|
||||
/* 4.a it just fits */
|
||||
/* 4.a it just fits */
|
||||
link->node.name = "this name will have 105 characters as it is just the "
|
||||
"max that fits in the SU once we add the CE entry.txt";
|
||||
link->dest = "./and/../a/./big/destination/with/10/components";
|
||||
@ -978,7 +978,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 59);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -987,7 +987,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -996,7 +996,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -1025,10 +1025,10 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[47], 0);
|
||||
CU_ASSERT_EQUAL(entry[48], 10);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
/* 4.b it just fits, the the component ends in '/' */
|
||||
|
||||
/* 4.b it just fits, the the component ends in '/' */
|
||||
link->node.name = "this name will have 105 characters as it is just the "
|
||||
"max that fits in the SU once we add the CE entry.txt";
|
||||
link->dest = "./and/../a/./big/destination/with/10/components/";
|
||||
@ -1076,7 +1076,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 59);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -1085,7 +1085,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -1094,7 +1094,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -1123,10 +1123,10 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[47], 0);
|
||||
CU_ASSERT_EQUAL(entry[48], 10);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
/* 4.c extra char in name, that forces it to be divided */
|
||||
|
||||
/* 4.c extra char in name, that forces it to be divided */
|
||||
link->node.name = "this name will have 106 characters as it is just the "
|
||||
"max that fits in the SU once we add the CE entryc.txt";
|
||||
link->dest = "./and/../a/./big/destination/with/10/components";
|
||||
@ -1175,7 +1175,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
CU_ASSERT_EQUAL(entry[5], 't');
|
||||
|
||||
|
||||
/* finally, SL is the single entry in CE */
|
||||
entry = susp.ce_susp_fields[1];
|
||||
CU_ASSERT_PTR_NOT_NULL(entry);
|
||||
@ -1184,7 +1184,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 59);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -1193,7 +1193,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -1202,7 +1202,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -1231,9 +1231,9 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[47], 0);
|
||||
CU_ASSERT_EQUAL(entry[48], 10);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
|
||||
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
/* 5 max destination length to fit in a single SL entry (250) */
|
||||
link->node.name = "this name will have 74 characters as it is the max "
|
||||
"that fits in the SU.txt";
|
||||
@ -1259,7 +1259,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[2], 255);
|
||||
CU_ASSERT_EQUAL(entry[3], 1);
|
||||
CU_ASSERT_EQUAL(entry[4], 0);
|
||||
|
||||
|
||||
/* first component */
|
||||
CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[6], 0);
|
||||
@ -1268,7 +1268,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[7], 0);
|
||||
CU_ASSERT_EQUAL(entry[8], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
|
||||
|
||||
|
||||
/* 3rd component */
|
||||
CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[13], 0);
|
||||
@ -1277,7 +1277,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[14], 0);
|
||||
CU_ASSERT_EQUAL(entry[15], 1);
|
||||
CU_ASSERT_EQUAL(entry[16], 'a');
|
||||
|
||||
|
||||
/* 5th component */
|
||||
CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
|
||||
CU_ASSERT_EQUAL(entry[18], 0);
|
||||
@ -1301,7 +1301,7 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[43], 0);
|
||||
CU_ASSERT_EQUAL(entry[44], 4);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 45, "with", 4);
|
||||
|
||||
|
||||
/* 10th component */
|
||||
CU_ASSERT_EQUAL(entry[49], 0);
|
||||
CU_ASSERT_EQUAL(entry[50], 2);
|
||||
@ -1316,59 +1316,59 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_EQUAL(entry[65], 0);
|
||||
CU_ASSERT_EQUAL(entry[66], 4);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 67, "that", 4);
|
||||
|
||||
|
||||
/* 13th component */
|
||||
CU_ASSERT_EQUAL(entry[71], 0);
|
||||
CU_ASSERT_EQUAL(entry[72], 8);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 73, "conforms", 8);
|
||||
|
||||
|
||||
/* 14th component */
|
||||
CU_ASSERT_EQUAL(entry[81], 0);
|
||||
CU_ASSERT_EQUAL(entry[82], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 83, "the", 3);
|
||||
|
||||
|
||||
/* 15th component */
|
||||
CU_ASSERT_EQUAL(entry[86], 0);
|
||||
CU_ASSERT_EQUAL(entry[87], 3);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 88, "max", 3);
|
||||
|
||||
|
||||
/* 16th component */
|
||||
CU_ASSERT_EQUAL(entry[91], 0);
|
||||
CU_ASSERT_EQUAL(entry[92], 4);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 93, "that", 4);
|
||||
|
||||
|
||||
/* 17th component */
|
||||
CU_ASSERT_EQUAL(entry[97], 0);
|
||||
CU_ASSERT_EQUAL(entry[98], 4);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 99, "fits", 4);
|
||||
|
||||
|
||||
/* 18th component */
|
||||
CU_ASSERT_EQUAL(entry[103], 0);
|
||||
CU_ASSERT_EQUAL(entry[104], 2);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 105, "in", 2);
|
||||
|
||||
|
||||
/* 19th component */
|
||||
CU_ASSERT_EQUAL(entry[107], 0);
|
||||
CU_ASSERT_EQUAL(entry[108], 11);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 109, "a single SL", 11);
|
||||
|
||||
|
||||
/* 20th component */
|
||||
CU_ASSERT_EQUAL(entry[120], 0);
|
||||
CU_ASSERT_EQUAL(entry[121], 38);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 122, "entry as it takes "
|
||||
"just two hundred and", 38);
|
||||
|
||||
|
||||
/* 21th component */
|
||||
CU_ASSERT_EQUAL(entry[160], 0);
|
||||
CU_ASSERT_EQUAL(entry[161], 29);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 162, "fifty bytes bytes bytes bytes", 29);
|
||||
|
||||
|
||||
/* 22th component */
|
||||
CU_ASSERT_EQUAL(entry[191], 0);
|
||||
CU_ASSERT_EQUAL(entry[192], 53);
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 193, "bytes bytes bytes bytes bytes bytes"
|
||||
" bytes bytes bytes", 53);
|
||||
|
||||
|
||||
/* 23th component */
|
||||
CU_ASSERT_EQUAL(entry[246], 0x4); /* parent */
|
||||
CU_ASSERT_EQUAL(entry[247], 0);
|
||||
@ -1379,15 +1379,15 @@ static void test_rrip_get_susp_fields_symlink()
|
||||
CU_ASSERT_NSTRING_EQUAL(entry + 250, "bytes", 5);
|
||||
|
||||
susp_info_free(&susp);
|
||||
|
||||
|
||||
free(node);
|
||||
free(link);
|
||||
}
|
||||
|
||||
void add_rockridge_suite()
|
||||
void add_rockridge_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("RockRidge Suite", NULL, NULL);
|
||||
|
||||
|
||||
CU_add_test(pSuite, "rrip_calc_len(file)", test_rrip_calc_len_file);
|
||||
CU_add_test(pSuite, "rrip_calc_len(symlink)", test_rrip_calc_len_symlink);
|
||||
CU_add_test(pSuite, "rrip_get_susp_fields(file)", test_rrip_get_susp_fields_file);
|
||||
|
@ -43,13 +43,13 @@ void test_mem_open()
|
||||
|
||||
/* try to open an already opened stream */
|
||||
ret = iso_stream_open(stream);
|
||||
CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENNED);
|
||||
CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENED);
|
||||
|
||||
ret = iso_stream_close(stream);
|
||||
CU_ASSERT_EQUAL(ret, 1);
|
||||
|
||||
ret = iso_stream_close(stream);
|
||||
CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENNED);
|
||||
CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENED);
|
||||
|
||||
iso_stream_unref(stream);
|
||||
}
|
||||
|
Reference in New Issue
Block a user